Skip to content

3.Examples and Demos

Abhishek Pandala edited this page Dec 12, 2021 · 10 revisions

We use the following two quadratic programs as an example on each of the interfaces for the rest of the documentation.

Problem Setup - 1

The following problem shows a standard QP with both equality and inequality constraints image

The solution for the above QP is [0.833 −0.583 1.000]'

Problem Setup - 2

The following problem shows a standard QP with only inequality constraints image

The solution for the above QP is [0.450 −0.200 1.000]'

C/C++ Interface

C/C++ Interface via Sparse Matrices

The demo file for C/C++ interface via sparse matrices can be found in runqp.c. To interface with the qpSWIFT function, add the header file

#include "qpSWIFT.h"

qpSWIFT has three main functions, QP_SETUP, QP_SOLVE, and QP_CLEANUP. Initialize the QP struct with

QP* myQP

The basic algorithmic skeleton for qpSWIFT is as follows

QP *myQP;
myQP = QP_SETUP(n, m, p, Pjc, Pir, Ppr, Ajc, Air, Apr, Gjc, Gir, Gpr, c, h, b, 
                    sigma_d, Permut);
/* settings can be changed at this point */
qp_int ExitCode = QP_SOLVE(myQP);
/* solution and solution statistics can be accessed now */
QP_CLEANUP(myQP);

Initially, a pointer for the QP structure is defined. The data fields of the QP structure and the necessary memory are allocated using the first function QP_SETUP. Any custom settings, for example, the maximum number of iterations, can be set after invoking the QP_SETUP function. The second function QP_SOLVE computes the actual solution. At this stage, the solution is accessible using myQP->x. The third function QP_CLEANUP clears the entire setup. The description of the input arguments for each of the functions is provided below.

The first function, QP_SETUP, has the following input arguments

qp_int n        /* number of decision Variables */  
qp_int m        /* number of inequality constraints */  
qp_int p        /* number of equality constraints */
qp_int* Pjc     /* jc vector of P Matrix in CCS format */  
qp_int* Pir     /* ir vector of P Matrix in CCS format */  
qp_real* Ppr    /* pr vector of P Matrix in CCS format */  
qp_int* Ajc     /* jc vector of A Matrix in CCS format */  
qp_int* Air     /* ir vector of A Matrix in CCS format */  
qp_real* Apr    /* pr vector of A Matrix in CCS format */  
qp_int* Gjc     /* jc vector of G Matrix in CCS format */  
qp_int* Gir     /* ir vector of G Matrix in CCS format */  
qp_real* Gpr    /* pr vector of G Matrix in CCS format */  
qp_real* c      /* cost function vector */  
qp_real* h      /* inequality constraints vector */  
qp_real* b      /* equality constraints vector */
qp_int sigma_d  /* desired sigma*/
qp_int Permut   /* permutation vector of KKT Matrix */

Here, qpSWIFT accepts matrices in Compressed Column Storage format. sigma_d is set to zero. The last argument, Permut, refers to the permutation matrix of the KKT matrix. This can be set to NULL if you want to use the inbuilt AMD routines to compute the permutation matrix. More info regarding CCS format and Permutation matrices can be found in Appendix. If there are no equality constraints in the QP problem, then set the arguments Ajc, Air, Apr, b to a NULL pointer and the number of equality constraints as p = 0. After invoking this function, the solver settings for the QP can now be changed using

myQP->settings->maxit   /* Maximum number of Iterations of QP */
myQP->settings->reltol  /* Relative Tolerance */
myQP->settings->abstol  /* Absolute Tolerance */
myQP->settings->sigma   /* sigma desired */
myQP->settings->verbose /* Verbose Levels || 0 :: No Print */
                        /*                || >0 :: Print Everything */

The default for these settings can be found in GlobalOptions.h. The function QP_SOLVE performs the actual solution

Exit_Code = QP_SOLVE(myQP)

The Exit_Code has the exit flag of the qpSWIFT. The following flags are set for ExitCode

QP_OPTIMAL (0)  /* optimal solution found */
QP_KKTFAIL (1)  /* failure in solving LDL' factorization */
QP_MAXIT (2)    /* maximum number of iterations exceeded */
QP_FATAL (3)    /* unknown problem in solver */

