CVX中涉及log、exp、熵的函数都是使用的连续逼近方法来近似原函数,这种逼近慢且精度不高,可能会导致结果出现failed、Inaccurate等情况,导致结果不准确,甚至出现Nan,CVX本身也会出现warning
CVXQUAD是基于CVX的一个函数集,其采用更好的Pade Approximation方法,用CVXQUAD中提供的函数来替代对数、指数函数,可以达到更高精度。
CVXQUAD的安装可以直接参考以下帖子
https://blog.csdn.net/fighting5/article/details/114780233
下面具体介绍如何用CVXQUAD中的函数来替换log和exp函数
对于log函数,使用rel_entr_quad函数来近似,比如,对于形如log(f(x))的函数,其中f(x)为关于x的一个凹函数,可以引入松弛变量t,来代替原本的f(x),具体来说:
首先,把原本的log(f(x))替换成-rel_entr_quad(1, t)
然后,加入新的约束:t<=f(x)
这样就可以了(如果f(x)本身是仿射函数,那么不用加入新变量t,直接使用-rel_entr_quad(1, f(x))就行),举个具体的例子,假如有下面这个优化问题:
直接使用CVX求解,代码为
cvx_begin
variables x1 x2
maximize log(x1)+x2
subject to
x1+x2<=log(log(x2))+10;
x2>=1;
cvx_end
使用 rel_entr_quad函数来近似log函数(当然上面问题很简单,使用原本的代码就可以获得精确解,这里只是举个例子),代码如下
cvx_begin
variables x1 x2 t2
maximize -rel_entr_quad(1,x1)+x2
subject to
x1+x2<=-rel_entr_quad(1, t2)+10;
t2<=-rel_entr_quad(1,x2)
cvx_end
其中倒数第二行等价于t2<=log(x2)
在matlab中运行两段代码的结果是一样的。
对于exp函数,我们利用CVXQUAD中的指数锥exponential来替换,具体地说对形如exp(g(x))的函数,其中g(x)为凸函数,类似地,引入新变量r、q
首先把原本的exp(g(x))替换为r
然后加入新的约束:q>=g(x)以及{q,1,r}==exponential(1)就可以了
如果g(x)为仿射函数,则不需要引入q
同样举个例子,考虑下面的优化问题
直接使用cvx求解,代码是这样的
cvx_begin
variables x1 x2
minimize exp(x1^2)+exp(x2)
subject to
x1+x2<=10;
x1+x2>=0;
cvx_end
用 CVXQUAD中的函数代替,代码如下
cvx_begin
variables x1 x2 r1 q1 r2
minimize r1+r2
subject to
q1>=x1^2
{q1,1,r1}==exponential(1)
{x2,1,r2}==exponential(1)
x1+x2<=10;
x1+x2>=0;
cvx_end
同样,这两段代码的结果相同。