YALMIP学习(一):入门

目录

  • 前言
  • 代码总览
  • YALMIP符号变量
  • 约束条件

前言

  最近在学习YALMIP,跟着官网的Tutorials一步一个脚印地前进着。写的这些关于YALMIP学习的系列文章也都是我从官网翻译过来的,算是给自己的笔记吧。
  官网Tutorials链接在此:https://yalmip.github.io/tutorials/.
  本文所翻译的Getting started原文链接在此:https://yalmip.github.io/tutorial/basics/.

代码总览

  下文代码基本涵盖了关于YALMIP我们需要学习的所有内容,包括:(1)使用sdpvar定义变量、约束条件、目标函数和选项(包括通过sdpsettings函数设置求解器选项);(2)使用optimize()函数解决问题;(3)检查结果并获取最终解。
(PS:下文代码选择的求解器为QUADPROG,如果没有安装QUADPROG,只需在定义options时删除该求解器的设置,YALMIP将自动选择其他已安装的求解器。)

% 定义变量
x = sdpvar(10,1);

% 设置约束条件
Constraints = [sum(x) <= 10, x(1) == 0, 0.5 <= x(2) <= 1.5];
for i = 1 : 7
  Constraints = [Constraints, x(i) + x(i+1) <= x(i+2) + x(i+3)];
end

% 定义目标函数
Objective = x'*x + norm(x,1);

% 使用options结构体来为YALMIP和所需求解器指定优化参数
options = sdpsettings('verbose',1,'solver','quadprog','quadprog.maxiter',100);

% 将约束条件、目标函数和选项作为输入传递给优化函数,进行问题求解
sol = optimize(Constraints,Objective,options);

% 获取最终解或进行错误分析
if sol.problem == 0
 % 获取解的值
 solution = value(x);
else
 disp('出错了!');
 sol.info
 yalmiperror(sol.problem)
end

YALMIP符号变量

  在YALMIP中最重要的命令是sdpvar,用于定义决策变量。定义一个n行m列矩阵(或标量)的方法如下:

P = sdpvar(n,m);

  方阵默认为对称阵。若需要定义一个完全参数化(即不一定对称)的方阵,还需要输入第三个参数:

P = sdpvar(3,3,'full');

  如果在上述代码中省略句尾的分号,或直接在命令行输入“P”后回车,可以查看此矩阵的性质。结果如下所示:

Linear matrix variable 3x3 (full, real, 9 variables)

  第三个参数也可以用于获得一系列预定义的变量,如Toeplitz、Hankel、对角、对称和斜对称矩阵等(更多细节请参考sdpvar)。当然,也可以用常规方法来定义向量,如下所示:

x = sdpvar(n,1);	% 向量
D = diag(x) ;    % 对角矩阵
H = hankel(x);   % Hankel矩阵
T = toeplitz(x); % Toeplitz矩阵

  标量可以通过如下三种方法来定义:

x = sdpvar(1,1); y = sdpvar(1,1);
x = sdpvar(1); y = sdpvar(1);
sdpvar x y

  sdpvar对象在MATLAB中的使用方法和任何其他变量一样,大多数函数都是重载的。因此,以下命令是有效的:

P = sdpvar(3,3) + diag(sdpvar(3,1));
X = [P P;P eye(length(P))] + 2*trace(P);
Y = X + sum(sum(P*rand(length(P)))) + P(end,end)+hankel(X(:,1));

% eye()函数用于返回单位矩阵,如eye(n)将返回n*n单位矩阵
% trace()函数用于求矩阵的迹
% end函数返回下标的最大值

  在码代码时,如果对YALMIP不太熟悉,建议养成查看表达式和变量的习惯,看看它们的属性是否与期望相符。举个栗子,若定义正确,上文代码所得的X应该是一个6x6实对称矩阵。根据下文对X的查看结果可得,它确实是一个由9个变量构成的对称6x6矩阵。

>> X
Linear matrix variable 6x6 (symmetric, real, 9 variables)

  在某些情况下,可以使用多维变量来简化编码。YALMIP支持两种不同的构造:元胞数组和多维sdpvar对象。元胞数组格式只是以下代码的抽象化:

for i = 1:5
  X{i} = sdpvar(2,3);