The solution can be accessed via the pointer

myQP->x         /* Primal Solution a.k.a solution of the QP */
myQP->y         /* Dual Solution of the QP (equality constraints) */
myQP->z         /* Dual Solution of the QP (inequality constraints) */
myQP->s         /* Slack Variables of the QP */

The statistics of the solution can be accessed via myQP->stats pointer and has the following fields

/* Time Statistics */
tsetup          /* Setup time ; includes initialisation as well */
tsolve          /* QP solve time */
kkt_time        /* kkt matrix inversion time */
ldl_numeric     /* kkt matrix factorization time */
/* Time Statistics */

/* Algorithmic Statistics */
IterationCount  /* iteration Count */
n_rx            /* norm of residual vector rx */
n_ry            /* norm of residual vector ry */
n_rz            /* norm of residual vector rz */
n_mu            /* complementary Slackness (s'z/m) */

alpha_p         /* primal step Size */
alpha_d         /* dual step Size  */
/* Algorithmic Statistics */

fval            /* function Value */
Flag            /* solver FLAG */
AMD_RESULT      /* AMD Compilation Result */
                    /* >=0 means successful  */
                    /* <0 means unsuccessful  */
                    /* -3 means unused */

The last function to call is QP_CLEANUP.

QP_CLEANUP(myQP)

This function clears all the memory created by QP_SETUP. Please note that this function needs to be called after copying the QP solution and relevant statistics.

C/C++ Interface via Dense Matrices

Demo file for C++ interface can be found at runqpcpp.cpp. The dense interface is also similar to the sparse interface. To interface with the dense interface, add the header file

#include "qpSWIFT.h"

The algorithmic skeleton for qpSWIFT dense interface is as follows

QP *myQP;
myQP = QP_SETUP_dense(n, m, p, P, A, G, c, h, b, Permut, COLUMN_MAJOR_ORDERING);
/* settings can be changed now */
qp_int ExitCode = QP_SOLVE(myQP);
/* solution and solution statistics can be accessed now */
QP_CLEANUP_dense(myQP);

First the QP struct pointer is created as

QP* myQP;

The solver can be interfaced via the same three functions, the same way as the sparse interface or can be done via a dense interface using QP_SETUP_dense function. Initially, a pointer for the QP structure is defined. The data fields of the QP structure and the necessary memory are allocated using the first function QP_SETUP_dense. Any custom settings, for example, the maximum number of iterations, can be set after invoking the QP_SETUP_dense function. The second function QP_SOLVE computes the actual solution. At this stage, the solution is accessible using myQP->x. The third function QP_CLEANUP_dense clears the entire setup. The description of the input arguments for each of the functions is provided below.

qp_int n        /* Number of decision Variables */  
qp_int m        /* Number of inequality constraints */  
qp_int p        /* Number of equality constraints */
qp_real *P      /* data pointer of P Matrix */  
qp_real *G      /* data pointer of G Matrix */ 
qp_real *A      /* data pointer of A Matrix */  
qp_real *c      /* cost function vector */  
qp_real *h      /* inequality constraints vector */  
qp_real *b      /* equality constraints vector */
qp_int Permut   /* Permutation vector of KKT Matrix */
qp_int ordering /* Indicates row major or column major ordering of P,A,G matrices*/
                    /* ROW_MAJOR_ORDERING - row major indexing of matrices */
                    /* COLUMN_MAJOR_ORDERING - column major indexing of matrices */

Note that all the matrices P, A, and G must be in contiguous blocks of memory and must be in either row-major or column-major ordering. If there are no equality constraints, set the A matrix and b vector to NULL pointer and the number of equality constraints p to be 0. The argument Permut refers to the permutation matrix of the KKT matrix. This can be set to NULL if you want to use the inbuilt AMD routines to compute the permutation matrix. More info regarding CCS format and Permutation matrices can be found in Appendix. After invoking this function, the solver settings for the QP can now be changed using

