qpOASES使用说明

  • 1 说明
  • 2 主要步骤
  • 创建QProblem类的实例
  • 第一个QP的初始化和求解
  • 求解后续QP
  • 一个实列
  • 设置自己的实例



本文将在几分钟内向您解释如何通过qpOASES解决二次规划(QP)问题或整个序列问题。 最后,提供了一个教程示例,可以作为您自己的QP的模板。

1 说明

qpOASES的核心是QProblem类,它能够使用在线有效集策略存储、处理和解决凸二次规划;它使用了几个辅助类。 除特殊情况外,QProblem类是qpOASES功能的唯一用户接口。

为了解决一系列具有固定Hessian和约束矩阵的凸二次规划,需要采取以下步骤:

  1. 创建QProblem类的实例。
  2. 初始化QProblem对象并求解第一个QP(由其QP矩阵(matrices)和向量(vectors)指定)。
  3. 再将向量传递给QProblem对象来解决每个后续QP。

现在,我们将更详细地解释这三个步骤。 在后面的章节中将介绍各种变体和特殊情况,以便于演示。

2 主要步骤

创建QProblem类的实例

通过以下构造函数创建QProblem对象

QProblem( int_t nV, int_t nC );

通过构造函数,可获得二次规划的变量数nV和约束数nC。 目前,还不能解决具有变化维度的QP序列。
第一步概述:可以使用命令创建QProblem类的实例示例:QProblem example( nV,nC )

第一个QP的初始化和求解

第二步需要初始化QProblem对象的所有内部数据结构和序列中第一个QP的求解。 只需调用以下函数即可满足这两个要求:

returnValue init( const real_t* const H,
const real_t* const g,
const real_t* const A,
const real_t* const lb,
const real_t* const ub,
const real_t* const lbA,
const real_t* const ubA,
int_t& nWSR,
real_t* const cputime
);

其中,QPieSeries用法 qmap erase的用法_QPieSeries用法是(半)正定矩阵,且QPieSeries用法 qmap erase的用法_工作集_02;梯度向量QPieSeries用法 qmap erase的用法_QPieSeries用法_03,约束矩阵QPieSeries用法 qmap erase的用法_初始化_04,自变量的下边界和上边界向量QPieSeries用法 qmap erase的用法_初始化_05,约束的下边界和上边界向量为QPieSeries用法 qmap erase的用法_QPieSeries用法_06。等式约束是将上、下(约束)边界向量的相应条目设置为相同的值。
所有这些数据必须存储在具有适当尺寸的real_t类型的数组中(按行存储的矩阵,在一维数组中,C风格)。

  • 例如,如果QP公式中没有上边界,则可以传递空指针而不是向量lb1。
  • 所有init函数都会对所有向量参数进行深拷贝(deep copy),因此您必须自己释放内存
  • 矩阵参数H和A不会被深拷贝,因此连续调用qpOASES时不能更改它们

函数init初始化所有内部数据结构。例如,矩阵因子分解,并使用在线有效集策略的初始同伦思想解决第一个二次规划。

整数参数nWSR指定在初始同伦期间要执行的最大工作集重新计算次数(在输出时它包含实际执行的工作集重新计算的次数!)。
如果cputime不是空指针,则它包含整个初始化的最大允许CPU时间(以秒为单位)(以及输出时实际需要的CPU时间)。

函数init会返回一个状态代码(类型为returnValue),表示初始化是否成功。可能的值是:
SUCCESSFUL_RETURN :初始化成功(包括第一个QP的求解)。
RET_MAX_NWSR_REACHED:在给定的工作集重新计算数量内无法解决初始QP。
RET_INIT_FAILED(或更详细的错误代码):初始化失败。
如果init返回SUCCESSFUL_RETURN,则可以通过多个函数获取有关第一个QP解决方案的信息。 其中,最重要的几个函数是:

returnValue getPrimalSolution( real t* const xOpt ) const
  • 将最优原始解向量(dimension:nV)写入数组xOpt,该数组必须由用户分配(和释放)
returnValue getDualSolution( real t* const yOpt ) const
  • 将最佳双解决方案向量(维度:nV + nC)写入数组yOpt,该数据必须由用户分配(和释放)
real t getObjVal( ) const

