提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
近期在使用MATLAB cvx进行优化问题求解的过程中遇到了各种各样的问题,bug不断,明明看起来很合理的表达式却一再报错,最终经过一个多月的调试终于将优化问题求解了出来。
在调试期间,用到了很多方法,例如问题和约束条件的转化,非凸转化为近似凸,查阅资料,改变公式写法等等手段,本文记录一下编程过程中遇到的错误、bug,希望能够帮到有相同问题的秃友们。
如果是cvx初学者,想要掌握一般cvx语法和编程方法,可以看这篇文章:
MATLAB中CVX工具箱解决凸优化问题的基本知识——语法、变量声明、目标函数、约束条件、cvx编程错误及解决方法
CVX工具箱中有很多特定的,专有的函数,这些函数不仅能够简化表达式,还能够通过函数替换来解决很多报错问题,例如除法、取倒数、对数㏒函数等都有专门函数替代,下面这篇文章总结了cvx中常用的函数,阅读这篇文章一定会对你产生帮助!
MATLAB cvx工具箱中常用的替换函数汇总,解决表达式报错问题
错误原因:
如果变量声明是在cvx框架之外(cvx_begin-cvx_end之外),那么cvx运行过程中会产生数据从cvx类型存到double(外面是double的)的过程。必须要将中间变量在cvx表达式里面进行定义。
具体来说,cvx中的variable类型是其特有的数据类型,也就是你的优化变量是cvx类型,如果你想要让你的cvx优化变量和其他已定义好的double数据进行数学运算,就必须提前声明表达式类型的变量来接受这个操作。
解决方法:
例如:a是cvx之外的double类型,b是cvx中的variable变量,如果想要在cvx中实现ab,那么必须定义表达式expression类型的变量来接收ab的值。
错误代码:
b = rand(3,2);
cvx_begin
variable a;
variable c; %c为variable变量
c = a * b; %因为c是variable变量,所以进行该操作会出现错误
minimize f(x)
subject to
a <= 10;
cvx_end
将上述代码中的variable c;修改为expression c;即可得到正确代码。
正确代码:
b = rand(3,2);
cvx_begin
variable a;
expression c; %c为variable变量
c = a * b; %因为c是variable变量,所以进行该操作会出现错误
minimize f(x)
subject to
a <= 10;
cvx_end
知识点总结:cvx中variable和expression的区别
在CVX软件包中,Variable(变量)和Expression(表达式)是CVX变量声明中最基本的两种类型。
Variable是可以优化的变量,可以看做是一个容器,存储着优化过程中待求解的变量。在声明一个Variable时,需要指定其形状、是否为实数、是否为非负数等属性,这样可以方便地控制变量的取值范围和优化方法的选择。Variable在最优化问题中具有待求解的性质,它在CVX中被定义为待优化的对象。
Expression用来指定变量之间的约束关系,也可以理解为一个可以计算的数学表达式。Expression可以由variable和基本的算术操作、点乘、矩阵乘法、原子函数等运算通过组合得到,可以是定值或是与Variable相关的表达式。
Variable一般是问题中的未知量,需要被求解出来,而Expression通常是已知的、确定的。由于Expression不需要求解,所以CVX对其进行符号相关的运算和简化等,有助于提高数值计算的效率。也就是把Expression作为一个中间变量,最终cvx不会保存Expression的计算结果。
报错提示:
This is often an indication that an equality constraint was written with one equals ‘=’ instead of two ‘==’. The model must be rewritten before cvx can proceed.
错误原因:
cvx中的variable变量不是允许人为赋值的,只有在最后得出结果才会被结果覆盖,使用等号对某一个变量进行赋值是不允许的,cvx会动态优化变量,不允许人为复制。
解决方法:
使用expression声明临时变量,expression变量是可以使用“=”的。
// 声明临时变量
cvx_begin
variable a; %优化变量,不可以赋值修改,可以用双等号==来写约束条件
expression b; %临时变量,可以用等号=来赋值修改
minimize(f(x));
subject to
a == 0; %约束条件,a必须等于零
b = 10; %给b赋值为10,优化结束后自动清除
cvx_end
报错提示:
Disciplined convex programming error:
Cannot perform the operation: {real affine} .* {invalid}
不能进行下面操作:仿射*无效
错误原因:
变量中存在无效数据,例如正负无穷+Inf、-Inf,空数据NaN,或者是0。
解决方法:
查看那个变量中的数据是无效的,修改该变量的值,或者调整初始化参数,或者检查哪一步运算出现了无效数据,修改该语句,进而消除无效数据。
报错提示:
点除运算出现错误,出错 ./ (line 29)
错误原因:
cvx中的除法很容易出现问题,有时候你认为很正常的除法操作,但是cvx中就是会出错,因此cvx中有专有的针对除法操作的函数,inv_pos()。
解决方法:
例如: x ./ y报错
用inv_pos(y)来代替y,上式修改为x * inv_pos(y)
cvx_begin
variable a;
variable b; %c为variable变量
minimize (a * inv_pos(b)) %不要用a/b
subject to
a <= 10;
cvx_end
知识点总结:cvx中inv_pos函数
在CVX中,inv_pos(x)是一个原子函数,用于求一个正数x的倒数,即1/x。但是,在定义该函数的时候,需要加上一个前缀“inv_pos”来表示参数x必须是正数,否则会产生未定义的结果。
在优化问题中,经常需要对矩阵或向量的逆进行求解。但是,如果涉及到非正定或奇异矩阵,逆运算是无法进行的。因此,为了确保矩阵或向量是正定的,可以使用CVX中的inv_pos函数,它会自动判断变量的正定性并求解其逆。当变量不是正定的时候,inv_pos函数会返回inf(无穷大)或NaN(非数值)。
例如,在求解下面的凸优化问题的时候:
cvx_begin
variable x
minimize(inv_pos(x) - 1)
subject to
x >= 0.5;
cvx_end
上面这个问题要求求解一个变量x,使得1/x最小,且x要大于等于0.5。在这个例子中,因为我们使用了inv_pos函数,所以x必须是正数,否则会出现一个错误。最后,CVX将求解出一个正数x,使得1/x最小。
报错提示:
错误使用 cvx/log (line 64)
Disciplined convex programming error:
Illegal operation: log( {convex} ).
错误原因:
cvx中是不允许出现log函数中出现凸函数的,即log(凸)是非法的,cvx中有专门针对log运算的函数,即rel_entr
解决方法:
使用rel_entr表示log函数
rel_entr(x,y) = xlog(x/y)
当你知道了上述表达式表示的含义后,你可以将你的log表达式进行变形,然后使用多个rel_entr
函数的组合来表示的想要表达的式子。
例如:wlog(1+p/w),借助数学公式log(1/x)=-log(x),可得表达式:
wlog(1+p/w) = -rel_entr(w,w+p),注意负号
%想要计算log(1+1/x)
a = rel_entr(x+1,x)+rel_entr(x,x+1);
知识点总结:cvx中rel_entr函数
在CVX中,rel_entr(x, y)是一个原子函数,表示 KL 散度的一部分,即 x log(x/y)。其中,x和y具有相同的尺寸和形状,元素之间进行逐项计算。
rel_entr函数的第一个参数 x 可以是任何非负实数或实数向量(或矩阵),而第二个参数 y 也是非负实数或实数向量(或矩阵),并且 y 中不能存在 0 的项。当 x 和 y 相等时,rel_entr(x, y)的值是 0。在CVX问题中,rel_entr(x, y)通常用在求解最大熵问题、信息论问题、对数几率回归等一些特殊问题。
代码示例:
cvx_begin
variable x(n);
maximize(sum(rel_entr(x, p)));
subject to
sum(x) == 1;
x >= 0;
cvx_end
其中,x 是一个 n 维列向量,p 也是一个相同尺寸和形状的列向量,CVX会自动将所有元素之间的操作转换成相应的 KL散度公式。在这个例子中,CVX将每个 x(i) 和 p(i) 进行逐项相除,然后计算 KL 散度公式的一部分并相加,从而求解满足约束条件的最大化x的问题。
报错提示:
Disciplined convex programming error:
Illegal operation: {invalid} + {convex}
错误原因:
无效数据与凸表达式相加,错误原因及处理方法与错误3类似,不再赘述。
报错提示:
Disciplined convex programming error:
Cannot perform the operation: {positive constant} ./ {real affine}
错误原因:
正实数除以仿射函数,很明显该表达式是一个非凸的,cvx作为一个凸优化工具箱是无法解决非凸问题的。
解决方法:
将表达式转化为凸表达式,重新转化约束条件或目标函数。不再使用cvx工具箱,使用其他求解优化问题的工具箱,例如Gurobi、CPLEX等。
上面总结了几个cvx编程中常见的错误,能力有限,不一定能准确解决各位遇到的现实问题,cvx编程看起来简单,实际上水很深,希望大家不要放弃,掌握好编程技巧,一起进步,祝各位的论文仿真早日成功!
如果是cvx初学者,想要掌握一般cvx语法和编程方法,可以看这篇文章:
MATLAB中CVX工具箱解决凸优化问题的基本知识——语法、变量声明、目标函数、约束条件、cvx编程错误及解决方法
CVX工具箱中有很多特定的,专有的函数,这些函数不仅能够简化表达式,还能够通过函数替换来解决很多报错问题,例如除法、取倒数、对数㏒函数等都有专门函数替代,下面这篇文章总结了cvx中常用的函数,阅读这篇文章一定会对你产生帮助!
MATLAB cvx工具箱中常用的替换函数汇总,解决表达式报错问题
如果是对MATLAB基础操作,尤其是涉及到矩阵操作、逻辑运算、数组生成等方面不是很熟悉的,可以参考下面这篇文章:
MATLAB基础操作,矩阵乘法、数组矩阵索引、最大最小运算符、零矩阵/随机矩阵/单位矩阵的生成、log函数、Inf和NaN的含义,语句过长用连接符换行、逻辑运算符以及区别
如果程序调试成功需要画结果图,但是对MATLAB画图的基本知识和语法搞不清楚的,可以参考下面这篇文章:
MATLAB绘图必看,画图大全!MATLAB绘图基础操作大全—折线图、散点图、颜色样式、线条粗细汇总