end

  通过在sdpvar中设置向量维数,上文的元胞数组还可以用下述方法设置:

X = sdpvar([2 2 2 2 2],[3 3 3 3 3]);

  此元胞数组可以在MATLAB中正常使用。但这种定义方法的缺陷在于变量X不能直接用作标准的sdpvar对象(在MATLAB中,plus等运算符在单元格上不可重载)。因此,可以使用完全通用的多维sdpvar创建一个等价对象:

X = sdpvar(2,3,5);

  通过这种方法,我们可以用标准的MATLAB代码直接对这个对象进行操作:

Y = sum(X,3)
X(:,:,2)

  根据标准YALMIP语法,如果前两个维度相同,那么前两个面就是对称的。要创建完全参数化的高维变量,需要给定一个“full”标志:

X = sdpvar(2,2,2,2,'full');

  有关多维变量的示例请查看Sudoku example。

约束条件

  我们可以通过“创建+连接”的方式定义约束集合。约束的含义取决于上下文:如果左右两侧都是Hermitian矩阵,则约束将按照正定性进行解释,否则将逐元素进行解释。因此,定义一个对称矩阵和正定性约束的方法如下:

n = 3;
P = sdpvar(n,n);
C = [P>=0];

  定义具有正元素的对称矩阵示例如下:

P = sdpvar(n,n);
C = [P(:)>=0];

  注意,这样就两次定义了非对角约束。一个好的半定规划(Semi-definite Programming,SDP)求解器可能会在预处理过程中检测到这一点并简化模型,不过我们也可以使用常规方法来手动定义特殊元素,如下所示:

C = [triu(P)>=0];	% triu()函数用于抽取上三角矩阵

  或者:

C = [P(find(triu(ones(n))))>=0];

  根据上述规则,可以使用>=运算符定义具有正元素的非平方矩阵(即非对称矩阵),如下所示:

P = sdpvar(n,2*n);
C = [P>=0];

  同样的方法也可以用于定义具有正元素的完全参数化的矩阵:

P = sdpvar(n,n,'full');
C = [P>=0];

  一系列约束可以通过“添加”或“连接”来定义,如下所示:

P = sdpvar(n,n);
C = [P>=0] + [P(1,1)>=2];
C = [P>=0, P(1,1)>=2];

  定义约束时所涉及的表达式中可以包括任意sdpvar对象,等式约束(==)和不等式约束(<=)也都可以使用,如下所示:

C = [P>=0, P(1,1)<=2, sum(sum(P))==10

  在工作区双击约束,或在命令行输入约束名后回车,可以查看约束列表,并检查约束是否已有效定义了。正如前文关于查看表达式和变量的建议一样,推荐大家及时查看约束,以保证它们的属性与期望相符。查看上述约束所得结果示例如下:

++++++++++++++++++++++++++++++++++++++
|   ID|                    Constraint|
++++++++++++++++++++++++++++++++++++++
|   #1|         Matrix inequality 3x3|
|   #2|   Element-wise inequality 1x1|
|   #3|       Equality constraint 1x1|
++++++++++++++++++++++++++++++++++++++

  以下代码可以实现多个约束的同时定义:

F = [0 <= P(1,1) <= 2];

  严格不等式是不能使用的(将收到YALMIP发出的警告),因为数值求解器是使用数值公差进行优化的,故严格不等式在求解时没有任何意义。因此,如果我们需要设置严格上限,则必须设置一个边界。边界的选择很重要:若其太小,则没什么作用,因为它会淹没在求解器用来定义足够接近可行约束的常规公差中;若其太大,则可能会使可行空间大大缩小。

my_tolerance_for_strict = 1e-5;
F = [0 <= P(1,1) <= 2-my_tolerance_for_strict];

  for循环也能用于连接多个约束:

F = [0 <= P(1,1) <= 2];
for i = 2:n-1
 F = [F, P(i,1) <= P(2,i) - P(i,i)];
end

  在定义了变量和约束之后,就可以进行各类优化问题的求解了。接下来我们将从线性规划开始,学习一系列普通规划问题及其MATLAB实现方法。
  下一课:YALMIP学习(二):线性规划

你可能感兴趣的:(YALMIP学习,matlab)