def get_dependency(expression):
    sym = symvar(expression)
    f = Function('f', sym, [expression])
    dep = col.OrderedDict()
    for index, sym in enumerate(sym):
        J = f.sparsity_jac(index, 0)
        dep[sym] = sorted(set(J.T.row()))
    return dep
Example #2
0
def _codegen_model(model_folder: str, f: ca.Function, library_name: str):
    # Compile shared libraries
    if os.name == 'posix':
        compiler_flags = ['-O2', '-fPIC']
        linker_flags = ['-fPIC']
    else:
        compiler_flags = ['/O2', '/wd4101']  # Shut up unused local variable warnings.
        linker_flags = ['/DLL']

    # Generate C code
    logger.debug("Generating {}".format(library_name))

    cg = ca.CodeGenerator(library_name)
    cg.add(f, True) # Nondifferentiated function
    cg.add(f.forward(1), True) # Jacobian-times-vector product
    cg.add(f.reverse(1), True) # vector-times-Jacobian product
    cg.add(f.reverse(1).forward(1), True) # Hessian-times-vector product
    cg.generate(model_folder + '/')

    compiler = distutils.ccompiler.new_compiler()

    file_name = os.path.relpath(os.path.join(model_folder, library_name + '.c'))
    object_name = compiler.object_filenames([file_name])[0]
    library = os.path.join(model_folder, library_name + compiler.shared_lib_extension)
    try:
        # NOTE: For some reason running in debug mode in PyCharm (2017.1)
        # on Windows causes cl.exe to fail on its own binary name (?!) and
        # the include paths. This does not happen when running directly
        # from cmd.exe / PowerShell or e.g. with debug mode in VS Code.
        compiler.compile([file_name], extra_postargs=compiler_flags)

        # We do not want the "lib" prefix on POSIX systems, so we call
        # link() directly with our desired filename instead of
        # link_shared_lib().
        compiler.link(compiler.SHARED_LIBRARY, [object_name], library, extra_preargs=linker_flags)
    except:
        raise
    finally:
        with contextlib.suppress(FileNotFoundError):
            os.remove(file_name)
            os.remove(object_name)
    return library
    raise ValueError("string_to_test should be: 'G', 'D', 'A' or 'E'")

m = biorbd.Model(model_path)
bound_min = []
bound_max = []
for i in range(m.nbSegment()):
    seg = m.segment(i)
    for r in seg.QRanges():
        bound_min.append(r.min())
        bound_max.append(r.max())
bounds = (bound_min, bound_max)

pn = DummyPenalty(m)
ObjectiveFcn.Lagrange.TRACK_SEGMENT_WITH_CUSTOM_RT.value[0](
    pn, pn, idx_segment_bow_hair, rt_on_string)
custom_rt = Function("custom_rt", [pn.nlp.q], [pn.val]).expand()
ObjectiveFcn.Mayer.SUPERIMPOSE_MARKERS.value[0](pn, pn, tag_bow_contact,
                                                tag_violin)
superimpose = Function("superimpose", [pn.nlp.q], [pn.val]).expand()


def objective_function(x, *args, **kwargs):
    out = np.ndarray((6, ))
    out[:3] = np.array(custom_rt(x))[:, 0]
    out[3:] = np.array(superimpose(x))[:, 0]
    return out


