最近在做论文的仿真,所有又跟cvx这个老兄弟见面了,不得不说真的是很怵,很是要静下心来细细的看代码、改错才行。遇到很多问题,今天记一个困扰了我两天的问题。
我文章中构建的目标函数中有这样一项
∑
i
=
1
M
∑
j
=
1
N
y
i
j
2
⋅
d
i
u
i
j
⋅
S
N
R
i
\sum_{i = 1}^M\sum_{j = 1}^N\frac{y_{ij}^2\cdot d_i}{u_{ij}\cdot SNR_i}
∑i=1M∑j=1Nuij⋅SNRiyij2⋅di。其中
y
i
j
y_{ij}
yij和
u
i
j
u_{ij}
uij是优化变量。
所以我接下来肯定就是把这一项写成目标函数了。
一开始我是这么写的
minimize sum(sum((y.^2./u)')'.*data_size./SNR_device)
结果一运行,很悲催,就报了标题里那个错误。
于是面向谷歌编程,找到了cvx forum这个论坛,里面有一个叫mark的大佬经常给大家解答问题,看了一圈下来,最扎心的几句话就是:你这个函数不是凸函数/你说是凸函数?那你证明给我看啊。看得我的心拔凉拔凉。不会我函数里这一项也表示不出来吧。
我想了一下可能是因为cvx不接受两个变量直接相乘吧(用mark大佬的话来说:你这个函数不能用cvx表示,那就是非凸的)。
于是我换了一下表示方式,决定把变量矩阵的每一个元素拆开相乘,像这样。
% temp和production1是定义的两个中间变量,用expression声明
temp = y(1,1)^2*inv_pos(u(1,1)); %不能对temp赋初值为0,所以把第一个计算值赋给它,后面再循环计算
for j = 2:n
temp = temp + y(1,j)^2*inv_pos(u(1,j));
end
production1 = temp*data_size(1)/SNR_device(1);
for i = 2:m
temp = y(i,1)^2*inv_pos(u(i,1));
for j = 2:n
temp = temp + y(i,j)^2*inv_pos(u(i,j));
end
production1 = production1 + temp*data_size(i)/SNR_device(i);
end
其实,应该能一眼看出来,即使换了一个表达方式,本质上也还是两个convex类型的变量相乘,所以依然报{convex} .* {convex}的错误。
这个时候想到逛论坛看到的一个帖子,问题的形式好像差不错,也是两个变量相除。
就是这个了:Cannot perform the operation: {convex} .* {convex}
mark大佬提到可以用quad_over_lin(X, Y)函数,这个函数等于SUM(ABS(X).^2)./Y,其中X是向量,Y是标量,我只能把希望寄予这个函数上。
%再尝试一次,下面这一部分是为了求任务从设备到无线节点的传输时间,用quad_over_lin代替除法,防止出现{convex}.*{convex}的错误
temp = quad_over_lin(y(1,1),u(1,1))*data_size(1)/SNR_device(1);
for j = 2:n
temp = temp + quad_over_lin(y(1,j),u(1,j))*data_size(1)/SNR_device(1);
end
production1 = temp;
for i = 2:m
temp = quad_over_lin(y(i,1),u(i,1))*data_size(i)/SNR_device(i);
for j = 2:n
temp = temp + quad_over_lin(y(i,j),u(i,j))*data_size(i)/SNR_device(i);
end
production1 = production1 + temp;
end
我试了一下,好在X是标量
的情况下,也是可以使用的,于是用上面那个循环累加的方法,把我函数中的这一项写出来了,运行之后这里也没有报错,看来是解决了{convex} .* {convex}这个错误了。
希望后面的仿真能够顺利啊,到年底的这几个月一定要咬牙坚持住,我可以的。
另,如果使用cvx包的过程中遇到问题,一定要先检查自己的函数是不是凸函数,另外多逛cvx forum,多看看别人踩过的坑,改进自己的代码。