myQP->settings->maxit   /* Maximum number of Iterations of QP */
myQP->settings->reltol  /* Relative Tolerance */
myQP->settings->abstol  /* Absolute Tolerance */
myQP->settings->sigma   /* sigma desired */
myQP->settings->verbose /* Verbose Levels || 0 :: No Print */
                        /*                || >0 :: Print Everything */

The default for these settings can be found in GlobalOptions.h. The function QP_SOLVE performs the actual solution

Exit_Code = QP_SOLVE(myQP)

The Exit_Code has the exit flag of the qpSWIFT. The following flags are set for ExitCode

QP_OPTIMAL (0)  /* optimal solution found */
QP_KKTFAIL (1)  /* failure in solving LDL' factorization */
QP_MAXIT (2)    /* maximum number of iterations exceeded */
QP_FATAL (3)    /* unknown problem in solver */

The solution can be accessed via the pointer

myQP->x         /* Primal Solution a.k.a solution of the QP */
myQP->y         /* Dual Solution of the QP (equality constraints) */
myQP->z         /* Dual Solution of the QP (inequality constraints) */
myQP->s         /* Slack Variables of the QP */

The statistics of the solution can be accessed via myQP->stats pointer and has the following fields

/* Time Statistics */
tsetup          /* Setup time ; includes initialisation as well */
tsolve          /* QP solve time */
kkt_time        /* kkt matrix inversion time */
ldl_numeric     /* kkt matrix factorization time */
/* Time Statistics */

/* Algorithmic Statistics */
IterationCount  /* iteration Count */
n_rx            /* norm of residual vector rx */
n_ry            /* norm of residual vector ry */
n_rz            /* norm of residual vector rz */
n_mu            /* complementary Slackness (s'z/m) */

alpha_p         /* primal step Size */
alpha_d         /* dual step Size  */
/* Algorithmic Statistics */

fval            /* function Value */
Flag            /* solver FLAG */
AMD_RESULT      /* AMD Compilation Result */
                    /* >=0 means successful  */
                    /* <0 means unsuccessful  */
                    /* -3 means unused */

The last function to call is QP_CLEANUP_dense.

QP_CLEANUP_dense(myQP)

This function clears all the memory created by QP_SETUP_dense. Please note that this function needs to be called after copying the QP solution and relevant statistics.

Interface with Eigen

qpSWIFT can be interfaced with Eigen via the dense matrix interface. Assuming that the matrices P, A, G and the vectors c, h, b are Eigen matrices, we can invoke qpSWIFT via

myQP = QP_SETUP_dense(P.rows(),A.rows().G.rows(),P.data(),G.data(),A.data(),...
                          c.data(),h.data(),b.data(),NULL,COLUMN_MAJOR_ORDERING);

The rest of the steps are similar to the dense interface.

Matlab Interface

Demo file can be found at demoqp.m. To use qpSWIFT for general quadratic program of the form

+

type the following commands

[sol,basic_info,adv_info] = qpSWIFT(sparse(P),c,sparse(A),b,sparse(G),h)

or

[sol,basic_info,adv_info] = qpSWIFT(sparse(P),c,sparse(A),b,sparse(G),h,opts)

For inequality only quadratic program of the form

+

the syntax is as follows

[sol,basic_info,adv_info] = qpSWIFT(sparse(P),c,sparse(G),h)

or

[sol,basic_info,adv_info] = qpSWIFT(sparse(P),c,sparse(G),h,opts)

The input arguments and their description is given below

P is a sparse matrix of dimension (n,n)
c is a dense column vector of size n
A is a sparse matrix of size (p,n); p is the number of equality constraints
b is a dense column vector of size p
G is a sparse matrix of size (m,n); m is the number of inequality constraints
h is a dense column vector of size m
opts is a structure with the following fields
-> MAXITER : maximum number of iterations needed
-> ABSTOL : absolute tolerance
-> RELTOL : relative tolerance
-> SIGMA : maximum centering allowed
-> VERBOSE : print levels || 0 -- no print
                          || >0 -- print everything
-> Permut : permutation vector obtained as
            KKT = [P A' G';
            A 0 0;
            G 0 -I];
            Permut = amd(KKT);

Note that opts is not mandatory and all fields of opts are also not mandatory. All input matrices must be sparse. The output arguments have the following description