b = bioviz.Viz(loaded_model=m,
               markers_size=0.003,
               show_markers=True,
    def __set_costs(self, ocp):
        self.y_ref = []
        self.y_ref_end = []
        self.lagrange_costs = SX()
        self.mayer_costs = SX()
        self.W = np.zeros((0, 0))
        self.W_e = np.zeros((0, 0))
        if self.acados_ocp.cost.cost_type == "LINEAR_LS":
            # set Lagrange terms
            self.acados_ocp.cost.Vx = np.zeros(
                (self.acados_ocp.dims.ny, self.acados_ocp.dims.nx))
            self.acados_ocp.cost.Vx[:self.acados_ocp.dims.nx, :] = np.eye(
                self.acados_ocp.dims.nx)

            Vu = np.zeros((self.acados_ocp.dims.ny, self.acados_ocp.dims.nu))
            Vu[self.acados_ocp.dims.nx:, :] = np.eye(self.acados_ocp.dims.nu)
            self.acados_ocp.cost.Vu = Vu

            # set Mayer term
            self.acados_ocp.cost.Vx_e = np.zeros(
                (self.acados_ocp.dims.nx, self.acados_ocp.dims.nx))

        elif self.acados_ocp.cost.cost_type == "NONLINEAR_LS":
            if ocp.nb_phases != 1:
                raise NotImplementedError(
                    "ACADOS with more than one phase is not implemented yet")

            for i in range(ocp.nb_phases):
                # TODO: I think ocp.J is missing here (the parameters would be stored there)
                # TODO: Yes the objectives in ocp are not dealt with,
                #  does that makes sense since we only work with 1 phase ?
                for j, J in enumerate(ocp.nlp[i]["J"]):
                    if J[0]["objective"].type.get_type(
                    ) == ObjectiveFunction.LagrangeFunction:
                        self.lagrange_costs = vertcat(
                            self.lagrange_costs, J[0]["val"].reshape((-1, 1)))
                        self.W = linalg.block_diag(
                            self.W,
                            np.diag([J[0]["objective"].weight] *
                                    J[0]["val"].numel()))
                        if J[0]["target"] is not None:
                            self.y_ref.append([
                                J_tp["target"].T.reshape((-1, 1)) for J_tp in J
                            ])
                        else:
                            self.y_ref.append([
                                np.zeros((J_tp["val"].numel(), 1))
                                for J_tp in J
                            ])

                    elif J[0]["objective"].type.get_type(
                    ) == ObjectiveFunction.MayerFunction:
                        mayer_func_tp = Function(f"cas_mayer_func_{i}_{j}",
                                                 [ocp.nlp[i]["X"][-1]],
                                                 [J[0]["val"]])
                        self.W_e = linalg.block_diag(
                            self.W_e,
                            np.diag([J[0]["objective"].weight] *
                                    J[0]["val"].numel()))
                        self.mayer_costs = vertcat(
                            self.mayer_costs,
                            mayer_func_tp(ocp.nlp[i]["X"][0]))
                        if J[0]["target"] is not None:
                            self.y_ref_end.append([J[0]["target"]])
                        else:
                            self.y_ref_end.append(
                                [np.zeros((J[0]["val"].numel(), 1))])

                    else:
                        raise RuntimeError(
                            "The objective function is not Lagrange nor Mayer."
                        )

            if self.lagrange_costs.numel():
                self.acados_ocp.model.cost_y_expr = self.lagrange_costs
            else:
                self.acados_ocp.model.cost_y_expr = SX(1, 1)
            if self.mayer_costs.numel():
                self.acados_ocp.model.cost_y_expr_e = self.mayer_costs
            else:
                self.acados_ocp.model.cost_y_expr_e = SX(1, 1)
            self.acados_ocp.dims.ny = self.acados_ocp.model.cost_y_expr.shape[
                0]
            self.acados_ocp.dims.ny_e = self.acados_ocp.model.cost_y_expr_e.shape[
                0]
            self.acados_ocp.cost.yref = np.zeros((max(self.acados_ocp.dims.ny,
                                                      1), ))
            self.acados_ocp.cost.yref_e = np.concatenate(self.y_ref_end,
                                                         -1).T.squeeze()

            if self.W.shape == (0, 0):
                self.acados_ocp.cost.W = np.zeros((1, 1))
            else:
                self.acados_ocp.cost.W = self.W
            if self.W_e.shape == (0, 0):
                self.acados_ocp.cost.W_e = np.zeros((1, 1))
            else:
                self.acados_ocp.cost.W_e = self.W_e

        elif self.acados_ocp.cost.cost_type == "EXTERNAL":
            for i in range(ocp.nb_phases):
                for j in range(len(ocp.nlp[i]["J"])):
                    J = ocp.nlp[i]["J"][j][0]

                    raise RuntimeError(
                        "TODO: The target is not right currently")
                    if J["type"] == ObjectiveFunction.LagrangeFunction:
                        self.lagrange_costs = vertcat(
                            self.lagrange_costs, J["val"][0] - J["target"][0])
                    elif J["type"] == ObjectiveFunction.MayerFunction:
                        raise RuntimeError(
                            "TODO: I may have broken this (is this the right J?)"
                        )
                        mayer_func_tp = Function(f"cas_mayer_func_{i}_{j}",
                                                 [ocp.nlp[i]["X"][-1]],
                                                 [J["val"]])
                        self.mayer_costs = vertcat(
                            self.mayer_costs,
                            mayer_func_tp(ocp.nlp[i]["X"][0]))
                    else:
                        raise RuntimeError(
                            "The objective function is not Lagrange nor Mayer."
                        )
            self.acados_ocp.model.cost_expr_ext_cost = sum1(
                self.lagrange_costs)
            self.acados_ocp.model.cost_expr_ext_cost_e = sum1(self.mayer_costs)

        else:
            raise RuntimeError(
                "Available acados cost type: 'LINEAR_LS', 'NONLINEAR_LS' and 'EXTERNAL'."
            )
Example #5
0
def markers_fun(biorbd_model):
    qMX = MX.sym('qMX', biorbd_model.nbQ())
    return Function('markers', [qMX], [biorbd_model.markers(qMX)])
Example #6
0
    def configure_soft_contact_function(ocp, nlp):
        """
        Configure the soft contact sphere

        Parameters
        ----------
        ocp: OptimalControlProgram
            A reference to the ocp
        nlp: NonLinearProgram
            A reference to the phase
        """

        global_soft_contact_force_func = MX.zeros(
            nlp.model.nbSoftContacts() * 6, 1)
        n = nlp.model.nbQ()
        component_list = ["Mx", "My", "Mz", "Fx", "Fy", "Fz"]

        for i_sc in range(nlp.model.nbSoftContacts()):
            soft_contact = nlp.model.softContact(i_sc)

            global_soft_contact_force_func[i_sc * 6:(i_sc + 1) * 6, :] = (
                biorbd.SoftContactSphere(soft_contact).computeForceAtOrigin(
                    nlp.model, nlp.states.mx_reduced[:n],
                    nlp.states.mx_reduced[n:]).to_mx())
        nlp.soft_contact_forces_func = Function(
            "soft_contact_forces_func",
            [
                nlp.states.mx_reduced, nlp.controls.mx_reduced,
                nlp.parameters.mx
            ],
            [global_soft_contact_force_func],
            ["x", "u", "p"],
            ["soft_contact_forces"],
        ).expand()

        for i_sc in range(nlp.model.nbSoftContacts()):
            all_soft_contact_names = []
            all_soft_contact_names.extend([
                f"{nlp.model.softContactName(i_sc).to_string()}_{name}"
                for name in component_list if nlp.model.softContactName(
                    i_sc).to_string() not in all_soft_contact_names
            ])

            if "soft_contact_forces" in nlp.plot_mapping:
                phase_mappings = nlp.plot_mapping["soft_contact_forces"]
            else:
                soft_contact_names_in_phase = [
                    f"{nlp.model.softContactName(i_sc).to_string()}_{name}"
                    for name in component_list if nlp.model.softContactName(
                        i_sc).to_string() not in all_soft_contact_names
                ]
                phase_mappings = Mapping([
                    i for i, c in enumerate(all_soft_contact_names)
                    if c in soft_contact_names_in_phase
                ])
            nlp.plot[
                f"soft_contact_forces_{nlp.model.softContactName(i_sc).to_string()}"] = CustomPlot(
                    lambda t, x, u, p: nlp.soft_contact_forces_func(x, u, p)[
                        (i_sc * 6):((i_sc + 1) * 6), :],
                    plot_type=PlotType.INTEGRATED,
                    axes_idx=phase_mappings,
                    legend=all_soft_contact_names,
                )
Example #7
0
    A_d = SX([[1, 0.1, 0], [0, -0.14957, 0.024395], [0, 0, 0.82456]])
    B_d = SX([[0], [0], [0.054386]])
    T = 0.1

    h = SX.sym('h')
    h_p = SX.sym('h_p')
    eta = SX.sym('eta')
    states = vertcat(h, h_p, eta)
    u_pwm = SX.sym('u_pwm')
    controls = vertcat(u_pwm)
    rhs = vertcat(h_p,
                  k_L / m * ((k_V * (eta + eta_0) - A_B * h_p) / A_SP)**2 - g,
                  -1 / T_M * eta + k_M / T_M * u_pwm)

    f = Function('f', [states, controls], [rhs * T + states])

    # K = SX([[0.99581, 0.086879, 0.1499]])
    K = SX([[31.2043, 2.7128, 0.4824]])

    phi_c = A_d - B_d @ K

    P_f = SX([[5959.1, 517.92, 65.058], [517.92, 51.198, 5.6392],
              [65.058, 5.6392, 641.7]])
    # P_f=SX([[2.4944e+005,20941,1932.4],[20941,1839.4,168.05],[1932.4,168.05,641.7]])
    state_r = SX([[0.8], [0], [48.760258862]])
    u_r = [157.291157619]
    Q = SX.zeros(3, 3)
    # Q[0, 0] = 1e4
    Q[0, 0] = 1
    Q[1, 1] = 1
def generate_data(biorbd_model, final_time, nb_shooting):
    # Aliases
    nb_q = biorbd_model.nbQ()
    nb_qdot = biorbd_model.nbQdot()
    nb_tau = biorbd_model.nbGeneralizedTorque()
    nb_mus = biorbd_model.nbMuscleTotal()
    nb_markers = biorbd_model.nbMarkers()
    dt = final_time / nb_shooting

    # Casadi related stuff
    symbolic_states = MX.sym("x", nb_q + nb_qdot + nb_mus, 1)
    symbolic_controls = MX.sym("u", nb_tau + nb_mus, 1)
    nlp = {
        "model":
        biorbd_model,
        "nbTau":
        nb_tau,
        "nbQ":
        nb_q,
        "nbQdot":
        nb_qdot,
        "nbMuscle":
        nb_mus,
        "q_mapping":
        BidirectionalMapping(Mapping(range(nb_q)), Mapping(range(nb_q))),
        "q_dot_mapping":
        BidirectionalMapping(Mapping(range(nb_qdot)), Mapping(range(nb_qdot))),
        "tau_mapping":
        BidirectionalMapping(Mapping(range(nb_tau)), Mapping(range(nb_tau))),
    }
    markers_func = []
    for i in range(nb_markers):
        markers_func.append(
            Function(
                "ForwardKin",
                [symbolic_states],
                [biorbd_model.marker(symbolic_states[:nb_q], i).to_mx()],
                ["q"],
                ["marker_" + str(i)],
            ).expand())
    dynamics_func = Function(
        "ForwardDyn",
        [symbolic_states, symbolic_controls],
        [
            Dynamics.forward_dynamics_muscle_excitations_and_torque_driven(
                symbolic_states, symbolic_controls, nlp)
        ],
        ["x", "u"],
        ["xdot"],
    ).expand()

    def dyn_interface(t, x, u):
        u = np.concatenate([np.zeros(2), u])
        return np.array(dynamics_func(x, u)).squeeze()

    # Generate some muscle excitations
    U = np.random.rand(nb_shooting, nb_mus)

    # Integrate and collect the position of the markers accordingly
    X = np.ndarray(
        (biorbd_model.nbQ() + biorbd_model.nbQdot() + nb_mus, nb_shooting + 1))
    markers = np.ndarray((3, biorbd_model.nbMarkers(), nb_shooting + 1))

    def add_to_data(i, q):
        X[:, i] = q
        for j, mark_func in enumerate(markers_func):
            markers[:, j, i] = np.array(mark_func(q)).squeeze()

    x_init = np.array([0] * nb_q + [0] * nb_qdot + [0.5] * nb_mus)
    add_to_data(0, x_init)
    for i, u in enumerate(U):
        sol = solve_ivp(dyn_interface, (0, dt),
                        x_init,
                        method="RK45",
                        args=(u, ))
        x_init = sol["y"][:, -1]
        add_to_data(i + 1, x_init)

    time_interp = np.linspace(0, final_time, nb_shooting + 1)
    return time_interp, markers, X, U
def generate_c_code_external_cost(model, stage_type):

    casadi_version = CasadiMeta.version()
    casadi_opts = dict(mex=False, casadi_int="int", casadi_real="double")

    if casadi_version not in (ALLOWED_CASADI_VERSIONS):
        casadi_version_warning(casadi_version)

    x = model.x
    p = model.p

    if isinstance(x, MX):
        symbol = MX.sym
    else:
        symbol = SX.sym

    if stage_type == 'terminal':
        suffix_name = "_cost_ext_cost_e_fun"
        suffix_name_hess = "_cost_ext_cost_e_fun_jac_hess"
        suffix_name_jac = "_cost_ext_cost_e_fun_jac"
        u = symbol("u", 0, 0)
        ext_cost = model.cost_expr_ext_cost_e

    elif stage_type == 'path':
        suffix_name = "_cost_ext_cost_fun"
        suffix_name_hess = "_cost_ext_cost_fun_jac_hess"
        suffix_name_jac = "_cost_ext_cost_fun_jac"
        u = model.u
        ext_cost = model.cost_expr_ext_cost

    elif stage_type == 'initial':
        suffix_name = "_cost_ext_cost_0_fun"
        suffix_name_hess = "_cost_ext_cost_0_fun_jac_hess"
        suffix_name_jac = "_cost_ext_cost_0_fun_jac"
        u = model.u
        ext_cost = model.cost_expr_ext_cost_0

    # set up functions to be exported
    fun_name = model.name + suffix_name
    fun_name_hess = model.name + suffix_name_hess
    fun_name_jac = model.name + suffix_name_jac

    # generate expression for full gradient and Hessian
    full_hess, grad = hessian(ext_cost, vertcat(u, x))

    ext_cost_fun = Function(fun_name, [x, u, p], [ext_cost])
    ext_cost_fun_jac_hess = Function(fun_name_hess, [x, u, p],
                                     [ext_cost, grad, full_hess])
    ext_cost_fun_jac = Function(fun_name_jac, [x, u, p], [ext_cost, grad])

    # generate C code
    if not os.path.exists("c_generated_code"):
        os.mkdir("c_generated_code")

    os.chdir("c_generated_code")
    gen_dir = model.name + '_cost'
    if not os.path.exists(gen_dir):
        os.mkdir(gen_dir)
    gen_dir_location = "./" + gen_dir
    os.chdir(gen_dir_location)

    ext_cost_fun.generate(fun_name, casadi_opts)
    ext_cost_fun_jac_hess.generate(fun_name_hess, casadi_opts)
    ext_cost_fun_jac.generate(fun_name_jac, casadi_opts)

    os.chdir("../..")
    return
Example #10
0
def objective(x,y,p,N,params):
    
    nPrimal = x.numel()               #number of primal sln
    nDual = y['lam_g'].numel()               #number of dual
    nParam = p.numel()                  #number of parameters
    
    #Loading initial states and controls
    data = spio.loadmat('CstrDistXinit.mat', squeeze_me = True)
    Xinit = data['Xinit']
    xf = Xinit[0:84]
    u_opt = Xinit[84:]

    #Model parameters
    NT = params['dist']['NT']             #Stages in column
    Uf = 0.3                          #Feed rate to CSTR F_0
    _,state,xdot,inputs = ColCSTR_model(Uf,params)
    sf = Function('sf',[state,inputs],[xdot])

    params['model']['sf'] = sf
    params['model']['xdot_val_rf_ss'] = xf
    params['model']['x'] = x
    params['model']['u_opt'] = u_opt
    
    nx = params['prob']['nx']
    nu = params['prob']['nu']
    nk = params['prob']['nk']
    tf = params['prob']['tf']
    ns = params['prob']['ns']
    h = params['prob']['h']

    #Preparing collocation matrices
    _, C, D, d = collocationSetup()
    params['prob']['d'] = d
    colloc = {'C':C,'D':D, 'h':h}
    params['colloc'] = colloc
    
    #NLP variable vector
    V = MX()                              #Decision variables (control + state)
    obj = 0                                                 #Objective function
    cons = MX()                                          #Nonlinear Constraints
    
    delta_time = 1
    alpha = 1
    beta = 1
    gamma = 1

    params['weight']['delta_time'] = delta_time
    params['weight']['alpha'] = alpha
    params['weight']['beta'] = beta
    params['weight']['gamma'] = gamma
    
    #Initial states and Controls
    data_init = spio.loadmat('CstrDistXinit.mat', squeeze_me = True)
    xf = data_init['Xinit'][0:84]
    u_opt = data_init['Xinit'][84:89]
    
    #"Lift" Initial conditions
    X0 = MX.sym('X0', nx)
    V = vertcat(V,X0)                     #Decision variables
    cons = vertcat(cons, X0 - x[0:nx,0]) #Nonlinear constraints
    cons_x0 = X0 - x[0:nx,0]

    #Formulating the NLP
    Xk = X0
    
    data = spio.loadmat('Qmax.mat', squeeze_me = True)
    params['Qmax'] = data['Qmax']
    ssoftc = 0
    
    for i in range(0,N):
       obj, cons, V, Xk, params, ssoftc = itPredHorizon_pf(Xk, V, cons, obj, params, i, ssoftc)

    V = vertcat(V[:])
    cons = vertcat(cons[:])

    #Objective function and constraint functions
    f = Function('f', [V], [obj], ['V'], ['objective'])
    c = Function('c', [V], [cons], ['V'], ['constraint'])
    cx0 = Function('cx0',[X0], [cons_x0], ['X0'], ['constraint'])

    #Constructing Lagrangian
    lag_expr = obj + mtimes(transpose(y['lam_g']),cons)
    g = Function('g',[V],[jacobian(obj,V),obj])
    lagr = Function('lagr', [V], [lag_expr], ['V'], ['lag_expr'])
    [H,gg] = hessian(lag_expr,V)
    H = Function('H',[V],[H,gg])
    [Hobj,gobj] = hessian(obj,V)
    Hobj = Function('Hobj', [V], [Hobj,gobj])
    J = Function('J',[V],[jacobian(cons,V),cons])
    Jp = Function('Jp',[X0],[jacobian(cons_x0,X0),cons_x0])

    #Evaluating functions at current point
    f = f(x)
    g = g(x)
    g = g[0]
    g = transpose(g)
    H = H(x)
    H = H[0]
    Lxp = H[0:nPrimal,0:nParam]
    J = J(x)
    J = J[0]
    Jtemp = DM.zeros((nDual,nParam))
    cp = Jp(x[0:nParam])
    cp = cp[0]
    Jtemp[0:nParam, 0:nParam] = cp.full()
    cp = Jtemp.sparse()
    cst = c(x)

    #Evaluation of objective function used for Greshgorin bound
    Hobj = Hobj(x)
    Hobj = Hobj[0].sparse()
    f = f.full()
    g = g.sparse()
    Lxp = Lxp.sparse()
    cst = cst.full()
   
    #Equality constraint
    Jeq = J
    dpe = cp

    return f, g, H, Lxp, cst, J, cp, Jeq, dpe, Hobj
Example #11
0
N = 10
ode_fun, nx, nu = chen_model(implicit=True)
nlp = ocp_nlp({'N': N, 'nx': nx, 'nu': nu, 'ng': N * [1] + [0]})

# ODE Model
step = 0.1
nlp.set_model(ode_fun, step)

# Cost function
Q = diag([1.0, 1.0])
R = 1e-2
x = SX.sym('x', nx)
u = SX.sym('u', nu)
u_N = SX.sym('u', 0)
f = ocp_nlp_function(Function('ls_cost', [x, u], [vertcat(x, u)]))
f_N = ocp_nlp_function(Function('ls_cost_N', [x, u_N], [x]))
ls_cost = ocp_nlp_ls_cost(N, N * [f] + [f_N])
ls_cost.ls_cost_matrix = N * [block_diag(Q, R)] + [Q]
nlp.set_cost(ls_cost)

# Constraints
g = ocp_nlp_function(Function('path_constraint', [x, u], [u]))
g_N = ocp_nlp_function(Function('path_constraintN', [x, u], [SX([])]))
nlp.set_path_constraints(N * [g] + [g_N])
for i in range(N):
    nlp.lg[i] = -0.5
    nlp.ug[i] = +0.5

solver = ocp_nlp_solver(
    'sqp', nlp, {
Example #12
0
def gp_pred_function(x,
                     hyp,
                     kern_types,
                     x_train=None,
                     beta=None,
                     k_inv_training=None,
                     pred_var=True,
                     compute_grads=False):
    """

    """
    n_gps = len(kern_types)
    inp = SX.sym("input", x.shape)

    out_dict = dict()
    mu_all = []
    pred_sigma_all = []
    jac_mu_all = []

    for i in range(n_gps):
        kern_i = _get_kernel_function(kern_types[i], hyp[i])
        if beta is None:
            beta_i = None
        else:
            beta_i = beta[:, i]
        k_inv_i = None
        if not k_inv_training is None:
            k_inv_i = k_inv_training[i]
        if pred_var:
            mu_new, sigma_new = gp_pred(inp, kern_i, beta_i, x_train, k_inv_i,
                                        pred_var)
            pred_func = Function("pred_func", [inp], [mu_new, sigma_new],
                                 ["inp"], ["mu_1", "sigma_1"])
            F_1 = pred_func(inp=x)
            pred_sigma = F_1["sigma_1"]
            pred_sigma_all = horzcat(pred_sigma_all, pred_sigma)

        else:
            mu_new = gp_pred(inp, kern_i, beta_i, x_train, k_inv_i, pred_var)
            pred_func = Function("pred_func", [inp], [mu_new], ["inp"],
                                 ["mu_1"])
            F_1 = pred_func(inp=x)

        mu_1 = F_1["mu_1"]
        mu_all = horzcat(mu_all, mu_1)

        if compute_grads:
            # jac_func = pred_func.jacobian("inp","mu_1")

            jac_func = pred_func.factory('dmudinp', ['inp'], ['jac:mu_1:inp'])

            F_1_jac = jac_func(inp=x)
            # print(F_1_jac)
            jac_mu = F_1_jac['jac_mu_1_inp']
            jac_mu_all = vertcat(jac_mu_all, jac_mu)

    out_dict["pred_mu"] = mu_all
    if pred_var:
        out_dict["pred_sigma"] = pred_sigma_all
    if compute_grads:
        out_dict["jac_mu"] = jac_mu_all

    return out_dict
Example #13
0
    def dxdt(self, h: float, states: Union[MX, SX], controls: Union[MX, SX],
             params: Union[MX, SX]) -> tuple:
        """
        The dynamics of the system

        Parameters
        ----------
        h: float
            The time step
        states: Union[MX, SX]
            The states of the system
        controls: Union[MX, SX]
            The controls of the system
        params: Union[MX, SX]
            The parameters of the system

        Returns
        -------
        The derivative of the states
        """

        nu = controls.shape[0]
        nx = states.shape[0]

        # Choose collocation points
        time_points = [0] + collocation_points(self.degree, "legendre")

        # Coefficients of the collocation equation
        C = self.CX.zeros((self.degree + 1, self.degree + 1))

        # Coefficients of the continuity equation
        D = self.CX.zeros(self.degree + 1)

        # Dimensionless time inside one control interval
        time_control_interval = self.CX.sym("time_control_interval")

        # For all collocation points
        for j in range(self.degree + 1):
            # Construct Lagrange polynomials to get the polynomial basis at the collocation point
            L = 1
            for r in range(self.degree + 1):
                if r != j:
                    L *= (time_control_interval -
                          time_points[r]) / (time_points[j] - time_points[r])

            # Evaluate the polynomial at the final time to get the coefficients of the continuity equation
            lfcn = Function("lfcn", [time_control_interval], [L])
            D[j] = lfcn(1.0)

            # Evaluate the time derivative of the polynomial at all collocation points to get
            # the coefficients of the continuity equation
            tfcn = Function("tfcn", [time_control_interval],
                            [tangent(L, time_control_interval)])
            for r in range(self.degree + 1):
                C[j, r] = tfcn(time_points[r])

        # Total number of variables for one finite element
        x0 = states
        u = controls

        x_irk_points = [
            self.CX.sym(f"X_irk_{j}", nx, 1)
            for j in range(1, self.degree + 1)
        ]
        x = [x0] + x_irk_points

        x_irk_points_eq = []
        for j in range(1, self.degree + 1):

            t_norm_init = (j - 1) / self.degree  # normalized time
            # Expression for the state derivative at the collocation point
            xp_j = 0
            for r in range(self.degree + 1):
                xp_j += C[r, j] * x[r]

            # Append collocation equations
            f_j = self.fun(x[j], self.get_u(u, t_norm_init), params)[:,
                                                                     self.idx]
            x_irk_points_eq.append(h * f_j - xp_j)

        # Concatenate constraints
        x_irk_points = vertcat(*x_irk_points)
        x_irk_points_eq = vertcat(*x_irk_points_eq)

        # Root-finding function, implicitly defines x_irk_points as a function of x0 and p
        vfcn = Function("vfcn", [x_irk_points, x0, u, params],
                        [x_irk_points_eq]).expand()

        # Create a implicit function instance to solve the system of equations
        ifcn = rootfinder("ifcn", "newton", vfcn)
        x_irk_points = ifcn(self.CX(), x0, u, params)
        x = [
            x0 if r == 0 else x_irk_points[(r - 1) * nx:r * nx]
            for r in range(self.degree + 1)
        ]

        # Get an expression for the state at the end of the finite element
        xf = self.CX.zeros(nx, self.degree + 1)  # 0 #
        for r in range(self.degree + 1):
            xf[:, r] = xf[:, r - 1] + D[r] * x[r]

        return xf[:, -1], horzcat(x0, xf[:, -1])
Example #14
0
    def _set_penalty_function(self, all_pn: Union[PenaltyNodeList, list,
                                                  tuple], fcn: Union[MX, SX]):
        """
        Finalize the preparation of the penalty (setting function and weighted_function)

        Parameters
        ----------
        all_pn: PenaltyNodeList
            The nodes
        fcn: Union[MX, SX]
            The value of the penalty function
        """

        # Sanity checks
        if self.transition and self.explicit_derivative:
            raise ValueError(
                "transition and explicit_derivative cannot be true simultaneously"
            )
        if self.transition and self.derivative:
            raise ValueError(
                "transition and derivative cannot be true simultaneously")
        if self.derivative and self.explicit_derivative:
            raise ValueError(
                "derivative and explicit_derivative cannot be true simultaneously"
            )

        if self.multinode_constraint or self.transition:
            ocp = all_pn[0].ocp
            nlp = all_pn[0].nlp
            nlp_post = all_pn[1].nlp
            name = self.name.replace("->", "_").replace(" ",
                                                        "_").replace(",", "_")
            states_pre = nlp.states.cx_end
            states_post = nlp_post.states.cx
            controls_pre = nlp.controls.cx_end
            controls_post = nlp_post.controls.cx
            state_cx = vertcat(states_pre, states_post)
            control_cx = vertcat(controls_pre, controls_post)

        else:
            ocp = all_pn.ocp
            nlp = all_pn.nlp
            name = self.name
            if self.integrate:
                state_cx = horzcat(*([all_pn.nlp.states.cx] +
                                     all_pn.nlp.states.cx_intermediates_list))
                control_cx = all_pn.nlp.controls.cx
            else:
                state_cx = all_pn.nlp.states.cx
                control_cx = all_pn.nlp.controls.cx
            if self.explicit_derivative:
                if self.derivative:
                    raise RuntimeError(
                        "derivative and explicit_derivative cannot be simultaneously true"
                    )
                state_cx = horzcat(state_cx, all_pn.nlp.states.cx_end)
                control_cx = horzcat(control_cx, all_pn.nlp.controls.cx_end)

        param_cx = nlp.cx(nlp.parameters.cx)

        # Do not use nlp.add_casadi_func because all functions must be registered
        self.function = biorbd.to_casadi_func(name,
                                              fcn[self.rows, self.cols],
                                              state_cx,
                                              control_cx,
                                              param_cx,
                                              expand=self.expand)
        self.function_non_threaded = self.function

        if self.derivative:
            state_cx = horzcat(all_pn.nlp.states.cx_end, all_pn.nlp.states.cx)
            control_cx = horzcat(all_pn.nlp.controls.cx_end,
                                 all_pn.nlp.controls.cx)
            self.function = biorbd.to_casadi_func(
                f"{name}",
                self.function(all_pn.nlp.states.cx_end,
                              all_pn.nlp.controls.cx_end, param_cx) -
                self.function(all_pn.nlp.states.cx, all_pn.nlp.controls.cx,
                              param_cx),
                state_cx,
                control_cx,
                param_cx,
            )

        modified_fcn = self.function(state_cx, control_cx, param_cx)

        dt_cx = nlp.cx.sym("dt", 1, 1)
        weight_cx = nlp.cx.sym("weight", 1, 1)
        target_cx = nlp.cx.sym("target", modified_fcn.shape)
        modified_fcn = modified_fcn - target_cx

        if self.weight:
            modified_fcn = modified_fcn**2 if self.quadratic else modified_fcn
            modified_fcn = weight_cx * modified_fcn * dt_cx
        else:
            modified_fcn = modified_fcn * dt_cx

        # Do not use nlp.add_casadi_func because all of them must be registered
        self.weighted_function = Function(
            name,
            [state_cx, control_cx, param_cx, weight_cx, target_cx, dt_cx],
            [modified_fcn])
        self.weighted_function_non_threaded = self.weighted_function

        if ocp.n_threads > 1 and self.multi_thread and len(self.node_idx) > 1:
            self.function = self.function.map(len(self.node_idx), "thread",
                                              ocp.n_threads)
            self.weighted_function = self.weighted_function.map(
                len(self.node_idx), "thread", ocp.n_threads)
        else:
            self.multi_thread = False  # Override the multi_threading, since only one node is optimized

        if self.expand:
            self.function = self.function.expand()
            self.weighted_function = self.weighted_function.expand()
Example #15
0
    def __set_costs(self, ocp):

        if ocp.nb_phases != 1:
            raise NotImplementedError("ACADOS with more than one phase is not implemented yet.")
        # costs handling in self.acados_ocp
        self.y_ref = []
        self.y_ref_end = []
        self.lagrange_costs = SX()
        self.mayer_costs = SX()
        self.W = np.zeros((0, 0))
        self.W_e = np.zeros((0, 0))

        if self.acados_ocp.cost.cost_type == "LINEAR_LS":
            raise RuntimeError("LINEAR_LS is not interfaced yet.")

        elif self.acados_ocp.cost.cost_type == "NONLINEAR_LS":
            for i in range(ocp.nb_phases):
                for j, J in enumerate(ocp.nlp[i].J):
                    if J[0]["objective"].type.get_type() == ObjectiveFunction.LagrangeFunction:
                        self.lagrange_costs = vertcat(self.lagrange_costs, J[0]["val"].reshape((-1, 1)))
                        self.W = linalg.block_diag(self.W, np.diag([J[0]["objective"].weight] * J[0]["val"].numel()))
                        if J[0]["target"] is not None:
                            self.y_ref.append([J_tp["target"].T.reshape((-1, 1)) for J_tp in J])
                        else:
                            self.y_ref.append([np.zeros((J_tp["val"].numel(), 1)) for J_tp in J])

                    elif J[0]["objective"].type.get_type() == ObjectiveFunction.MayerFunction:
                        mayer_func_tp = Function(f"cas_mayer_func_{i}_{j}", [ocp.nlp[i].X[-1]], [J[0]["val"]])
                        self.W_e = linalg.block_diag(
                            self.W_e, np.diag([J[0]["objective"].weight] * J[0]["val"].numel())
                        )
                        self.mayer_costs = vertcat(self.mayer_costs, mayer_func_tp(ocp.nlp[i].X[0]))
                        if J[0]["target"] is not None:
                            self.y_ref_end.append(
                                [J[0]["target"]] if isinstance(J[0]["target"], (int, float)) else J[0]["target"]
                            )
                        else:
                            self.y_ref_end.append([0] * (J[0]["val"].numel()))

                    else:
                        raise RuntimeError("The objective function is not Lagrange nor Mayer.")

                # parameter as mayer function
                # IMPORTANT: it is considered that only parameters are stored in ocp.J, for now.
                if self.params:
                    for j, J in enumerate(ocp.J):
                        mayer_func_tp = Function(f"cas_J_mayer_func_{i}_{j}", [ocp.nlp[i].X[-1]], [J[0]["val"]])
                        self.W_e = linalg.block_diag(
                            self.W_e, np.diag(([J[0]["objective"].weight] * J[0]["val"].numel()))
                        )
                        self.mayer_costs = vertcat(self.mayer_costs, mayer_func_tp(ocp.nlp[i].X[0]))
                        if J[0]["target"] is not None:
                            self.y_ref_end.append(
                                [J[0]["target"]] if isinstance(J[0]["target"], (int, float)) else J[0]["target"]
                            )
                        else:
                            self.y_ref_end.append([0] * (J[0]["val"].numel()))

            # Set costs
            self.acados_ocp.model.cost_y_expr = self.lagrange_costs if self.lagrange_costs.numel() else SX(1, 1)
            self.acados_ocp.model.cost_y_expr_e = self.mayer_costs if self.mayer_costs.numel() else SX(1, 1)

            # Set dimensions
            self.acados_ocp.dims.ny = self.acados_ocp.model.cost_y_expr.shape[0]
            self.acados_ocp.dims.ny_e = self.acados_ocp.model.cost_y_expr_e.shape[0]

            # Set weight
            self.acados_ocp.cost.W = np.zeros((1, 1)) if self.W.shape == (0, 0) else self.W
            self.acados_ocp.cost.W_e = np.zeros((1, 1)) if self.W_e.shape == (0, 0) else self.W_e

            # Set target shape
            self.acados_ocp.cost.yref = np.zeros((self.acados_ocp.cost.W.shape[0],))
            self.acados_ocp.cost.yref_e = np.zeros((self.acados_ocp.cost.W_e.shape[0],))

        elif self.acados_ocp.cost.cost_type == "EXTERNAL":
            raise RuntimeError("External is not interfaced yet, please use NONLINEAR_LS")

        else:
            raise RuntimeError("Available acados cost type: 'LINEAR_LS', 'NONLINEAR_LS' and 'EXTERNAL'.")
Example #16
0
    def add_or_replace_to_penalty_pool(self, ocp, _):
        """
        Doing some configuration on the parameter and add it to the list of parameter_to_optimize

        Parameters
        ----------
        ocp: OptimalControlProgram
            A reference to the ocp
        _: Any
            The place holder for what is supposed to be nlp
        """

        old_parameter_cx = ocp.v.parameters_in_list.cx
        ocp.v.add_parameter(self)

        # Express the previously defined parameters with the new param set
        state_cx = ocp.cx()
        controls_cx = ocp.cx()
        parameter_cx = ocp.v.parameters_in_list.cx
        for p in ocp.v.parameters_in_list:
            for p_list in p.penalty_list[0]:
                if p_list.weighted_function is None:
                    continue
                dt_cx = ocp.cx.sym("dt", 1, 1)
                weight_cx = ocp.cx.sym("weight", 1, 1)
                target_cx = ocp.cx.sym("target",
                                       p_list.weighted_function.numel_out(), 1)

                p_list.function = Function(
                    p_list.function.name(),
                    [state_cx, controls_cx, parameter_cx],
                    [p_list.function(state_cx, controls_cx, old_parameter_cx)],
                )
                p_list.weighted_function = Function(
                    p_list.function.name(),
                    [
                        state_cx, controls_cx, parameter_cx, weight_cx,
                        target_cx, dt_cx
                    ],
                    [
                        p_list.weighted_function(state_cx, controls_cx,
                                                 old_parameter_cx, weight_cx,
                                                 target_cx, dt_cx)
                    ],
                )

        if self.penalty_list:
            if ocp.phase_transitions:
                raise NotImplementedError(
                    "Updating parameters while having phase_transition is not supported yet"
                )

            if isinstance(self.penalty_list, Objective):
                penalty_list_tp = ObjectiveList()
                penalty_list_tp.add(self.penalty_list)
                self.penalty_list = penalty_list_tp
            elif not isinstance(self.penalty_list, ObjectiveList):
                raise RuntimeError(
                    "penalty_list should be built from an Objective or ObjectiveList"
                )

            if len(self.penalty_list) > 1 or len(self.penalty_list[0]) > 1:
                raise NotImplementedError(
                    "Parameters with more that one penalty is not implemented yet"
                )

            for penalty in self.penalty_list[0]:
                # Sanity check
                if not isinstance(penalty.type, ObjectiveFcn.Parameter):
                    raise RuntimeError(
                        "Parameters should be declared custom_type=ObjectiveFcn.Parameters"
                    )
                if penalty.node != Node.DEFAULT:
                    raise RuntimeError(
                        "Parameters are timeless optimization, node=Node.DEFAULT should be declared"
                    )

                func = penalty.custom_function

                all_pn = PenaltyNodeList(ocp, None, [], [], [], [])
                val = func(ocp, self.cx * self.scaling, **penalty.params)
                self.set_penalty(ocp, penalty, val, target_ns=1)
                penalty.clear_penalty(ocp, None)
                penalty._add_penalty_to_pool(all_pn)
    def __set_costs(self, ocp):
        # set weight for states and controls (default: 1.00)
        # Q = 1.00 * np.eye(self.acados_ocp.dims.nx)
        # R = 1.00 * np.eye(self.acados_ocp.dims.nu)
        # self.acados_ocp.cost.W = linalg.block_diag(Q, R)
        # self.acados_ocp.cost.W_e = Q
        self.y_ref = []
        self.y_ref_end = []
        if self.acados_ocp.cost.cost_type == "LINEAR_LS":
            # set Lagrange terms
            self.acados_ocp.cost.Vx = np.zeros((self.acados_ocp.dims.ny, self.acados_ocp.dims.nx))
            self.acados_ocp.cost.Vx[: self.acados_ocp.dims.nx, :] = np.eye(self.acados_ocp.dims.nx)

            Vu = np.zeros((self.acados_ocp.dims.ny, self.acados_ocp.dims.nu))
            Vu[self.acados_ocp.dims.nx :, :] = np.eye(self.acados_ocp.dims.nu)
            self.acados_ocp.cost.Vu = Vu

            # set Mayer term
            self.acados_ocp.cost.Vx_e = np.zeros((self.acados_ocp.dims.nx, self.acados_ocp.dims.nx))

        elif self.acados_ocp.cost.cost_type == "NONLINEAR_LS":
            if ocp.nb_phases != 1:
                # TODO: Please confirm this
                raise NotImplementedError("ACADOS with more than one phase is not implemented yet")

            for i in range(ocp.nb_phases):
                # TODO: I think ocp.J is missing here (the parameters would be stored there)
                for j, J in enumerate(ocp.nlp[i]["J"]):
                    if J[0]["objective"].type.get_type() == ObjectiveFunction.LagrangeFunction:
                        self.lagrange_costs = vertcat(self.lagrange_costs, J[0]["val"].reshape((-1, 1)))
                        if J[0]["target"] is not None:
                            self.y_ref.append([J_tp["target"].T.reshape((-1, 1)) for J_tp in J])
                        else:
                            raise RuntimeError("Should we put y_ref = zeros?")

                    elif J[0]["objective"].type.get_type() == ObjectiveFunction.MayerFunction:
                        raise RuntimeError("TODO: I may have broken this (is this the right J?)")
                        mayer_func_tp = Function(f"cas_mayer_func_{i}_{j}", [ocp.nlp[i]["X"][-1]], [J[0]["val"]])
                        self.mayer_costs = vertcat(self.mayer_costs, mayer_func_tp(ocp.nlp[i]["X"][0]))
                        if J[0]["target"] is not None:
                            self.y_ref_end.append([J[0]["target"]])
                        else:
                            raise RuntimeError("TODO: Should we put y_ref_end = zeros?")

                    else:
                        raise RuntimeError("The objective function is not Lagrange nor Mayer.")

            if self.lagrange_costs.numel():
                self.acados_ocp.model.cost_y_expr = self.lagrange_costs
            else:
                self.acados_ocp.model.cost_y_expr = SX(1, 1)
            if self.mayer_costs.numel():
                self.acados_ocp.model.cost_y_expr_e = self.mayer_costs
            else:
                self.acados_ocp.model.cost_y_expr_e = SX(1, 1)
            self.acados_ocp.dims.ny = self.acados_ocp.model.cost_y_expr.shape[0]
            self.acados_ocp.dims.ny_e = self.acados_ocp.model.cost_y_expr_e.shape[0]
            self.acados_ocp.cost.yref = np.zeros((max(self.acados_ocp.dims.ny, 1),))
            self.acados_ocp.cost.yref_e = np.zeros((max(self.acados_ocp.dims.ny_e, 1),))

            # TODO changed hard coded values below (you can use J["weight"])
            Q_ocp = np.zeros((15, 15))
            np.fill_diagonal(Q_ocp, 1000)
            R_ocp = np.zeros((4, 4))
            np.fill_diagonal(R_ocp, 1000)

            self.acados_ocp.cost.W = linalg.block_diag(Q_ocp, R_ocp)
            self.acados_ocp.cost.W_e = np.zeros((1, 1))

            # TODO: Is the following useful?
            # if len(self.y_ref):
            #     self.y_ref = np.vstack(self.y_ref)
            # else:
            #     self.y_ref = [np.zeros((1, 1))] * self.ocp
            # if len(self.y_ref_end):
            #     self.y_ref_end = np.vstack(self.y_ref_end)
            # else:
            #     self.y_ref_end = np.zeros((1, 1))

        elif self.acados_ocp.cost.cost_type == "EXTERNAL":
            for i in range(ocp.nb_phases):
                for j in range(len(ocp.nlp[i]["J"])):
                    J = ocp.nlp[i]["J"][j][0]

                    raise RuntimeError("TODO: The target is not right currently")
                    if J["type"] == ObjectiveFunction.LagrangeFunction:
                        self.lagrange_costs = vertcat(self.lagrange_costs, J["val"][0] - J["target"][0])
                    elif J["type"] == ObjectiveFunction.MayerFunction:
                        raise RuntimeError("TODO: I may have broken this (is this the right J?)")
                        mayer_func_tp = Function(f"cas_mayer_func_{i}_{j}", [ocp.nlp[i]["X"][-1]], [J["val"]])
                        self.mayer_costs = vertcat(self.mayer_costs, mayer_func_tp(ocp.nlp[i]["X"][0]))
                    else:
                        raise RuntimeError("The objective function is not Lagrange nor Mayer.")
            self.acados_ocp.model.cost_expr_ext_cost = sum1(self.lagrange_costs)
            self.acados_ocp.model.cost_expr_ext_cost_e = sum1(self.mayer_costs)

        else:
            raise RuntimeError("Available acados cost type: 'LINEAR_LS', 'NONLINEAR_LS' and 'EXTERNAL'.")
Example #18
0
               [biorbd_model.muscleNames()[i].to_string() for i in range(18)],
               rotation=45)
plt.bar(x2, height, width, color='blue')
plt.xlabel('muscles')
plt.ylabel('weight')
plt.title('weight on force iso max')
plt.legend(["Acados", "Ipopt"], loc=2)
plt.show()

# ---- Tau --- #
symbolic_states = MX.sym("x", biorbd_model.nbQ() * 2, 1)
symbolic_controls = MX.sym("a", biorbd_model.nbMuscles(), 1)
torque_func = Function(
    "MuscleTau",
    [symbolic_states, symbolic_controls],
    [muscles_tau(symbolic_states, symbolic_controls, nlp_ac)],
    ["x", "a"],
    ["torque"],
).expand()
torques_ac = np.ndarray((biorbd_model.nbQ(), n_shooting_points))
torques_ac[:, :] = torque_func(x_ac[:, :], u_ac[:, :])

symbolic_states = MX.sym("x", biorbd_model.nbQ() * 2, 1)
symbolic_controls = MX.sym("a", biorbd_model.nbMuscles(), 1)
torque_func = Function(
    "MuscleTau",
    [symbolic_states, symbolic_controls],
    [muscles_tau(symbolic_states, symbolic_controls, nlp_ip)],
    ["x", "a"],
    ["torque"],
).expand()
    q, qdot, tau, mus = ProblemType.get_data_from_V(ocp, sol["x"])
    n_q = ocp.nlp[0]["model"].nbQ()
    n_mark = ocp.nlp[0]["model"].nbMarkers()
    n_frames = q.shape[1]
    mus_act = mus[0]
    mus_exci = np.array(mus[1])

    markers = np.ndarray((3, n_mark, q.shape[1]))
    markers_func = []
    for i in range(n_mark):
        markers_func.append(
            Function(
                "ForwardKin",
                [ocp.symbolic_states],
                [biorbd_model.marker(ocp.symbolic_states[:n_q], i).to_mx()],
                ["q"],
                ["marker_" + str(i)],
            ).expand())
    for i in range(n_frames):
        for j, mark_func in enumerate(markers_func):
            markers[:, j, i] = np.array(
                mark_func(
                    np.append(np.append(q[:, i], qdot[:, i]),
                              mus_act[0][:, i]))).squeeze()

    plt.figure("Markers")
    for i in range(markers.shape[1]):
        plt.plot(np.linspace(0, 2, n_shooting_points + 1),
                 markers_ref[:, i, :].T, "k")
        plt.plot(np.linspace(0, 2, n_shooting_points + 1), markers[:, i, :].T,
Example #20
0
def RK4(ode, ode_opt):
    """
    Numerical integration using fourth order Runge-Kutta method.
    :param ode: ode["x"] -> States. ode["p"] -> Controls. ode["ode"] -> Ordinary differential equation function
    (dynamics of the system).
    :param ode_opt: ode_opt["t0"] -> Initial time of the integration. ode_opt["tf"] -> Final time of the integration.
    ode_opt["number_of_finite_elements"] -> Number of steps between nodes. ode_opt["idx"] -> Index of ??. (integer)
    :return: Integration function. (CasADi function)
    """
    t_span = ode_opt["t0"], ode_opt["tf"]
    n_step = ode_opt["number_of_finite_elements"]
    idx = ode_opt["idx"]
    CX = ode_opt["CX"]
    x_sym = ode["x"]
    u_sym = ode["p"]
    param_sym = ode_opt["param"]
    fun = ode["ode"]
    model = ode_opt["model"]
    step_time = t_span[1] - t_span[0]
    h_norm = 1 / n_step
    h = step_time * h_norm  # Length of steps
    control_type = ode_opt["control_type"]

    def get_u(u, dt_norm):
        if control_type == ControlType.CONSTANT:
            return u
        elif control_type == ControlType.LINEAR_CONTINUOUS:
            return u[:, 0] + (u[:, 1] - u[:, 0]) * dt_norm
        else:
            raise RuntimeError(f"{control_type} ControlType not implemented yet")

    def dxdt(h, states, controls, params):
        u = controls
        x = CX(states.shape[0], n_step + 1)
        p = params
        x[:, 0] = states

        nb_dof = 0
        quat_idx = []
        quat_number = 0
        for j in range(model.nbSegment()):
            if model.segment(j).isRotationAQuaternion():
                quat_idx.append([nb_dof, nb_dof + 1, nb_dof + 2, model.nbDof() + quat_number])
                quat_number += 1
            nb_dof += model.segment(j).nbDof()

        for i in range(1, n_step + 1):
            t_norm_init = (i - 1) / n_step  # normalized time
            k1 = fun(x[:, i - 1], get_u(u, t_norm_init), p)[:, idx]
            k2 = fun(x[:, i - 1] + h / 2 * k1, get_u(u, t_norm_init + h_norm / 2), p)[:, idx]
            k3 = fun(x[:, i - 1] + h / 2 * k2, get_u(u, t_norm_init + h_norm / 2), p)[:, idx]
            k4 = fun(x[:, i - 1] + h * k3, get_u(u, t_norm_init + h_norm), p)[:, idx]
            x[:, i] = x[:, i - 1] + h / 6 * (k1 + 2 * k2 + 2 * k3 + k4)

            for j in range(model.nbQuat()):
                quaternion = vertcat(
                    x[quat_idx[j][3], i], x[quat_idx[j][0], i], x[quat_idx[j][1], i], x[quat_idx[j][2], i]
                )
                quaternion /= norm_fro(quaternion)
                x[quat_idx[j][0] : quat_idx[j][2] + 1, i] = quaternion[1:4]
                x[quat_idx[j][3], i] = quaternion[0]

        return x[:, -1], x

    return Function(
        "integrator", [x_sym, u_sym, param_sym], dxdt(h, x_sym, u_sym, param_sym), ["x0", "p", "params"], ["xf", "xall"]
    )
Example #21
0
    # Eingang symbolisch definieren
    u_1 = SX.sym('u_1')
    u_2 = SX.sym("u_2")
    # Eingangsverktor
    controls = vertcat(u_1, u_2)

    # kriegen die Anzahl der Zeiler("shape" ist ein Tuple)
    n_states = states.shape[0]  # p 22.

    # Eingangsanzahl
    n_controls = controls.shape[0]

    rhs = vertcat(sin(theta) * u_1, cos(theta) * u_1, u_2)

    f = Function('f', [states, controls], [rhs * T + states])

    K = SX([[0.99581, 0.086879, 0.1499]])
    # K = SX([[31.2043,  2.7128, 0.4824]])
    phi_c = A_d - B_d @ K

    P_f = SX([[5959.1, 517.92, 65.058], [517.92, 51.198, 5.6392],
              [65.058, 5.6392, 641.7]])
    # P_f=SX([[68639,5891.4,616.42],[5891.4,519.84,53.599],[616.42,53.599,641.7]])
    state_r = SX([[0.8], [0], [48.760258862]])
    u_r = [157.291157619]
    Q = SX.zeros(3, 3)
    # Q[0, 0] = 1e3
    Q[0, 0] = 1
    Q[1, 1] = 1
    Q[2, 2] = 1
Example #22
0
    # muscles_tau = model.muscularJointTorque(muscles_states, True,  q, qdot).to_mx()
    muscles_force = model.muscleForces(muscles_states, q, qdot).to_mx()
    return muscles_force

seaborn.set_style("whitegrid")
seaborn.color_palette()

biorbd_model = biorbd.Model("arm_wt_rot_scap.bioMod")
qMX = MX.sym("qMX", biorbd_model.nbQ(), 1)
dqMX = MX.sym("dqMX", biorbd_model.nbQ(), 1)
aMX = MX.sym("aMX", biorbd_model.nbMuscles(), 1)
uMX = MX.sym("uMX", biorbd_model.nbMuscles(), 1)
force_func = Function(
    "MuscleForce",
    [qMX, dqMX, aMX, uMX],
    [muscles_forces(qMX, dqMX, aMX, uMX, biorbd_model)],
    ["qMX", "dqMX", "aMX", "uMX"],
    ["Force"],
).expand()

T = 8
Ns = 800
motion = "REACH2"
nb_try = 30
marker_noise_lvl = [0, 0.002, 0.005, 0.01]
EMG_noise_lvl = [0, 1.5, 2, 2.5]
co_lvl = 4
TRACK_EMG = True
if TRACK_EMG:
    with_emg = "w"
else:
Example #23
0
def optProblem(x, u, x0_measure, N, params):

    NT = params['dist']['NT']
    Uf = params['dist']['F_0']

    #Modeling the system
    _, state, xdot, inputs = ColCSTR_model(Uf, params)
    f = Function('f', [state, inputs], [xdot])

    #Unpacking parameters
    x_min = params['bounds']['x_min']
    x_max = params['bounds']['x_max']

    #Loading steady state data
    data = spio.loadmat('CstrDistXinit.mat', squeeze_me=True)
    Xinit = data['Xinit']
    xf = Xinit[0:84]
    u_opt = Xinit[84:89]

    #Problem dimensions
    nx = params['prob']['nx']  #Number of states
    nu = params['prob']['nu']  #Number of inputs
    nk = params['prob']['nk']
    tf = params['prob']['tf']
    h = params['prob']['h']
    ns = params['prob']['ns']

    #Collecting model variables
    u = tile(u, nk)
    model = {
        'NT': NT,
        'f': f,
        'xdot_val_rf_ss': xf,
        'x': x,
        'u_opt': u_opt,
        'u': u
    }
    params['model'] = model

    #Preparing collocation matrices
    _, C, D, d = collocationSetup()
    params['prob']['d'] = d

    #Collecting collocation variables
    colloc = {'C': C, 'D': D, 'h': h}
    params['colloc'] = colloc

    #Empty NLP
    w = MX()  #Decision variables (control + state)
    w0 = []  #Initial guess
    lbw = []  #Lower bound for decision variable
    ubw = []  #Upper bound for decision variable
    g = MX()  #Nonlinear constraint
    lbg = []  #Lower bound for nonlinear constraint
    ubg = []  #Upper bound for nonlinear constraint
    J = 0  #Initialize objective function

    #Weight variables
    delta_t = 1
    alpha = 1
    beta = 1
    gamma = 1
    weight = {'delta_t': delta_t, 'alpha': alpha, 'beta': beta, 'gamma': gamma}
    params['weight'] = weight

    #Initial conditions
    X0 = MX.sym('X0', nx)
    w = vertcat(w, X0)
    w0 = [i for i in x[0, 0:nx]]
    lbw = [i for i in x_min]
    ubw = [i for i in x_max]
    g = vertcat(g, X0 - x0_measure)
    lbg = params['bounds']['lbg']
    ubg = params['bounds']['ubg']

    Xk = X0
    data = spio.loadmat('Qmax.mat', squeeze_me=True)
    Qmax = data['Qmax']
    params['Qmax'] = Qmax

    count = 2  #Counter for state variable
    ssoftc = 0
    for iter in range(0, N):
        J, g, w0, w, lbg, ubg, lbw, ubw, Xk, params, count, ssoftc = itPredHorizon(
            Xk, w, w0, lbw, ubw, lbg, ubg, g, J, params, iter, count, ssoftc,
            d)

    return J, g, w0, w, lbg, ubg, lbw, ubw, params
Example #24
0
    def __set_constraints(self, ocp):
        """
        Set the constraints from the ocp

        Parameters
        ----------
        ocp: OptimalControlProgram
            A reference to the current OptimalControlProgram
        """

        # constraints handling in self.acados_ocp
        u_min = np.array(ocp.nlp[0].u_bounds.min)
        u_max = np.array(ocp.nlp[0].u_bounds.max)
        x_min = np.array(ocp.nlp[0].x_bounds.min)
        x_max = np.array(ocp.nlp[0].x_bounds.max)
        self.all_constr = SX()
        self.end_constr = SX()
        # TODO:change for more node flexibility on bounds
        self.all_g_bounds = Bounds(interpolation=InterpolationType.CONSTANT)
        self.end_g_bounds = Bounds(interpolation=InterpolationType.CONSTANT)
        for i in range(ocp.n_phases):
            for g, G in enumerate(ocp.nlp[i].g):
                if not G:
                    continue
                if G[0]["constraint"].node[0] is Node.ALL:
                    self.all_constr = vertcat(self.all_constr,
                                              G[0]["val"].reshape((-1, 1)))
                    self.all_g_bounds.concatenate(G[0]["bounds"])
                    if len(G) > ocp.nlp[0].ns:
                        constr_end_func_tp = Function(
                            f"cas_constr_end_func_{i}_{g}", [ocp.nlp[i].X[-1]],
                            [G[0]["val"]])
                        self.end_constr = vertcat(
                            self.end_constr,
                            constr_end_func_tp(ocp.nlp[i].X[0]).reshape(
                                (-1, 1)))
                        self.end_g_bounds.concatenate(G[0]["bounds"])

                elif G[0]["constraint"].node[0] is Node.END:
                    constr_end_func_tp = Function(
                        f"cas_constr_end_func_{i}_{g}", [ocp.nlp[i].X[-1]],
                        [G[0]["val"]])
                    self.end_constr = vertcat(
                        self.end_constr,
                        constr_end_func_tp(ocp.nlp[i].X[0]).reshape((-1, 1)))
                    self.end_g_bounds.concatenate(G[0]["bounds"])

                else:
                    raise RuntimeError(
                        "Except for states and controls, Acados solver only handles constraints on last or all nodes."
                    )

        self.acados_model.con_h_expr = self.all_constr
        self.acados_model.con_h_expr_e = self.end_constr

        if not np.all(np.all(u_min.T == u_min.T[0, :], axis=0)):
            raise NotImplementedError(
                "u_bounds min must be the same at each shooting point with ACADOS"
            )
        if not np.all(np.all(u_max.T == u_max.T[0, :], axis=0)):
            raise NotImplementedError(
                "u_bounds max must be the same at each shooting point with ACADOS"
            )

        if (not np.isfinite(u_min).all() or not np.isfinite(x_min).all()
                or not np.isfinite(u_max).all()
                or not np.isfinite(x_max).all()):
            raise NotImplementedError(
                "u_bounds and x_bounds cannot be set to infinity in ACADOS. Consider changing it "
                "to a big value instead.")

        # setup state constraints
        # TODO replace all these np.concatenate by proper bound and initial_guess classes
        self.x_bound_max = np.ndarray((self.acados_ocp.dims.nx, 3))
        self.x_bound_min = np.ndarray((self.acados_ocp.dims.nx, 3))
        param_bounds_max = []
        param_bounds_min = []

        if self.params.size:
            param_bounds_max = self.params.bounds.max[:, 0]
            param_bounds_min = self.params.bounds.min[:, 0]

        for i in range(3):
            self.x_bound_max[:, i] = np.concatenate(
                (param_bounds_max, np.array(ocp.nlp[0].x_bounds.max[:, i])))
            self.x_bound_min[:, i] = np.concatenate(
                (param_bounds_min, np.array(ocp.nlp[0].x_bounds.min[:, i])))

        # setup control constraints
        self.acados_ocp.constraints.lbu = np.array(ocp.nlp[0].u_bounds.min[:,
                                                                           0])
        self.acados_ocp.constraints.ubu = np.array(ocp.nlp[0].u_bounds.max[:,
                                                                           0])
        self.acados_ocp.constraints.idxbu = np.array(
            range(self.acados_ocp.dims.nu))
        self.acados_ocp.dims.nbu = self.acados_ocp.dims.nu

        # initial state constraints
        self.acados_ocp.constraints.lbx_0 = self.x_bound_min[:, 0]
        self.acados_ocp.constraints.ubx_0 = self.x_bound_max[:, 0]
        self.acados_ocp.constraints.idxbx_0 = np.array(
            range(self.acados_ocp.dims.nx))
        self.acados_ocp.dims.nbx_0 = self.acados_ocp.dims.nx

        # setup path state constraints
        self.acados_ocp.constraints.Jbx = np.eye(self.acados_ocp.dims.nx)
        self.acados_ocp.constraints.lbx = self.x_bound_min[:, 1]
        self.acados_ocp.constraints.ubx = self.x_bound_max[:, 1]
        self.acados_ocp.constraints.idxbx = np.array(
            range(self.acados_ocp.dims.nx))
        self.acados_ocp.dims.nbx = self.acados_ocp.dims.nx

        # setup terminal state constraints
        self.acados_ocp.constraints.Jbx_e = np.eye(self.acados_ocp.dims.nx)
        self.acados_ocp.constraints.lbx_e = self.x_bound_min[:, -1]
        self.acados_ocp.constraints.ubx_e = self.x_bound_max[:, -1]
        self.acados_ocp.constraints.idxbx_e = np.array(
            range(self.acados_ocp.dims.nx))
        self.acados_ocp.dims.nbx_e = self.acados_ocp.dims.nx

        # setup algebraic constraint
        self.acados_ocp.constraints.lh = np.array(self.all_g_bounds.min[:, 0])
        self.acados_ocp.constraints.uh = np.array(self.all_g_bounds.max[:, 0])

        # setup terminal algebraic constraint
        self.acados_ocp.constraints.lh_e = np.array(self.end_g_bounds.min[:,
                                                                          0])
        self.acados_ocp.constraints.uh_e = np.array(self.end_g_bounds.max[:,
                                                                          0])
Example #25
0
def generate_c_code_external_cost(model, is_terminal):

    casadi_version = CasadiMeta.version()
    casadi_opts = dict(mex=False, casadi_int="int", casadi_real="double")

    if casadi_version not in (ALLOWED_CASADI_VERSIONS):
        casadi_version_warning(casadi_version)

    x = model.x
    p = model.p

    if isinstance(x, MX):
        symbol = MX.sym
    else:
        symbol = SX.sym

    if is_terminal:
        suffix_name = "_cost_ext_cost_e_fun"
        suffix_name_hess = "_cost_ext_cost_e_fun_jac_hess"
        suffix_name_jac = "_cost_ext_cost_e_fun_jac"
        u = symbol("u", 0, 0)
        ext_cost = model.cost_expr_ext_cost_e

    else:
        suffix_name = "_cost_ext_cost_fun"
        suffix_name_hess = "_cost_ext_cost_fun_jac_hess"
        suffix_name_jac = "_cost_ext_cost_fun_jac"
        u = model.u
        ext_cost = model.cost_expr_ext_cost

    # set up functions to be exported
    fun_name = model.name + suffix_name
    fun_name_hess = model.name + suffix_name_hess
    fun_name_jac = model.name + suffix_name_jac

    # generate jacobians
    jac_x = jacobian(ext_cost, x)
    jac_u = jacobian(ext_cost, u)
    # generate hessians
    hess_uu = jacobian(jac_u.T, u)
    hess_xu = jacobian(jac_u.T, x)
    hess_ux = jacobian(jac_x.T, u)
    hess_xx = jacobian(jac_x.T, x)
    full_hess = vertcat(horzcat(hess_uu, hess_xu), horzcat(hess_ux, hess_xx))

    ext_cost_fun = Function(fun_name, [x, u, p], [ext_cost])
    ext_cost_fun_jac_hess = Function(
        fun_name_hess, [x, u, p],
        [ext_cost, vertcat(jac_u.T, jac_x.T), full_hess])
    ext_cost_fun_jac = Function(fun_name_jac, [x, u, p],
                                [ext_cost, vertcat(jac_u.T, jac_x.T)])

    # generate C code
    if not os.path.exists("c_generated_code"):
        os.mkdir("c_generated_code")

    os.chdir("c_generated_code")
    gen_dir = model.name + '_cost'
    if not os.path.exists(gen_dir):
        os.mkdir(gen_dir)
    gen_dir_location = "./" + gen_dir
    os.chdir(gen_dir_location)

    ext_cost_fun.generate(fun_name, casadi_opts)
    ext_cost_fun_jac_hess.generate(fun_name_hess, casadi_opts)
    ext_cost_fun_jac.generate(fun_name_jac, casadi_opts)

    os.chdir("../..")
    return
Example #26
0
    def __set_costs(self, ocp):
        """
        Set the cost functions from ocp

        Parameters
        ----------
        ocp: OptimalControlProgram
            A reference to the current OptimalControlProgram
        """

        if ocp.n_phases != 1:
            raise NotImplementedError(
                "ACADOS with more than one phase is not implemented yet.")
        # costs handling in self.acados_ocp
        self.y_ref = []
        self.y_ref_end = []
        self.lagrange_costs = SX()
        self.mayer_costs = SX()
        self.W = np.zeros((0, 0))
        self.W_e = np.zeros((0, 0))
        ctrl_objs = [
            PenaltyType.MINIMIZE_TORQUE,
            PenaltyType.MINIMIZE_MUSCLES_CONTROL,
            PenaltyType.MINIMIZE_ALL_CONTROLS,
        ]
        state_objs = [
            PenaltyType.MINIMIZE_STATE,
        ]

        if self.acados_ocp.cost.cost_type == "LINEAR_LS":
            self.Vu = np.array([], dtype=np.int64).reshape(0, ocp.nlp[0].nu)
            self.Vx = np.array([], dtype=np.int64).reshape(0, ocp.nlp[0].nx)
            self.Vxe = np.array([], dtype=np.int64).reshape(0, ocp.nlp[0].nx)
            for i in range(ocp.n_phases):
                for j, J in enumerate(ocp.nlp[i].J):
                    if J[0]["objective"].type.get_type(
                    ) == ObjectiveFunction.LagrangeFunction:
                        if J[0]["objective"].type.value[0] in ctrl_objs:
                            index = (J[0]["objective"].index
                                     if J[0]["objective"].index else list(
                                         np.arange(ocp.nlp[0].nu)))
                            vu = np.zeros(ocp.nlp[0].nu)
                            vu[index] = 1.0
                            self.Vu = np.vstack((self.Vu, np.diag(vu)))
                            self.Vx = np.vstack(
                                (self.Vx,
                                 np.zeros((ocp.nlp[0].nu, ocp.nlp[0].nx))))
                            self.W = linalg.block_diag(
                                self.W,
                                np.diag([J[0]["objective"].weight] *
                                        ocp.nlp[0].nu))
                            if J[0]["target"] is not None:
                                y_tp = np.zeros((ocp.nlp[0].nu, 1))
                                y_ref_tp = []
                                for J_tp in J:
                                    y_tp[index] = J_tp["target"].T.reshape(
                                        (-1, 1))
                                    y_ref_tp.append(y_tp)
                                self.y_ref.append(y_ref_tp)
                            else:
                                self.y_ref.append(
                                    [np.zeros((ocp.nlp[0].nu, 1)) for _ in J])
                        elif J[0]["objective"].type.value[0] in state_objs:
                            index = (J[0]["objective"].index
                                     if J[0]["objective"].index else list(
                                         np.arange(ocp.nlp[0].nx)))
                            vx = np.zeros(ocp.nlp[0].nx)
                            vx[index] = 1.0
                            self.Vx = np.vstack((self.Vx, np.diag(vx)))
                            self.Vu = np.vstack(
                                (self.Vu,
                                 np.zeros((ocp.nlp[0].nx, ocp.nlp[0].nu))))
                            self.W = linalg.block_diag(
                                self.W,
                                np.diag([J[0]["objective"].weight] *
                                        ocp.nlp[0].nx))
                            if J[0]["target"] is not None:
                                y_ref_tp = []
                                for J_tp in J:
                                    y_tp = np.zeros((ocp.nlp[0].nx, 1))
                                    y_tp[index] = J_tp["target"].T.reshape(
                                        (-1, 1))
                                    y_ref_tp.append(y_tp)
                                self.y_ref.append(y_ref_tp)
                            else:
                                self.y_ref.append(
                                    [np.zeros((ocp.nlp[0].nx, 1)) for _ in J])
                        else:
                            raise RuntimeError(
                                f"{J[0]['objective'].type.name} is an incompatible objective term with "
                                f"LINEAR_LS cost type")

                        # Deal with last node to match ipopt formulation
                        if J[0]["objective"].node[0].value == "all" and len(
                                J) > ocp.nlp[0].ns:
                            index = (J[0]["objective"].index
                                     if J[0]["objective"].index else list(
                                         np.arange(ocp.nlp[0].nx)))
                            vxe = np.zeros(ocp.nlp[0].nx)
                            vxe[index] = 1.0
                            self.Vxe = np.vstack((self.Vxe, np.diag(vxe)))
                            self.W_e = linalg.block_diag(
                                self.W_e,
                                np.diag([J[0]["objective"].weight] *
                                        ocp.nlp[0].nx))
                            if J[0]["target"] is not None:
                                y_tp = np.zeros((ocp.nlp[0].nx, 1))
                                y_tp[index] = J[-1]["target"].T.reshape(
                                    (-1, 1))
                                self.y_ref_end.append(y_tp)
                            else:
                                self.y_ref_end.append(
                                    np.zeros((ocp.nlp[0].nx, 1)))

                    elif J[0]["objective"].type.get_type(
                    ) == ObjectiveFunction.MayerFunction:
                        if J[0]["objective"].type.value[0] in state_objs:
                            index = (J[0]["objective"].index
                                     if J[0]["objective"].index else list(
                                         np.arange(ocp.nlp[0].nx)))
                            vxe = np.zeros(ocp.nlp[0].nx)
                            vxe[index] = 1.0
                            self.Vxe = np.vstack((self.Vxe, np.diag(vxe)))
                            self.W_e = linalg.block_diag(
                                self.W_e,
                                np.diag([J[0]["objective"].weight] *
                                        ocp.nlp[0].nx))
                            if J[0]["target"] is not None:
                                y_tp = np.zeros((ocp.nlp[0].nx, 1))
                                y_tp[index] = J[-1]["target"].T.reshape(
                                    (-1, 1))
                                self.y_ref_end.append(y_tp)
                            else:
                                self.y_ref_end.append(
                                    np.zeros((ocp.nlp[0].nx, 1)))
                        else:
                            raise RuntimeError(
                                f"{J[0]['objective'].type.name} is an incompatible objective term "
                                f"with LINEAR_LS cost type")

                    else:
                        raise RuntimeError(
                            "The objective function is not Lagrange nor Mayer."
                        )

                if self.params.size:
                    raise RuntimeError(
                        "Params not yet handled with LINEAR_LS cost type")

            # Set costs
            self.acados_ocp.cost.Vx = self.Vx if self.Vx.shape[0] else np.zeros(
                (0, 0))
            self.acados_ocp.cost.Vu = self.Vu if self.Vu.shape[0] else np.zeros(
                (0, 0))
            self.acados_ocp.cost.Vx_e = self.Vxe if self.Vxe.shape[
                0] else np.zeros((0, 0))

            # Set dimensions
            self.acados_ocp.dims.ny = sum(
                [len(data[0]) for data in self.y_ref])
            self.acados_ocp.dims.ny_e = sum(
                [len(data) for data in self.y_ref_end])

            # Set weight
            self.acados_ocp.cost.W = self.W
            self.acados_ocp.cost.W_e = self.W_e

            # Set target shape
            self.acados_ocp.cost.yref = np.zeros(
                (self.acados_ocp.cost.W.shape[0], ))
            self.acados_ocp.cost.yref_e = np.zeros(
                (self.acados_ocp.cost.W_e.shape[0], ))

        elif self.acados_ocp.cost.cost_type == "NONLINEAR_LS":
            for i in range(ocp.n_phases):
                for j, J in enumerate(ocp.nlp[i].J):
                    if J[0]["objective"].type.get_type(
                    ) == ObjectiveFunction.LagrangeFunction:
                        self.lagrange_costs = vertcat(
                            self.lagrange_costs, J[0]["val"].reshape((-1, 1)))
                        self.W = linalg.block_diag(
                            self.W,
                            np.diag([J[0]["objective"].weight] *
                                    J[0]["val"].numel()))
                        if J[0]["target"] is not None:
                            self.y_ref.append([
                                J_tp["target"].T.reshape((-1, 1)) for J_tp in J
                            ])
                        else:
                            self.y_ref.append([
                                np.zeros((J_tp["val"].numel(), 1))
                                for J_tp in J
                            ])

                        # Deal with last node to match ipopt formulation
                        if J[0]["objective"].node[0].value == "all" and len(
                                J) > ocp.nlp[0].ns:
                            mayer_func_tp = Function(f"cas_mayer_func_{i}_{j}",
                                                     [ocp.nlp[i].X[-1]],
                                                     [J[0]["val"]])
                            self.W_e = linalg.block_diag(
                                self.W_e,
                                np.diag([J[0]["objective"].weight] *
                                        J[0]["val"].numel()))
                            self.mayer_costs = vertcat(
                                self.mayer_costs,
                                mayer_func_tp(ocp.nlp[i].X[0]).reshape(
                                    (-1, 1)))
                            if J[0]["target"] is not None:
                                self.y_ref_end.append(
                                    J[-1]["target"].T.reshape((-1, 1)))
                            else:
                                self.y_ref_end.append(
                                    np.zeros((J[-1]["val"].numel(), 1)))

                    elif J[0]["objective"].type.get_type(
                    ) == ObjectiveFunction.MayerFunction:
                        mayer_func_tp = Function(f"cas_mayer_func_{i}_{j}",
                                                 [ocp.nlp[i].X[-1]],
                                                 [J[0]["val"]])
                        self.W_e = linalg.block_diag(
                            self.W_e,
                            np.diag([J[0]["objective"].weight] *
                                    J[0]["val"].numel()))
                        self.mayer_costs = vertcat(
                            self.mayer_costs,
                            mayer_func_tp(ocp.nlp[i].X[0]).reshape((-1, 1)))
                        if J[0]["target"] is not None:
                            self.y_ref_end.append(J[0]["target"].T.reshape(
                                (-1, 1)))
                        else:
                            self.y_ref_end.append(
                                np.zeros((J[0]["val"].numel(), 1)))

                    else:
                        raise RuntimeError(
                            "The objective function is not Lagrange nor Mayer."
                        )

                # parameter as mayer function
                # IMPORTANT: it is considered that only parameters are stored in ocp.J, for now.
                if self.params.size:
                    for j, J in enumerate(ocp.J):
                        mayer_func_tp = Function(f"cas_J_mayer_func_{i}_{j}",
                                                 [ocp.nlp[i].X[-1]],
                                                 [J[0]["val"]])
                        self.W_e = linalg.block_diag(
                            self.W_e,
                            np.diag(([J[0]["objective"].weight] *
                                     J[0]["val"].numel())))
                        self.mayer_costs = vertcat(
                            self.mayer_costs,
                            mayer_func_tp(ocp.nlp[i].X[0]).reshape((-1, 1)))
                        if J[0]["target"] is not None:
                            self.y_ref_end.append(J[0]["target"].T.reshape(
                                (-1, 1)))
                        else:
                            self.y_ref_end.append(
                                np.zeros((J[0]["val"].numel(), 1)))

            # Set costs
            self.acados_ocp.model.cost_y_expr = self.lagrange_costs if self.lagrange_costs.numel(
            ) else SX(1, 1)
            self.acados_ocp.model.cost_y_expr_e = self.mayer_costs if self.mayer_costs.numel(
            ) else SX(1, 1)

            # Set dimensions
            self.acados_ocp.dims.ny = self.acados_ocp.model.cost_y_expr.shape[
                0]
            self.acados_ocp.dims.ny_e = self.acados_ocp.model.cost_y_expr_e.shape[
                0]

            # Set weight
            self.acados_ocp.cost.W = np.zeros(
                (1, 1)) if self.W.shape == (0, 0) else self.W
            self.acados_ocp.cost.W_e = np.zeros(
                (1, 1)) if self.W_e.shape == (0, 0) else self.W_e

            # Set target shape
            self.acados_ocp.cost.yref = np.zeros(
                (self.acados_ocp.cost.W.shape[0], ))
            self.acados_ocp.cost.yref_e = np.zeros(
                (self.acados_ocp.cost.W_e.shape[0], ))

        elif self.acados_ocp.cost.cost_type == "EXTERNAL":
            raise RuntimeError(
                "EXTERNAL is not interfaced yet, please use NONLINEAR_LS")

        else:
            raise RuntimeError(
                "Available acados cost type: 'LINEAR_LS', 'NONLINEAR_LS' and 'EXTERNAL'."
            )
Example #27
0
def test_multistep_trajectory(before_test_onestep_reachability):
    """ Compare multi-steps 'by hand' with the function """

    mu_0, _, gp, k_fb, k_ff, L_mu, L_sigm, c_safety, a, b = before_test_onestep_reachability
    T = 3
    n_u, n_s = np.shape(k_fb)

    k_fb_cas_single = SX.sym("k_fb_single", (n_u, n_s))
    k_ff_cas_single = SX.sym("k_ff_single", (n_u, 1))
    k_ff_cas_all = SX.sym("k_ff_single", (T, n_u))

    k_fb_cas_all = SX.sym("k_fb_all", (T - 1, n_s * n_u))
    k_fb_cas_all_inp = [
        k_fb_cas_all[i, :].reshape((n_u, n_s)) for i in range(T - 1)
    ]
    mu_0_cas = SX.sym("mu_0", (n_s, 1))
    sigma_0_cas = SX.sym("sigma_0", (n_s, n_s))

    mu_onestep_no_var_in, sigm_onestep_no_var_in, _ = prop_casadi.one_step_taylor(
        mu_0_cas, gp, k_ff_cas_single, a=a, b=b)

    mu_one_step, sigm_onestep, _ = prop_casadi.one_step_taylor(
        mu_0_cas,
        gp,
        k_ff_cas_single,
        k_fb=k_fb_cas_single,
        sigma_x=sigma_0_cas,
        a=a,
        b=b)

    mu_multistep, sigma_multistep, _ = prop_casadi.multi_step_taylor_symbolic(
        mu_0_cas, gp, k_ff_cas_all, k_fb_cas_all_inp, a=a, b=b)

    on_step_no_var_in = Function(
        "on_step_no_var_in", [mu_0_cas, k_ff_cas_single],
        [mu_onestep_no_var_in, sigm_onestep_no_var_in])
    one_step = Function(
        "one_step", [mu_0_cas, sigma_0_cas, k_ff_cas_single, k_fb_cas_single],
        [mu_one_step, sigm_onestep])
    multi_step = Function("multi_step", [mu_0_cas, k_ff_cas_all, k_fb_cas_all],
                          [mu_multistep, sigma_multistep])

    # TODO: Need mu, sigma as input aswell
    mu_1, sigma_1 = on_step_no_var_in(mu_0, k_ff)

    mu_2, sigma_2 = one_step(mu_1, sigma_1, k_ff, k_fb)
    mu_3, sigma_3 = one_step(mu_2, sigma_2, k_ff, k_fb)

    # TODO: stack k_ff and k_fb
    k_fb_mult = np.array(cas_reshape(k_fb, (1, n_u * n_s)))
    k_fb_mult = np.array(vertcat(*[k_fb_mult] * (T - 1)))

    k_ff_mult = vertcat(*[k_ff] * T)
    mu_all, sigma_all = multi_step(mu_0, k_ff_mult, k_fb_mult)

    assert np.allclose(
        np.array(mu_all[0, :]),
        np.array(mu_1).T), "Are the centers of the first prediction the same?"
    assert np.allclose(
        np.array(mu_all[-1, :]),
        np.array(mu_3).T), "Are the centers of the final prediction the same?"
    assert np.allclose(cas_reshape(sigma_all[-1, :], (n_s, n_s)),
                       sigma_3), "Are the last covariance matrices the same?"
Example #28
0
class PenaltyOption(OptionGeneric):
    """
    A placeholder for a penalty

    Attributes
    ----------
    node: Node
        The node within a phase on which the penalty is acting on
    quadratic: bool
        If the penalty is quadratic
    rows: Union[list, tuple, range, np.ndarray]
        The index of the rows in the penalty to keep
    cols: Union[list, tuple, range, np.ndarray]
        The index of the columns in the penalty to keep
    expand: bool
        If the penalty should be expanded or not
    target: np.array(target)
        A target to track for the penalty
    target_plot_name: str
        The plot name of the target
    target_to_plot: np.ndarray
        The subset of the target to plot
    plot_target: bool
        If the target should be plotted
    custom_function: Callable
        A user defined function to call to get the penalty
    node_idx: Union[list, tuple, Node]
        The index in nlp to apply the penalty to
    dt: float
        The delta time
    function: Function
        The casadi function of the penalty
    weighted_function: Function
        The casadi function of the penalty weighted
    derivative: bool
        If the minimization is applied on the numerical derivative of the state [f(t+1) - f(t)]
    explicit_derivative: bool
        If the minimization is applied to derivative of the penalty [f(t, t+1)]
    integration_rule: IntegralApproximation
        The integration rule to use for the penalty
    transition: bool
        If the penalty is a transition
    phase_pre_idx: int
        The index of the nlp of pre when penalty is transition
    phase_post_idx: int
        The index of the nlp of post when penalty is transition
    constraint_type: ConstraintType
        If the penalty is from the user or from bioptim (implicit or internal)
    multi_thread: bool
        If the penalty is multithreaded

    Methods
    -------
    set_penalty(self, penalty: Union[MX, SX], all_pn: PenaltyNodeList)
        Prepare the dimension and index of the penalty (including the target)
    _set_dim_idx(self, dim: Union[list, tuple, range, np.ndarray], n_rows: int)
        Checks if the variable index is consistent with the requested variable.
    _check_target_dimensions(self, all_pn: PenaltyNodeList, n_time_expected: int)
        Checks if the variable index is consistent with the requested variable.
        If the function returns, all is okay
    _set_penalty_function(self, all_pn: Union[PenaltyNodeList, list, tuple], fcn: Union[MX, SX])
        Finalize the preparation of the penalty (setting function and weighted_function)
    add_target_to_plot(self, all_pn: PenaltyNodeList, combine_to: str)
        Interface to the plot so it can be properly added to the proper plot
    _finish_add_target_to_plot(self, all_pn: PenaltyNodeList)
        Internal interface to add (after having check the target dimensions) the target to the plot if needed
    add_or_replace_to_penalty_pool(self, ocp, nlp)
        Doing some configuration on the penalty and add it to the list of penalty
    _add_penalty_to_pool(self, all_pn: PenaltyNodeList)
        Return the penalty pool for the specified penalty (abstract)
    clear_penalty(self, ocp, nlp)
        Resets a penalty. A negative penalty index creates a new empty penalty (abstract)
    _get_penalty_node_list(self, ocp, nlp) -> PenaltyNodeList
        Get the actual node (time, X and U) specified in the penalty
    """

    def __init__(
        self,
        penalty: Any,
        phase: int = 0,
        node: Union[Node, list, tuple] = Node.DEFAULT,
        target: Union[int, float, np.array, list[int], list[float], list[np.array]] = None,
        quadratic: bool = None,
        weight: float = 1,
        derivative: bool = False,
        explicit_derivative: bool = False,
        integrate: bool = False,
        integration_rule: IntegralApproximation = IntegralApproximation.DEFAULT,
        index: list = None,
        rows: Union[list, tuple, range, np.ndarray] = None,
        cols: Union[list, tuple, range, np.ndarray] = None,
        states_mapping: BiMapping = None,
        custom_function: Callable = None,
        constraint_type: ConstraintType = ConstraintType.USER,
        multi_thread: bool = None,
        expand: bool = False,
        **params: Any,
    ):
        """
        Parameters
        ----------
        penalty: PenaltyType
            The actual penalty
        phase: int
            The phase the penalty is acting on
        node: Union[Node, list, tuple]
            The node within a phase on which the penalty is acting on
        target: Union[int, float, np.array, list[int], list[float], list[np.array]]
            A target to track for the penalty
        quadratic: bool
            If the penalty is quadratic
        weight: float
            The weighting applied to this specific penalty
        derivative: bool
            If the function should be evaluated at X and X+1
        explicit_derivative: bool
            If the function should be evaluated at [X, X+1]
        integrate: bool
            If the function should be integrated
        integration_rule: IntegralApproximation
            The rule to use for the integration
        index: int
            The component index the penalty is acting on
        custom_function: Callable
            A user defined function to call to get the penalty
        constraint_type: ConstraintType
            If the penalty is from the user or from bioptim (implicit or internal)
        **params: dict
            Generic parameters for the penalty
        """

        super(PenaltyOption, self).__init__(phase=phase, type=penalty, **params)
        self.node: Union[Node, list, tuple] = node
        self.quadratic = quadratic
        self.integration_rule = integration_rule

        if index is not None and rows is not None:
            raise ValueError("rows and index cannot be defined simultaneously since they are the same variable")
        self.rows = rows if rows is not None else index
        self.cols = cols
        self.expand = expand

        self.target = None
        if target is not None:
            target = np.array(target)
            if isinstance(target, int) or isinstance(target, float) or isinstance(target, np.ndarray):
                target = [target]
            self.target = []
            for t in target:
                self.target.append(np.array(t))
                if len(self.target[-1].shape) == 0:
                    self.target[-1] = self.target[-1][np.newaxis]
                if len(self.target[-1].shape) == 1:
                    self.target[-1] = self.target[-1][:, np.newaxis]
            if len(self.target) == 1 and (
                self.integration_rule == IntegralApproximation.TRAPEZOIDAL
                or self.integration_rule == IntegralApproximation.TRUE_TRAPEZOIDAL
            ):
                if self.node == Node.ALL or self.node == Node.DEFAULT:
                    self.target = [self.target[0][:, :-1], self.target[0][:, 1:]]
                else:
                    raise NotImplementedError(
                        f"A list of 2 elements is required with {self.node} and TRAPEZOIDAL Integration"
                        f"except for Node.NODE_ALL and Node.NODE_DEFAULT"
                        "which can be automatically generated"
                    )

        self.target_plot_name = None
        self.target_to_plot = None
        # todo: not implemented yet for trapezoidal integration
        self.plot_target = (
            False
            if (
                self.integration_rule == IntegralApproximation.TRAPEZOIDAL
                or self.integration_rule == IntegralApproximation.TRUE_TRAPEZOIDAL
            )
            else True
        )

        self.states_mapping = states_mapping

        self.custom_function = custom_function

        self.node_idx = []
        self.dt = 0
        self.weight = weight
        self.function: Union[Function, None] = None
        self.function_non_threaded: Union[Function, None] = None
        self.weighted_function: Union[Function, None] = None
        self.weighted_function_non_threaded: Union[Function, None] = None
        self.derivative = derivative
        self.explicit_derivative = explicit_derivative
        self.integrate = integrate
        self.transition = False
        self.multinode_constraint = False
        self.phase_pre_idx = None
        self.phase_post_idx = None
        if self.derivative and self.explicit_derivative:
            raise ValueError("derivative and explicit_derivative cannot be both True")
        self.constraint_type = constraint_type

        self.multi_thread = multi_thread

    def set_penalty(self, penalty: Union[MX, SX], all_pn: PenaltyNodeList):
        """
        Prepare the dimension and index of the penalty (including the target)

        Parameters
        ----------
        penalty: Union[MX, SX],
            The actual penalty function
        all_pn: PenaltyNodeList
            The penalty node elements
        """

        self.rows = self._set_dim_idx(self.rows, penalty.rows())
        self.cols = self._set_dim_idx(self.cols, penalty.columns())
        if self.target is not None:
            self._check_target_dimensions(all_pn, len(all_pn.t))
            if self.plot_target:
                self._finish_add_target_to_plot(all_pn)
        self._set_penalty_function(all_pn, penalty)
        self._add_penalty_to_pool(all_pn)

    def _set_dim_idx(self, dim: Union[list, tuple, range, np.ndarray], n_rows: int):
        """
        Checks if the variable index is consistent with the requested variable.

        Parameters
        ----------
        dim: Union[list, tuple, range]
            The dimension to set
        n_rows: int
            The expected row shape

        Returns
        -------
        The formatted indices
        """

        if dim is None:
            dim = range(n_rows)
        else:
            if isinstance(dim, int):
                dim = [dim]
            if max(dim) > n_rows:
                raise RuntimeError(f"{self.name} index cannot be higher than nx ({n_rows})")
        dim = np.array(dim)
        if not np.issubdtype(dim.dtype, np.integer):
            raise RuntimeError(f"{self.name} index must be a list of integer")
        return dim

    def _check_target_dimensions(self, all_pn: PenaltyNodeList, n_time_expected: int):
        """
        Checks if the variable index is consistent with the requested variable.
        If the function returns, all is okay

        Parameters
        ----------
        all_pn: PenaltyNodeList
            The penalty node elements
        n_time_expected: Union[list, tuple]
            The expected shape (n_rows, ns) of the data to track
        """

        if self.integration_rule == IntegralApproximation.RECTANGLE:
            n_dim = len(self.target[0].shape)
            if n_dim != 2 and n_dim != 3:
                raise RuntimeError(
                    f"target cannot be a vector (it can be a matrix with time dimension equals to 1 though)"
                )
            if self.target[0].shape[-1] == 1:
                self.target = np.repeat(self.target, n_time_expected, axis=-1)

            shape = (
                (len(self.rows), n_time_expected) if n_dim == 2 else (len(self.rows), len(self.cols), n_time_expected)
            )
            if self.target[0].shape != shape:
                raise RuntimeError(
                    f"target {self.target[0].shape} does not correspond to expected size {shape} for penalty {self.name}"
                )

            # If the target is on controls and control is constant, there will be one value missing
            if all_pn is not None:
                if (
                    all_pn.nlp.control_type == ControlType.CONSTANT
                    and all_pn.nlp.ns in all_pn.t
                    and self.target[0].shape[-1] == all_pn.nlp.ns
                ):
                    if all_pn.t[-1] != all_pn.nlp.ns:
                        raise NotImplementedError("Modifying target for END not being last is not implemented yet")
                    self.target[0] = np.concatenate(
                        (self.target[0], np.nan * np.zeros((self.target[0].shape[0], 1))), axis=1
                    )
        elif (
            self.integration_rule == IntegralApproximation.TRAPEZOIDAL
            or self.integration_rule == IntegralApproximation.TRAPEZOIDAL
        ):

            target_dim = len(self.target)
            if target_dim != 2:
                raise RuntimeError(f"targets with trapezoidal integration rule need to get a list of two elements.")

            for target in self.target:
                n_dim = len(target.shape)
                if n_dim != 2 and n_dim != 3:
                    raise RuntimeError(
                        f"target cannot be a vector (it can be a matrix with time dimension equals to 1 though)"
                    )
                if target.shape[-1] == 1:
                    target = np.repeat(target, n_time_expected, axis=-1)

            shape = (
                (len(self.rows), n_time_expected - 1)
                if n_dim == 2
                else (len(self.rows), len(self.cols), n_time_expected - 1)
            )

            for target in self.target:
                if target.shape != shape:
                    raise RuntimeError(
                        f"target {target.shape} does not correspond to expected size {shape} for penalty {self.name}"
                    )

            # If the target is on controls and control is constant, there will be one value missing
            if all_pn is not None:
                if (
                    all_pn.nlp.control_type == ControlType.CONSTANT
                    and all_pn.nlp.ns in all_pn.t
                    and self.target[0].shape[-1] == all_pn.nlp.ns - 1
                    and self.target[1].shape[-1] == all_pn.nlp.ns - 1
                ):
                    if all_pn.t[-1] != all_pn.nlp.ns:
                        raise NotImplementedError("Modifying target for END not being last is not implemented yet")
                    self.target = np.concatenate((self.target, np.nan * np.zeros((self.target.shape[0], 1))), axis=1)

    def _set_penalty_function(self, all_pn: Union[PenaltyNodeList, list, tuple], fcn: Union[MX, SX]):
        """
        Finalize the preparation of the penalty (setting function and weighted_function)

        Parameters
        ----------
        all_pn: PenaltyNodeList
            The nodes
        fcn: Union[MX, SX]
            The value of the penalty function
        """

        # Sanity checks
        if self.transition and self.explicit_derivative:
            raise ValueError("transition and explicit_derivative cannot be true simultaneously")
        if self.transition and self.derivative:
            raise ValueError("transition and derivative cannot be true simultaneously")
        if self.derivative and self.explicit_derivative:
            raise ValueError("derivative and explicit_derivative cannot be true simultaneously")

        def get_u(nlp, u: Union[MX, SX], dt: Union[MX, SX]):
            """
            Get the control at a given time

            Parameters
            ----------
            nlp: NonlinearProgram
                The nonlinear program
            u: Union[MX, SX]
                The control matrix
            dt: Union[MX, SX]
                The time a which control should be computed

            Returns
            -------
            The control at a given time
            """

            if nlp.control_type == ControlType.CONSTANT:
                return u
            elif nlp.control_type == ControlType.LINEAR_CONTINUOUS:
                return u[:, 0] + (u[:, 1] - u[:, 0]) * dt
            else:
                raise RuntimeError(f"{nlp.control_type} ControlType not implemented yet")

            return u

        if self.multinode_constraint or self.transition:
            ocp = all_pn[0].ocp
            nlp = all_pn[0].nlp
            nlp_post = all_pn[1].nlp
            name = self.name.replace("->", "_").replace(" ", "_").replace(",", "_")
            states_pre = nlp.states.cx_end
            states_post = nlp_post.states.cx
            controls_pre = nlp.controls.cx_end
            controls_post = nlp_post.controls.cx
            state_cx = vertcat(states_pre, states_post)
            control_cx = vertcat(controls_pre, controls_post)

        else:
            ocp = all_pn.ocp
            nlp = all_pn.nlp
            name = self.name
            if self.integrate:
                state_cx = horzcat(*([all_pn.nlp.states.cx] + all_pn.nlp.states.cx_intermediates_list))
                control_cx = all_pn.nlp.controls.cx
            else:
                state_cx = all_pn.nlp.states.cx
                control_cx = all_pn.nlp.controls.cx
            if self.explicit_derivative:
                if self.derivative:
                    raise RuntimeError("derivative and explicit_derivative cannot be simultaneously true")
                state_cx = horzcat(state_cx, all_pn.nlp.states.cx_end)
                control_cx = horzcat(control_cx, all_pn.nlp.controls.cx_end)

        param_cx = nlp.cx(nlp.parameters.cx)

        # Do not use nlp.add_casadi_func because all functions must be registered
        sub_fcn = fcn[self.rows, self.cols]
        self.function = biorbd.to_casadi_func(name, sub_fcn, state_cx, control_cx, param_cx, expand=self.expand)
        self.function_non_threaded = self.function

        if self.derivative:
            state_cx = horzcat(all_pn.nlp.states.cx_end, all_pn.nlp.states.cx)
            control_cx = horzcat(all_pn.nlp.controls.cx_end, all_pn.nlp.controls.cx)
            self.function = biorbd.to_casadi_func(
                f"{name}",
                self.function(all_pn.nlp.states.cx_end, all_pn.nlp.controls.cx_end, param_cx)
                - self.function(all_pn.nlp.states.cx, all_pn.nlp.controls.cx, param_cx),
                state_cx,
                control_cx,
                param_cx,
            )

        dt_cx = nlp.cx.sym("dt", 1, 1)
        is_trapezoidal = (
            self.integration_rule == IntegralApproximation.TRAPEZOIDAL
            or self.integration_rule == IntegralApproximation.TRUE_TRAPEZOIDAL
        )
        target_shape = tuple(
            [
                len(self.rows),
                len(self.cols) + 1 if is_trapezoidal else len(self.cols),
            ]
        )
        target_cx = nlp.cx.sym("target", target_shape)
        weight_cx = nlp.cx.sym("weight", 1, 1)
        exponent = 2 if self.quadratic and self.weight else 1

        if is_trapezoidal:
            # Hypothesis: the function is continuous on states
            # it neglects the discontinuities at the beginning of the optimization
            state_cx = (
                horzcat(all_pn.nlp.states.cx, all_pn.nlp.states.cx_end)
                if self.integration_rule == IntegralApproximation.TRAPEZOIDAL
                else all_pn.nlp.states.cx
            )
            # to handle piecewise constant in controls we have to compute the value for the end of the interval
            # which only relies on the value of the control at the beginning of the interval
            control_cx = (
                horzcat(all_pn.nlp.controls.cx)
                if nlp.control_type == ControlType.CONSTANT
                else horzcat(all_pn.nlp.controls.cx, all_pn.nlp.controls.cx_end)
            )
            control_cx_end = get_u(nlp, control_cx, dt_cx)
            state_cx_end = (
                all_pn.nlp.states.cx_end
                if self.integration_rule == IntegralApproximation.TRAPEZOIDAL
                else nlp.dynamics[0](x0=state_cx, p=control_cx_end, params=nlp.parameters.cx)["xf"]
            )
            self.modified_function = biorbd.to_casadi_func(
                f"{name}",
                (
                    (self.function(all_pn.nlp.states.cx, all_pn.nlp.controls.cx, param_cx) - target_cx[:, 0])
                    ** exponent
                    + (self.function(state_cx_end, control_cx_end, param_cx) - target_cx[:, 1]) ** exponent
                )
                / 2,
                state_cx,
                control_cx,
                param_cx,
                target_cx,
                dt_cx,
            )
            modified_fcn = self.modified_function(state_cx, control_cx, param_cx, target_cx, dt_cx)
        else:
            modified_fcn = (self.function(state_cx, control_cx, param_cx) - target_cx) ** exponent

        modified_fcn = weight_cx * modified_fcn * dt_cx if self.weight else modified_fcn * dt_cx

        # Do not use nlp.add_casadi_func because all of them must be registered
        self.weighted_function = Function(
            name, [state_cx, control_cx, param_cx, weight_cx, target_cx, dt_cx], [modified_fcn]
        )
        self.weighted_function_non_threaded = self.weighted_function

        if ocp.n_threads > 1 and self.multi_thread and len(self.node_idx) > 1:
            self.function = self.function.map(len(self.node_idx), "thread", ocp.n_threads)
            self.weighted_function = self.weighted_function.map(len(self.node_idx), "thread", ocp.n_threads)
        else:
            self.multi_thread = False  # Override the multi_threading, since only one node is optimized

        if self.expand:
            self.function = self.function.expand()
            self.weighted_function = self.weighted_function.expand()

    def add_target_to_plot(self, all_pn: PenaltyNodeList, combine_to: str):
        """
        Interface to the plot so it can be properly added to the proper plot

        Parameters
        ----------
        all_pn: PenaltyNodeList
            The penalty node elements
        combine_to: str
            The name of the underlying plot to combine the tracking data to
        """

        if self.target is None or combine_to is None:
            return

        self.target_plot_name = combine_to
        # if the target is n x ns, we need to add a dimension (n x ns + 1) to make it compatible with the plot
        if self.target[0].shape[1] == all_pn.nlp.ns:
            self.target_to_plot = np.concatenate(
                (self.target[0], np.nan * np.ndarray((self.target[0].shape[0], 1))), axis=1
            )
        else:
            self.target_to_plot = self.target[0]

    def _finish_add_target_to_plot(self, all_pn: PenaltyNodeList):
        """
        Internal interface to add (after having check the target dimensions) the target to the plot if needed

        Parameters
        ----------
        all_pn: PenaltyNodeList
            The penalty node elements

        """

        def plot_function(t, x, u, p):
            if isinstance(t, (list, tuple)):
                return self.target_to_plot[:, [self.node_idx.index(_t) for _t in t]]
            else:
                return self.target_to_plot[:, self.node_idx.index(t)]

        if self.target_to_plot is not None:
            if self.target_to_plot.shape[1] > 1:
                plot_type = PlotType.STEP
            else:
                plot_type = PlotType.POINT

            all_pn.ocp.add_plot(
                self.target_plot_name,
                plot_function,
                color="tab:red",
                plot_type=plot_type,
                phase=all_pn.nlp.phase_idx,
                axes_idx=Mapping(self.rows),
                node_idx=self.node_idx,
            )

    def add_or_replace_to_penalty_pool(self, ocp, nlp):
        """
        Doing some configuration on the penalty and add it to the list of penalty

        Parameters
        ----------
        ocp: OptimalControlProgram
            A reference to the ocp
        nlp: NonLinearProgram
            A reference to the current phase of the ocp
        """
        if not self.name:
            if self.type.name == "CUSTOM":
                self.name = self.custom_function.__name__
            else:
                self.name = self.type.name

        penalty_type = self.type.get_type()
        if self.node == Node.TRANSITION:
            all_pn = []

            # Make sure the penalty behave like a PhaseTransition, even though it may be an Objective or Constraint
            self.node = Node.END
            self.node_idx = [0]
            self.transition = True
            self.dt = 1
            self.phase_pre_idx = nlp.phase_idx
            self.phase_post_idx = (nlp.phase_idx + 1) % ocp.n_phases
            if not self.states_mapping:
                self.states_mapping = BiMapping(range(nlp.states.shape), range(nlp.states.shape))

            all_pn.append(self._get_penalty_node_list(ocp, nlp))
            all_pn[0].u = [nlp.U[-1]]  # Make an exception to the fact that U is not available for the last node

            nlp = ocp.nlp[(nlp.phase_idx + 1) % ocp.n_phases]
            self.node = Node.START
            all_pn.append(self._get_penalty_node_list(ocp, nlp))

            self.node = Node.TRANSITION

            penalty_type.validate_penalty_time_index(self, all_pn[0])
            penalty_type.validate_penalty_time_index(self, all_pn[1])
            self.clear_penalty(ocp, all_pn[0].nlp)

        elif isinstance(self.node, tuple) and self.multinode_constraint:
            all_pn = []
            self.node_list = self.node
            # Make sure the penalty behave like a MultinodeConstraint, even though it may be an Objective or Constraint
            # self.transition = True
            self.dt = 1
            # self.phase_pre_idx
            # self.phase_post_idx = (nlp.phase_idx + 1) % ocp.n_phases
            if not self.states_mapping:
                self.states_mapping = BiMapping(range(nlp.states.shape), range(nlp.states.shape))
            self.node = self.node_list[0]
            nlp = ocp.nlp[self.phase_first_idx]
            all_pn.append(self._get_penalty_node_list(ocp, nlp))
            if self.node == Node.END:
                all_pn[0].u = [nlp.U[-1]]
                # Make an exception to the fact that U is not available for the last node

            self.node = self.node_list[1]
            nlp = ocp.nlp[self.phase_second_idx]
            all_pn.append(self._get_penalty_node_list(ocp, nlp))
            if self.node == Node.END:
                all_pn[1].u = [nlp.U[-1]]
                # Make an exception to the fact that U is not available for the last node

            # reset the node list
            self.node = self.node_list

            penalty_type.validate_penalty_time_index(self, all_pn[0])
            penalty_type.validate_penalty_time_index(self, all_pn[1])
            self.node_idx = [all_pn[0].t[0], all_pn[1].t[0]]
            self.clear_penalty(ocp, all_pn[0].nlp)
        else:
            all_pn = self._get_penalty_node_list(ocp, nlp)
            penalty_type.validate_penalty_time_index(self, all_pn)
            self.clear_penalty(all_pn.ocp, all_pn.nlp)
            self.dt = penalty_type.get_dt(all_pn.nlp)
            self.node_idx = (
                all_pn.t[:-1]
                if (
                    self.integration_rule == IntegralApproximation.TRAPEZOIDAL
                    or self.integration_rule == IntegralApproximation.TRUE_TRAPEZOIDAL
                )
                and self.target is not None
                else all_pn.t
            )

        penalty_function = self.type.value[0](self, all_pn, **self.params)
        self.set_penalty(penalty_function, all_pn)

    def _add_penalty_to_pool(self, all_pn: PenaltyNodeList):
        """
        Return the penalty pool for the specified penalty (abstract)

        Parameters
        ----------
        all_pn: PenaltyNodeList
            The penalty node elements
        """

        raise RuntimeError("get_dt cannot be called from an abstract class")

    def clear_penalty(self, ocp, nlp):
        """
        Resets a penalty. A negative penalty index creates a new empty penalty (abstract)

        Parameters
        ----------
        ocp: OptimalControlProgram
            A reference to the ocp
        nlp: NonLinearProgram
            A reference to the current phase of the ocp
        """

        raise RuntimeError("_reset_penalty cannot be called from an abstract class")

    def _get_penalty_node_list(self, ocp, nlp) -> PenaltyNodeList:
        """
        Get the actual node (time, X and U) specified in the penalty

        Parameters
        ----------
        ocp: OptimalControlProgram
            A reference to the ocp
        nlp: NonLinearProgram
            A reference to the current phase of the ocp

        Returns
        -------
        The actual node (time, X and U) specified in the penalty
        """

        if not isinstance(self.node, (list, tuple)):
            self.node = (self.node,)

        t = []
        for node in self.node:
            if isinstance(node, int):
                if node < 0 or node > nlp.ns:
                    raise RuntimeError(f"Invalid node, {node} must be between 0 and {nlp.ns}")
                t.append(node)
            elif node == Node.START:
                t.append(0)
            elif node == Node.MID:
                if nlp.ns % 2 == 1:
                    raise (ValueError("Number of shooting points must be even to use MID"))
                t.append(nlp.ns // 2)
            elif node == Node.INTERMEDIATES:
                t.extend(list(i for i in range(1, nlp.ns - 1)))
            elif node == Node.PENULTIMATE:
                if nlp.ns < 2:
                    raise (ValueError("Number of shooting points must be greater than 1"))
                t.append(nlp.ns - 1)
            elif node == Node.END:
                t.append(nlp.ns)
            elif node == Node.ALL_SHOOTING:
                t.extend(range(nlp.ns))
            elif node == Node.ALL:
                t.extend(range(nlp.ns + 1))
            else:
                raise RuntimeError(" is not a valid node")

        x = [nlp.X[idx] for idx in t]
        u = [nlp.U[idx] for idx in t if idx != nlp.ns]
        return PenaltyNodeList(ocp, nlp, t, x, u, nlp.parameters.cx)
Example #29
0
    def _create_nu_update_func(self):
        v = self.opt_problem.x
        x_var, y_var, u_var, eta, p_opt, theta_opt = self.ocp_solver.discretizer.unpack_decision_variables(
            v)
        par = MX.sym('par', self.model.n_p)
        theta = dict([(i, vec(MX.sym('theta_' + repr(i), self.model.n_theta)))
                      for i in range(self.finite_elements)])
        theta_var = vertcat(*[theta[i] for i in range(self.finite_elements)])

        time_dict = dict([(i, {}) for i in range(self.finite_elements)])

        for el in range(self.finite_elements):
            time_dict[el]['t_0'] = self.time_breakpoints[el]
            time_dict[el]['t_f'] = self.time_breakpoints[el + 1]
            time_dict[el]['f_nu'] = self.time_interpolation_nu[el]
            time_dict[el]['f_relax_alg'] = self.time_interpolation_nu[el]
            time_dict[el]['f_relax_eq'] = self.time_interpolation_nu[el]

        functions = defaultdict(dict)
        for el in range(self.finite_elements):
            func_rel_alg = self.model.convert_expr_from_tau_to_time(
                substitute(self.relaxed_alg, self.model.u, self.model.u_expr),
                self.time_breakpoints[el], self.time_breakpoints[el + 1])
            func_rel_eq = self.model.convert_expr_from_tau_to_time(
                substitute(self.relaxed_eq, self.model.u, self.model.u_expr),
                self.time_breakpoints[el], self.time_breakpoints[el + 1])
            nu_time_dependent = self.model.convert_expr_from_tau_to_time(
                self.nu_pol, self.time_breakpoints[el],
                self.time_breakpoints[el + 1])

            f_nu = Function('f_nu', self.model.all_sym, [nu_time_dependent])
            f_relax_alg = Function('f_relax_alg', self.model.all_sym,
                                   [func_rel_alg])
            f_relax_eq = Function('f_relax_eq', self.model.all_sym,
                                  [func_rel_eq])

            functions['f_nu'][el] = f_nu
            functions['f_relax_alg'][el] = f_relax_alg
            functions['f_relax_eq'][el] = f_relax_eq

        # get values (symbolically)
        results = self.ocp_solver.discretizer.get_system_at_given_times(
            x_var,
            y_var,
            u_var,
            time_dict,
            p=par,
            theta=theta,
            functions=functions)

        # compute new nu
        mu_mx = par[find_variables_indices_in_vector(self.mu_sym,
                                                     self.model.p)]
        new_nu = []
        rel_alg = []
        rel_eq = []
        for el in range(self.finite_elements):
            new_nu_k = []
            rel_alg_k = []
            rel_eq_k = []
            for j in range(self.degree):
                nu_kj = results[el]['f_nu'][j]
                rel_alg_kj = results[el]['f_relax_alg'][j]
                rel_eq_kj = results[el]['f_relax_eq'][j]
                rel_kj = vertcat(rel_alg_kj, rel_eq_kj)

                new_nu_k = horzcat(new_nu_k, nu_kj + mu_mx * rel_kj)
                rel_alg_k = horzcat(rel_alg_k, rel_alg_kj)
                rel_eq_k = horzcat(rel_eq_k, rel_eq_kj)
            new_nu.append(vec(new_nu_k))
            rel_alg.append(vec(rel_alg_k))
            rel_eq.append(vec(rel_eq_k))

        output = new_nu + rel_alg + rel_eq
        self.new_nu_func = Function('nu_update_function', [v, par, theta_var],
                                    output)
Example #30
0
    def _set_penalty_function(self, all_pn: Union[PenaltyNodeList, list, tuple], fcn: Union[MX, SX]):
        """
        Finalize the preparation of the penalty (setting function and weighted_function)

        Parameters
        ----------
        all_pn: PenaltyNodeList
            The nodes
        fcn: Union[MX, SX]
            The value of the penalty function
        """

        # Sanity checks
        if self.transition and self.explicit_derivative:
            raise ValueError("transition and explicit_derivative cannot be true simultaneously")
        if self.transition and self.derivative:
            raise ValueError("transition and derivative cannot be true simultaneously")
        if self.derivative and self.explicit_derivative:
            raise ValueError("derivative and explicit_derivative cannot be true simultaneously")

        def get_u(nlp, u: Union[MX, SX], dt: Union[MX, SX]):
            """
            Get the control at a given time

            Parameters
            ----------
            nlp: NonlinearProgram
                The nonlinear program
            u: Union[MX, SX]
                The control matrix
            dt: Union[MX, SX]
                The time a which control should be computed

            Returns
            -------
            The control at a given time
            """

            if nlp.control_type == ControlType.CONSTANT:
                return u
            elif nlp.control_type == ControlType.LINEAR_CONTINUOUS:
                return u[:, 0] + (u[:, 1] - u[:, 0]) * dt
            else:
                raise RuntimeError(f"{nlp.control_type} ControlType not implemented yet")

            return u

        if self.multinode_constraint or self.transition:
            ocp = all_pn[0].ocp
            nlp = all_pn[0].nlp
            nlp_post = all_pn[1].nlp
            name = self.name.replace("->", "_").replace(" ", "_").replace(",", "_")
            states_pre = nlp.states.cx_end
            states_post = nlp_post.states.cx
            controls_pre = nlp.controls.cx_end
            controls_post = nlp_post.controls.cx
            state_cx = vertcat(states_pre, states_post)
            control_cx = vertcat(controls_pre, controls_post)

        else:
            ocp = all_pn.ocp
            nlp = all_pn.nlp
            name = self.name
            if self.integrate:
                state_cx = horzcat(*([all_pn.nlp.states.cx] + all_pn.nlp.states.cx_intermediates_list))
                control_cx = all_pn.nlp.controls.cx
            else:
                state_cx = all_pn.nlp.states.cx
                control_cx = all_pn.nlp.controls.cx
            if self.explicit_derivative:
                if self.derivative:
                    raise RuntimeError("derivative and explicit_derivative cannot be simultaneously true")
                state_cx = horzcat(state_cx, all_pn.nlp.states.cx_end)
                control_cx = horzcat(control_cx, all_pn.nlp.controls.cx_end)

        param_cx = nlp.cx(nlp.parameters.cx)

        # Do not use nlp.add_casadi_func because all functions must be registered
        sub_fcn = fcn[self.rows, self.cols]
        self.function = biorbd.to_casadi_func(name, sub_fcn, state_cx, control_cx, param_cx, expand=self.expand)
        self.function_non_threaded = self.function

        if self.derivative:
            state_cx = horzcat(all_pn.nlp.states.cx_end, all_pn.nlp.states.cx)
            control_cx = horzcat(all_pn.nlp.controls.cx_end, all_pn.nlp.controls.cx)
            self.function = biorbd.to_casadi_func(
                f"{name}",
                self.function(all_pn.nlp.states.cx_end, all_pn.nlp.controls.cx_end, param_cx)
                - self.function(all_pn.nlp.states.cx, all_pn.nlp.controls.cx, param_cx),
                state_cx,
                control_cx,
                param_cx,
            )

        dt_cx = nlp.cx.sym("dt", 1, 1)
        is_trapezoidal = (
            self.integration_rule == IntegralApproximation.TRAPEZOIDAL
            or self.integration_rule == IntegralApproximation.TRUE_TRAPEZOIDAL
        )
        target_shape = tuple(
            [
                len(self.rows),
                len(self.cols) + 1 if is_trapezoidal else len(self.cols),
            ]
        )
        target_cx = nlp.cx.sym("target", target_shape)
        weight_cx = nlp.cx.sym("weight", 1, 1)
        exponent = 2 if self.quadratic and self.weight else 1

        if is_trapezoidal:
            # Hypothesis: the function is continuous on states
            # it neglects the discontinuities at the beginning of the optimization
            state_cx = (
                horzcat(all_pn.nlp.states.cx, all_pn.nlp.states.cx_end)
                if self.integration_rule == IntegralApproximation.TRAPEZOIDAL
                else all_pn.nlp.states.cx
            )
            # to handle piecewise constant in controls we have to compute the value for the end of the interval
            # which only relies on the value of the control at the beginning of the interval
            control_cx = (
                horzcat(all_pn.nlp.controls.cx)
                if nlp.control_type == ControlType.CONSTANT
                else horzcat(all_pn.nlp.controls.cx, all_pn.nlp.controls.cx_end)
            )
            control_cx_end = get_u(nlp, control_cx, dt_cx)
            state_cx_end = (
                all_pn.nlp.states.cx_end
                if self.integration_rule == IntegralApproximation.TRAPEZOIDAL
                else nlp.dynamics[0](x0=state_cx, p=control_cx_end, params=nlp.parameters.cx)["xf"]
            )
            self.modified_function = biorbd.to_casadi_func(
                f"{name}",
                (
                    (self.function(all_pn.nlp.states.cx, all_pn.nlp.controls.cx, param_cx) - target_cx[:, 0])
                    ** exponent
                    + (self.function(state_cx_end, control_cx_end, param_cx) - target_cx[:, 1]) ** exponent
                )
                / 2,
                state_cx,
                control_cx,
                param_cx,
                target_cx,
                dt_cx,
            )
            modified_fcn = self.modified_function(state_cx, control_cx, param_cx, target_cx, dt_cx)
        else:
            modified_fcn = (self.function(state_cx, control_cx, param_cx) - target_cx) ** exponent

        modified_fcn = weight_cx * modified_fcn * dt_cx if self.weight else modified_fcn * dt_cx

        # Do not use nlp.add_casadi_func because all of them must be registered
        self.weighted_function = Function(
            name, [state_cx, control_cx, param_cx, weight_cx, target_cx, dt_cx], [modified_fcn]
        )
        self.weighted_function_non_threaded = self.weighted_function

        if ocp.n_threads > 1 and self.multi_thread and len(self.node_idx) > 1:
            self.function = self.function.map(len(self.node_idx), "thread", ocp.n_threads)
            self.weighted_function = self.weighted_function.map(len(self.node_idx), "thread", ocp.n_threads)
        else:
            self.multi_thread = False  # Override the multi_threading, since only one node is optimized

        if self.expand:
            self.function = self.function.expand()
            self.weighted_function = self.weighted_function.expand()
    q_dot = states_sol["q_dot"]
    activations = states_sol["muscles"]
    tau = controls_sol["tau"]
    excitations = controls_sol["muscles"]

    n_q = ocp.nlp[0]["model"].nbQ()
    n_qdot = ocp.nlp[0]["model"].nbQdot()
    n_mark = ocp.nlp[0]["model"].nbMarkers()
    n_frames = q.shape[1]

    markers = np.ndarray((3, n_mark, q.shape[1]))
    symbolic_states = MX.sym("x", n_q, 1)
    markers_func = Function(
        "ForwardKin",
        [symbolic_states],
        [biorbd_model.markers(symbolic_states)],
        ["q"],
        ["markers"],
    ).expand()
    for i in range(n_frames):
        markers[:, :, i] = markers_func(q[:, i])

    plt.figure("Markers")
    for i in range(markers.shape[1]):
        plt.plot(np.linspace(0, 2, n_shooting_points + 1),
                 markers_ref[:, i, :].T, "k")
        plt.plot(np.linspace(0, 2, n_shooting_points + 1), markers[:, i, :].T,
                 "r--")
    plt.xlabel("Time")
    plt.ylabel("Markers Position")
Example #32
0
def qp_solve(prob, obj, p_init, x_init, y_init, lam_opt, mu_opt, case):
    """
    QP solver for path-following algorithm
    inputs: prob - problem description
            obj - problem equations
            p_init - initial parameter
            x_init - initial primal variable
            y_init - initial dual variable
            lam_opt - Lagrange multipliers of equality and active constraints
            mu_opt - Lagrange multipliers of inequality constraints
    outputs: y - solution primal variable
            qp_val - objective function value
            qp_exit - return status of QP solver
            deriv - derivatives of the problem
            k_zero_tilde - active set index
            k_plus_tilde - inactive set index
            grad - gradient of objective function
    """
    print 'Current point x:', x_init
    #Importing problem to be solved
    nx, np, neq, niq, name = prob()
    x, p, f, f_fun, con, conf, ubx, lbx, ubg, lbg = obj(
        x_init, y_init, p_init, neq, niq, nx, np)

    #Deteriming constraint types
    eq_con_ind = array([])  #indices of equality constraints
    iq_con_ind = array([])  #indices of inequality constraints
    eq_con = array([])  #equality constraints
    iq_con = array([])  #inequality constraints

    for i in range(0, len(lbg[0])):
        if lbg[0, i] == 0:
            eq_con = vertcat(eq_con, con[i])
            eq_con_ind = append(eq_con_ind, i)
        elif lbg[0, i] < 0:
            iq_con = vertcat(iq_con, con[i])
            iq_con_ind = append(iq_con_ind, i)
#    print 'Equality Constraint:', eq_con
#    print 'Inequality Constraint:', iq_con

#    if case == 'pure-predictor':

#       return qp_exit, optimal, x_qpopt, lam_qpopt, mu_qpopt
    if case == 'predictor-corrector':
        #Evaluating constraints at current iteration point
        con_vals = conf(x_init, p_init)
        #Determining which inequality constraints are active
        k_plus_tilde = array([])  #active constraint
        k_zero_tilde = array([])  #inactive constraint
        tol = 10e-5  #tolerance
        for i in range(0, len(iq_con_ind)):
            if ubg[0, i] - tol <= con_vals[i] and con_vals[i] <= ubg[0,
                                                                     i] + tol:
                k_plus_tilde = append(k_plus_tilde, i)
            else:
                k_zero_tilde = append(k_zero_tilde, i)
#        print 'Active constraints:', k_plus_tilde
#        print 'Inactive constraints:', k_zero_tilde
#        print 'Constraint values:', con_vals

        nk_pt = len(k_plus_tilde)  #number of active constraints
        nk_zt = len(k_zero_tilde)  #number of inactive constraints

        #Calculating Lagrangian
        lam = SX.sym('lam', neq)  #Lagrangian multiplier equality constraints
        mu = SX.sym('mu', niq)  #Lagrangian multiplier inequality constraints
        lag_f = f + mtimes(lam.T, eq_con) + mtimes(
            mu.T, iq_con)  #Lagrangian equation

        #Calculating derivatives
        g = gradient(f, x)  #Derivative of objective function
        g_fun = Function('g_fun', [x, p], [gradient(f, x)])
        H = 2 * jacobian(gradient(lag_f, x),
                         x)  #Second derivative of the Lagrangian
        H_fun = Function('H_fun', [x, p, lam, mu],
                         [jacobian(jacobian(lag_f, x), x)])

        if len(eq_con_ind) > 0:
            deq = jacobian(eq_con, x)  #Derivative of equality constraints
        else:
            deq = array([])
        if len(iq_con_ind) > 0:
            diq = jacobian(iq_con, x)  #Derivative of inequality constraints
        else:
            diq = array([])
        #Creating constraint matrices
        nc = niq + neq  #Total number of constraints
        if (niq > 0) and (neq > 0):  #Equality and inequality constraints
            #this part needs to be tested
            if (nk_zt > 0):  #Inactive constraints exist
                A = SX.zeros((nc, nx))
                print deq
                A[0, :] = deq  #A matrix
                lba = -1e16 * SX.zeros((nc, 1))
                lba[0, :] = -eq_con  #lower bound of A
                uba = 1e16 * SX.zeros((nc, 1))
                uba[0, :] = -eq_con  #upper bound of A
                for j in range(0, nk_pt):  #adding active constraints
                    A[neq + j + 1, :] = diq[int(k_plus_tilde[j]), :]
                    lba[neq + j + 1] = -iq_con[int(k_plus_tilde[j])]
                    uba[neq + j + 1] = -iq_con[int(k_plus_tilde[i])]
                for i in range(0, nk_zt):  #adding inactive constraints
                    A[neq + nk_pt + i + 1, :] = diq[int(k_zero_tilde[i]), :]
                    uba[neq + nk_pt + i + 1] = -iq_con[int(k_zero_tilde[i])]
                    #inactive constraints don't have lower bounds
            else:  #Active constraints only
                A = vertcat(deq, diq)
                lba = vertcat(-eq_con, -iq_con)
                uba = vertcat(-eq_con, -iq_con)
        elif (niq > 0) and (neq == 0):  #Inquality constraints
            if (nk_zt > 0):  #Inactive constraints exist
                A = SX.zeros((nc, nx))
                lba = -1e16 * SX.ones((nc, 1))
                uba = 1e16 * SX.ones((nc, 1))
                for j in range(0, nk_pt):  #adding active constraints
                    A[j, :] = diq[int(k_plus_tilde[j]), :]
                    lba[j] = -iq_con[int(k_plus_tilde[j])]
                    uba[j] = -iq_con[int(k_plus_tilde[j])]
                for i in range(0, nk_zt):  #adding inactive constraints
                    A[nk_pt + i, :] = diq[int(k_zero_tilde[i]), :]
                    uba[nk_pt + i] = -iq_con[int(k_zero_tilde[i])]
                    #inactive constraints don't have lower bounds
            else:
                raw_input()
                A = vertcat(deq, diq)
                lba = -iq_con
                uba = -iq_con
        elif (niq == 0) and (neq > 0):  #Equality constriants
            A = deq
            lba = -eq_con
            uba = -eq_con
        A_fun = Function('A_fun', [x, p], [A])
        lba_fun = Function('lba_fun', [x, p], [lba])
        uba_fun = Function('uba_fun', [x, p], [uba])
        #Checking that matrices are correct sizes and types
        if (H.size1() != nx) or (H.size2() != nx) or (H.is_dense() == 'False'):
            #H matrix should be a sparse (nxn) and symmetrical
            print(
                'WARNING: H matrix is not the correct dimensions or matrix type'
            )
        if (g.size1() != nx) or (g.size2() != 1) or g.is_dense() == 'True':
            #g matrix should be a dense (nx1)
            print(
                'WARNING: g matrix is not the correct dimensions or matrix type'
            )
        if (A.size1() !=
            (neq + niq)) or (A.size2() != nx) or (A.is_dense() == 'False'):
            #A should be a sparse (nc x n)
            print(
                'WARNING: A matrix is not the correct dimensions or matrix type'
            )
        if lba.size1() != (neq + niq) or (lba.size2() !=
                                          1) or lba.is_dense() == 'False':
            print(
                'WARNING: lba matrix is not the correct dimensions or matrix type'
            )
        if uba.size1() != (neq + niq) or (uba.size2() !=
                                          1) or uba.is_dense() == 'False':
            print(
                'WARNING: uba matrix is not the correct dimensions or matrix type'
            )

        #Evaluating QP matrices at optimal points
        H_opt = H_fun(x_init, p_init, lam_opt, mu_opt)
        g_opt = g_fun(x_init, p_init)
        A_opt = A_fun(x_init, p_init)
        lba_opt = lba_fun(x_init, p_init)
        uba_opt = uba_fun(x_init, p_init)

        #        print 'Lower bounds', lba_opt
        #        print 'Upper bounds', uba_opt
        #        print 'Bound matrix', A_opt

        #Defining QP structure
        qp = {}
        qp['h'] = H_opt.sparsity()
        qp['a'] = A_opt.sparsity()
        optimize = conic('optimize', 'qpoases', qp)
        optimal = optimize(h=H_opt,
                           g=g_opt,
                           a=A_opt,
                           lba=lba_opt,
                           uba=uba_opt,
                           x0=x_init)
        x_qpopt = optimal['x']
        if x_qpopt.shape == x_init.shape:
            qp_exit = 'optimal'
        else:
            qp_exit = ''
        lag_qpopt = optimal['lam_a']

        #Determing Lagrangian multipliers (lambda and mu)
        lam_qpopt = zeros(
            (nk_pt, 1))  #Lagrange multiplier of active constraints
        mu_qpopt = zeros(
            (nk_zt, 1))  #Lagrange multiplier of inactive constraints
        if nk_pt > 0:
            for j in range(0, len(k_plus_tilde)):
                lam_qpopt[j] = lag_qpopt[int(k_plus_tilde[j])]
        if nk_zt > 0:
            for k in range(0, len(k_zero_tilde)):
                print lag_qpopt[int(k_zero_tilde[k])]
        return qp_exit, optimal, x_qpopt, lam_qpopt, mu_qpopt