返回最优目标函数值。
第二步总结:创建了QProblem对象示例后,可以使用以下命令将其与第一个QP一起初始化:
example.init(H,g,A,lb,ub,lbA,ubA,nWSR,cputime)

求解后续QP

如果不是只有一个二次规划而是整个QP序列都要求解,这是MPC问题的通常情况,下一个QP可以用以下函数求解:

returnValue hotstart( const real_t* const g_new,
const real_t* const lb_new,
const real_t* const ub_new,
const real_t* const lbA_new,
const real_t* const ubA_new,
int_t& nWSR,
real_t* const cputime
);

通过传递其梯度向量g_new,其下限和上限向量lb_newub_new以及其约束的上、下边界向量lbA_newubA_new(假设QP矩阵是常数)来确定下一个QP。它通过在线有效集策略使用大多数nWSR工作集重新计算或大多数CPU时间的cputime秒(如果不为空)来求解。
在输出时,nWSRcputime分别包含实际执行的工作集重新计算的数量和求解下一个QP所需的实际CPU时间。
与大多数qpOASES函数一样,hotstart返回状态代码。可能的值是:
SUCCESSFUL_RETURN:QP已经求解成功。
RET_MAX_NWSR_REACHED:在给定数量的工作集重新计算中无法求解QP。
RET_HOTSTART_FAILED(或更详细的错误代码):QP求解失败。
第三步总结:创建并初始化一个Problem对象示例后,下一个QP可以如下方式求解:
example.hotstart(g new,lb new,ub new,lbA new,ubA new,nWLR,cpu time)

一个实列

文件 / example /example1.cpp中给出了使用qpOASES求解两个非常简单的二次规划的完整示例:

#include <qpOASES.hpp>
int main( )
{
USING_NAMESPACE_QPOASES
/* Setup data of first QP. */
real_t H[2*2] = { 1.0, 0.0, 0.0, 0.5 };
real_t A[1*2] = { 1.0, 1.0 };
real_t g[2] = { 1.5, 1.0 };
real_t lb[2] = { 0.5, -2.0 };
real_t ub[2] = { 5.0, 2.0 };
real_t lbA[1] = { -1.0 };
real_t ubA[1] = { 2.0 };
/* Setup data of second QP. */
real_t g_new[2] = { 1.0, 1.5 };
real_t lb_new[2] = { 0.0, -1.0 };
real_t ub_new[2] = { 5.0, -0.5 };
real_t lbA_new[1] = { -2.0 };
real_t ubA_new[1] = { 1.0 };
/* Setting up QProblem object. */
QProblem example( 2,1 );
/* Solve first QP. */
int_t nWSR = 10;
example.init( H,g,A,lb,ub,lbA,ubA, nWSR );
/* Solve second QP. */
nWSR = 10;
example.hotstart( g_new,lb_new,ub_new,lbA_new,ubA_new, nWSR );
/* Get and print solution of second QP. */
real_t xOpt[2];
example.getPrimalSolution( xOpt );
printf( "\n xOpt = [ %e, %e ]; objVal = %e\n\n",
xOpt[0],xOpt[1],example.getObjVal() );
return 0;
}

为了通过QProblem类访问qpOASES软件包的功能,需要包含头文件qpOASES.hpp

  • 首先,主函数定义了两个非常小规模的QP的数据。
  • 然后,创建一个QProblem对象,然后将其初始化并求解第一个QP。
  • 最后,使用hotstart函数用于求解第二个QP。

你可能想知道使用命名空间qpOASES的命令,它就在主函数的最开始。使用它是因为qpOASES软件包的所有类、全局函数和变量都收集在一个名为qpOASES的公共命名空间中

设置自己的实例

设置自己的示例的最简单方法,可以使用现有示例作为模板。进行此操作时,请执行以下步骤:
1.复制现有示例:

cd <install-dir>/examples
cp example1.cpp yourexample.cpp

2.编辑示例Makefile:
打开文件<install-dir> / example / Makefile并添加新目标

yourexample: yourexample.o
@$fECHOg "Creating" $@
@$fCPPg $fDEF TARGETg $fCPPFLAGSg $< $fQPOASES LINKg $fLINK LIBRARIESg
(Do not forget to add its name to the all target.)

3.实现你自己的例子:
修改文件<install -dir> /examples/yourexample.cpp并使用make指令。 名为<install-dir> / bin / yourexample的可执行文件就会出现。