sol represents the primal solution of the QP

basic_info has four fields
    -> Exit Flag : 0 : optimal solution found
                 : 1 : failure in factorising KKT matrix
                 : 2 : maximum number of iterations reached
                 : 3 : unknown problem in solver
    -> Iterations : number of iterations
    -> Setup Time : involves setting up QP; solving for the initial guess
    -> Solve Time : solution time
adv_info has five fields
    -> Fval : objective value of the QP
    -> KKT_Time : time needed to solve the KKT system of equations
    -> LDL_Time : time needed to perform LDL' factorization
    -> y : dual variables corresponding to equality constraints
    -> z : dual variables corresponding to inequality constraints
    -> s : primal slack variables

Python Interface

Demo file can be found at demoqp.py. To run qpSWIFT in your python script

import qpSWIFT as qp
res = qp.run(c,h,P,G,A,b,opts)

The last three arguments A, b, opts are optional. The input arguments and their description is as follows

P is a numpy matrix of dimension (n,n)
c is a numpy column vector of size n
A is a numpy matrix of size (p,n); p is the number of equality constraints
b is a numpy column vector of size p
G is a numpy matrix of size (m,n); m is the number of inequality constraints
h is a numpy column vector of size m
opts is a dictionary with the following keys
        -> MAXITER : maximum number of iterations needed
        -> ABSTOL  : absolute tolerance
        -> RELTOL  : relative tolerance
        -> SIGMA   : maximum centering allowed
        -> VERBOSE : PRINT LEVELS  ||  0   -- No Print
                                   || >0   -- Print everything
        -> OUTPUT  : OUTPUT LEVELS ||  1   -- sol + basicInfo
                                   ||  2   -- sol + basicInfo + advInfo
                                   ||  otherwise   -- sol  

opts is not mandatory and all fields of opts are also not mandatory. The output arguments and their description is as follows

res represents a dictionary class with the following key-value pairs

* [sol] : Basic Solution represented as numpy vector

* [basic_info] : Dictionary class with four key-value pairs
       -> Exit Flag : 0 : Optimal Solution Found
                    : 1 : Failure in factorizing KKT matrix
                    : 2 : Maximum Number of Iterations Reached
                    : 3 : Unknown Problem in Solver
       -> Iterations : Number of Iterations
       -> Setup Time : Involves setting up QP; solving for the initial guess
       -> Solve Time : Solution Time

* [adv_info] : Dictionary class with five key-value pairs
       -> Fval : Objective Value of the QP
       -> KKT_Time : Time needed to solve the KKT system of equations
       -> LDL_Time : Time needed to perform LDL' factorization
       -> y : Dual Variables
       -> z : Dual Variables
       -> s : Primal Slack Variables

Simulink Interface

The demo simulink models can be found at demoqp_e.slx and demoqp.slx. Input to the s-function can be changed by modifying the vectors in_P, c, in_G and, h in the matlab function InputData of the demoqp.slx model . Similar changes can be made to demoqp_e.slx file. There are five outputs to each of the simulink s-function which are as follows

   solution   /* Solution of QP; dimension is set in s-function (line 13) */
   exitflag   /*  : 0 : optimal solution found 
                  : 1 : failure in factorizing KKT matrix 
                  : 2 : maximum number of iterations reached 
                  : 3 : unknown problem in solver */
   iterations /* number of iterations */
   setuptime  /* setup time */
   solvetime  /* solution time */

Please note the following points while using the simulink interface.

  • Inputs to the simulink s-functions must be vectors of appropriate dimensions. The matrices must be in column-major ordering.
  • The solution vector of the QP is set to 3-dimensions (by default). To get the complete solution of QP, change the pre-processor definition #define NV to desired value before compiling the s-function
  • To use the simulink function in SLRT framework, add all the source files found in src/ to the Configuration Parameters > Simulation Target > Custom Code > Source file block in the simulink model file. Similarly, add the header file directory include/ to the Configuration Parameters > Simulation Target > Custom Code > Header file block
  • The settings of the QP can be changed in the simulink s-function lines (142-152). Necessary details are found in the comments of the respective s-function files.

Clone this wiki locally