c++中有二次型编程库吗?

Is there a quadratic programming library in C++?

本文关键字:编程 二次 c++      更新时间:2023-10-16

我找到的唯一Google搜索结果是quadprog++,但它不能解决二次规划问题,其矩阵不适用于Cholesky分解。

那么谁能给我一些关于其他图书馆的建议?谢谢。

CGAL看起来很适合二次规划。甚至还有手册

  // by default, we have a nonnegative QP with Ax <= b
  Program qp (CGAL::SMALLER, true, 0, false, 0); 
  // now set the non-default entries: 
  const int X = 0; 
  const int Y = 1;
  qp.set_a(X, 0,  1); qp.set_a(Y, 0, 1); qp.set_b(0, 7);  //  x + y  <= 7
  qp.set_a(X, 1, -1); qp.set_a(Y, 1, 2); qp.set_b(1, 4);  // -x + 2y <= 4
  qp.set_u(Y, true, 4);                                   //       y <= 4
  qp.set_d(X, X, 2); qp.set_d (Y, Y, 8); // !!specify 2D!!    x^2 + 4 y^2
  qp.set_c(Y, -32);                                       // -32y
  qp.set_c0(64);                                          // +64
  // solve the program, using ET as the exact type
  Solution s = CGAL::solve_quadratic_program(qp, ET());
  assert (s.solves_quadratic_program(qp));

第一个例子中的代码

LAPACK有许多Cholesky分解例程(他们称之为Cholesky分解)。有一些c++包装器可用于LAPACK(参见这个问题的列表)。

Anycom在那篇文章中的回答有点神秘,但他的意思是有LAPACK绑定可以与Boost的线性代数库uBLAS一起使用。


我找到了这个库:OOQP(面向对象的二次规划软件)。如果你向下滚动那一页,你会发现一篇研究论文和一份用户指南。这个库似乎有一个c++ API。

有几个库包含QP求解器。有开源和商业两种选择。现有的答案列出了其中的一些。我想把矩阵的问题弄清楚。

我假设你指的是客观矩阵。约束矩阵只需要导致一个非空可行集。你提到矩阵不适合Cholesky分解。由于Cholesky分解可以对任何正定矩阵形成,这意味着你的矩阵不是正定的。

如果矩阵是正半定的(即它有一个或多个零特征值),则问题是一个凸QP,可以有效地求解。然而,许多解决方案需要一个积极明确的目标。由于正半定QP的目标具有非平凡的零空间,因此可能有许多解。事实上,解的集合甚至可以无界。无论如何,数值算法只能给出近似解,所以矩阵的特征值恰好为零并不重要。你可以通过在对角线上添加一个小正值的对角线矩阵来使矩阵正定。它会选择最小2范数的解。在实践中,即使矩阵是正定的,这样做也是一个好主意,因为特征值接近于零的矩阵通常会给数值求解器带来问题。添加多少对角线是在稳定性和精度之间的权衡。

如果矩阵是不定的(即它甚至有一个负特征值),那么问题是np困难的。这意味着任何基于当前可用算法的代码,即使对于中等规模的问题,也会有不合理的最坏情况运行时间。如果你的问题有一些特殊的结构或者你不需要一个全局最优解那么你就可以了。一个典型的方法是寻找一个凸松弛。

上面的许多答案都忽略了一个微妙的问题:这个矩阵是仅仅是正半确定的(PSD)还是实际上是不确定的。我没有使用过quadprog,但如果它在PSD目标矩阵上失败,那就是软件缺乏鲁棒性的标志(凸qp通常是PSD,其中只有严格凸 qp是正定的)。根据Golub的《矩阵计算》一书,Cholesky分解可以应用于PSD矩阵,但数值稳定性往往会受到影响。

对于一般的非线性编程软件——包括凸的和非凸的,COIN-OR项目维护自由和非自由软件的列表。他们列出的解决方案之一是IPOPT,它当然能够解决您的问题。IPOPT使用内点算法,对于小问题,该算法通常比活动集方法(如quadprog使用)慢。作为替代方案,您可以将QP表述为线性互补问题(LCP),然后使用LCP求解器对其进行求解。我发现Fackler和Miranda的Matlab代码LEMKE很容易移植到c++。

如果你愿意支付,你可以使用Mosek。不过有一个30天的免费试用。它通常被认为是可用的最快的求解器(没有引用,抱歉)。接口是C风格的,尽管显然可以完美地从c++调用。Mosek实际上是一个二次规划求解器,但如果你不想将你的问题重新定义为一个二次问题(Mosek有很多关于如何做到这一点的文档),你仍然可以使用它的随机梯度下降求解器来解决你的二次公式。