Yalmip入门教程(3)-约束条件的定义

news2024/10/7 2:23:59

        博客中所有内容均来源于自己学习过程中积累的经验以及对yalmip官方文档的翻译:https://yalmip.github.io/tutorials/

        之前的博客简单介绍了约束条件的定义方法,接下来将对其进行详细介绍。

        首先简单复习一下:

        1.定义约束条件可以使用矩阵拼接,或者’+’号,两种方式是等价的;

        2.Yalmip中的约束可以写成连续的不等式形式;

        3.Yalmip中不支持严格的不等号(<或>),一旦出现,就会报错,然后弹出“猫猫图”。

        下面将继续讲解约束条件定义的方法与技巧。

1.约束的普通形式与矩阵形式

例1:请使用Yalmip工具箱写出下列优化问题的约束条件

        采用常规的思维,可以分别写出每个约束条件,然后采用拼接的方式将所有约束条件组合起来,matlab代码如下:

x = sdpvar(3,1);

C = [sum(x) <= 12 ,...

     5*x(1) + x(3) <= 9 ,...

     3*x(1) + 2*x(2) >= 6 ,...

     x(2) + 2*x(3) >= 1 ,...

     x >= 0];

        但是在求解优化问题的过程中,很多时候需要我们写出优化问题的对偶形式或KKT条件,这时候如果可以写成紧凑的矩阵形式,转换将会更加容易。例1的约束条件写成紧凑的矩阵形式为:

 

        将约束条件写作矩阵形式时,代码如下:

x = sdpvar(3,1);
A = [-1   0   0;
      0  -1   0;
      0   0  -1;
      1   1   1;
      5   0   1;
     -3  -2   0;
      0  -1  -2];
b = [0;0;0;12;9;-6;-1];
C = [A*x <= b];

        两种写法是完全等价的,下面的代码分别采用两种不同的约束定义方式对优化问题进行求解,可以得到相同的优化结果:

clc
clear
 
x = sdpvar(3,1);
A = [-1   0   0;
      0  -1   0;
      0   0  -1;
      1   1   1;
      5   0   1;
     -3  -2   0;
      0  -1  -2];
b = [0;0;0;12;9;-6;-1];
C1 = [A*x <= b];
C2 = [sum(x) <= 12 ,...
      5*x(1) + x(3) <= 9 ,...
      3*x(1) + 2*x(2) >= 6 ,...
      x(2) + 2*x(3) >= 1 ,...
      x >= 0];
objective = [1 2 3]*x;
optimize(C1 , objective);
objective1 = value(objective)
x1 = value(x)
optimize(C2 , objective);
objective2 = value(objective)
x2 = value(x)

运行结果:

objective1 =

    3.3333


x1 =

    1.3333
    1.0000
         0

objective2 =

    3.3333


x2 =

    1.3333
    1.0000
         0

        在实际编程过程中,两种形式各有优劣,但完全等价,可以根据自己的需要采用一般形式或矩阵形式定义约束条件,只要自己感觉更方便即可。

2.小技巧

2.1查看约束变量的参数

        在定义约束条件之后,在工作区双击对应的约束变量,或者在命令行输入约束变量再回车,可以查看约束的列表,并检查约束是否已有效定义了,例如,例1中用两种不同方式定义的约束条件列表分别如下:

        在该列表中,ID一列表示约束的编号,每个约束都是用’,’或者’+’隔开的,因此约束变量C1中仅有1个约束,约束变量C2中共有5条约束。Constraint一列表示约束的类型和数目,Element-wise inequality表示该约束条件为不等式约束,如果是等式约束,则显示‘Equality constraint’,其他一些常见的约束类型如表1所示。约束类型后面显示的是约束的数目,例如约束变量C1共包含七条约束,因此显示为7×1的约束,而约束变量C2中的第五条约束x>=0,实际上包含x1>=0,x2>=0,x3>=0共三条约束,因此显示为3×1的约束。 

表1 常见的约束类型

约束类型

含义

Matrix inequality

矩阵不等式约束

Second order cone constraint

二阶锥约束

Rotated Lorentz constraint

旋转锥约束

Binary constraint

二进制约束

Eigenvalue constraint

特征值约束

KYP constraint

Kalman Yakubovich Popov 约束

Sum-of-square constraint

平方和约束

Logic constraint

逻辑约束

Semi-continuous variable

半连续的变量约束

Semi-integer variable

半整数的变量约束

Vectorized second-order cone constraints

矢量化二阶锥约束

2.2尽量避免使用循环语句

        在Yalmip工具箱中,大部分matlab内置函数都可以用于sdpvar变量。之前我写过几篇博客说明如何在matlab代码中尽量避免循环的使用,以提升代码运行效率,因此也可将这种思想用于约束条件的定义过程中。下面以Yalmip工具箱官方文档中给出的数独求解的算例(https://yalmip.github.io/example/sudoku/)进行说明。

例2:使用Yalmip工具箱求解图1所示的数独问题

图1 一个数独问题

        为了求解这个问题,可以定义一个9×9×9的三维0-1变量A(i,j,k),当A(i,j,k)取值为1时,表示该数独的第i行第k列的取值为k,为了求解上述数独问题,需要写成初始的数独矩阵,并定义决策变量A:

A0 = [
0 4 7 0 5 0 0 0 8;
6 0 5 0 3 0 2 0 1;
0 0 0 7 0 6 0 3 0;
0 0 6 0 7 0 0 2 4;
9 0 0 8 0 4 0 0 6;
4 5 0 0 1 0 9 0 0;
0 1 0 5 0 2 0 0 0;
2 0 8 0 4 0 5 0 3;
5 0 0 0 9 0 7 1 0;
];
 
A = binvar(9,9,9,'full');

        首先,我们需要把变量A中的元素取值和初始矩阵A0对应起来,代码如下:

for i = 1:9
    for j = 1:9
        if S(i,j)
            F = [F, A(i,j,A0(i,j)) == 1];
        end
    end
end

        这也是常规使用循环语句的思维,但是,如果使用find和sub2ind命令,可以避免循环语句的使用。find函数比较常用,也比较简单,这里不再介绍,重点介绍一下sub2ind。该函数用于将下标向量组转为线性索引,具体的含义我们可以通过一个例子来理解。假设在matlab中有一个矩阵3×3的矩阵S,我们如果想取出矩阵S第3行第2列的元素,可以采用下标的形式写成S(3,2),如果采用线性索引的话,也可以写成A(6)。下标和线性索引的关系如图2所示:

图2 matlab二维数组中下标和线性索引的关系

        sub2ind就可以把一组下标转为一组线性索引,以避免循环的使用,标准语法为:

ind = sub2ind(sz,row,col)

        例如,我们要取出矩阵S的元素S(1,2),S(1,3),S(2,2)和S(3,2),也就是要求出线性索引向量[4 5 6 7],采用sub2ind函数即可解决:

row = [1 2 3 1];
col = [2 2 2 3];
sz = [3 3];
ind = sub2ind(sz,row,col)

输出结果为:

ind =

     4     5     6     7

        因此,使用find与sub2ind,可以将上述代码改写成:

[i,j,k] = find(A0);
F = [F, A(sub2ind(size(A),i,j,k)) == 1];

        这样做就可以避免使用双层循环。另外,数独游戏的规则是,每一行、每一列以及每一个3×3的子块的数字不能重复,其中每行每列数字不能重复的约束比较简单,代码如下:

F = [sum(A,1) == 1, sum(A,2) == 1, sum(A,3) == 1];

        要保证每个3×3的子块数字不能重复,可以采用循环的方式,代码如下:

for m = 1:3
    for n = 1:3
        for k = 1:9
            s = sum(sum(A((m-1)*3+(1:3),(n-1)*3+(1:3),k)));             
            F = [F, s == 1];
        end
    end
end

        为了尽量避免使用循环语句,可以将代码改写如下:

for k = 1:9
    F = [F, sum(sum(A(i1:i1+2 , j1:j1+2 , :))) == 1];
end

        这样写可以只用一层循环,具体原理比较简单,这里不再过多讲解。另外,对于数独问题,我们只需要求出可行解,并没有优化目标,因此使用optimize函数时可以只输入约束条件。

sol = optimize(F);

        求解成功后,可以使用一个矩阵Z来存储最终的数独求解结果:

Z = 0;
for i = 1:9
      Z = Z  + i*value(A(:,:,i));
end
Z

        为了避免循环语句,也可以写成:

Z = value(reshape(A,9,81)*kron((1:9)',eye(9)))

        其中,reshape函数用于改变矩阵的形状,并返回一个新的矩阵。在这条语句中,reshape(A,9,81)表示将矩阵A重塑为一个9行81列的矩阵。kron函数用于计算两个矩阵的张量积,在这条语句中,kron((1:9)',eye(9))可以得到一个81行9列的矩阵,其中对应位置的元素由(1:9)'和单位矩阵的元素相乘得到。将矩阵reshape(A,9,81)与矩阵kron((1:9)',eye(9)),得到的就是9×9的矩阵,也就是数独问题的解。

        综上所示,使用常规思维+更多的循环语句求解数独问题的完整代码如下:

方法1:放肆使用循环语句

clc
clear
 
tic
A0 = [
0 4 7 0 5 0 0 0 8;
6 0 5 0 3 0 2 0 1;
0 0 0 7 0 6 0 3 0;
0 0 6 0 7 0 0 2 4;
9 0 0 8 0 4 0 0 6;
4 5 0 0 1 0 9 0 0;
0 1 0 5 0 2 0 0 0;
2 0 8 0 4 0 5 0 3;
5 0 0 0 9 0 7 1 0;
];
 
A = binvar(9,9,9,'full');
F = [sum(A,1) == 1, sum(A,2) == 1, sum(A,3) == 1];
 
for i = 1:9
    for j = 1:9
        if A0(i,j)
            F = [F, A(i,j,A0(i,j)) == 1];
        end
    end
end
 
for m = 1:3
    for n = 1:3
        for k = 1:9
            s = sum(sum(A((m-1)*3+(1:3),(n-1)*3+(1:3),k)));             
            F = [F, s == 1];
        end
    end
end
 
diagnostics = optimize(F);
 
Z = 0;
for i = 1:9
      Z = Z  + i*value(A(:,:,i));
end
Z
toc

方法2:尽量减少循环语句

clc
clear

tic
A0 = [
5 3 0 0 7 0 0 0 0;
6 0 0 1 9 5 0 0 0;
0 9 8 0 0 0 0 6 0;
8 0 0 0 6 0 0 0 3;
4 0 0 8 0 3 0 0 1;
7 0 0 0 2 0 0 0 6;
0 6 0 0 0 0 2 8 0;
0 0 0 4 1 9 0 0 5;
0 0 0 0 8 0 0 7 9;
];

A = binvar(9,9,9,'full');

F = [sum(A,1) == 1, sum(A,2) == 1, sum(A,3) == 1];

i1 = [1,1,1,4,4,4,7,7,7];
j1 = [1,4,7,1,4,7,1,4,7];
for k = 1:9
    F = [F, sum(sum(A(i1:i1+2 , j1:j1+2 , :))) == 1];
end

[i,j,k] = find(A0);
F = [F, A(sub2ind(size(A),i,j,k)) == 1];

diagnostics = optimize(F);

Z = value(reshape(A,9,81)*kron((1:9)',eye(9)))
toc

        两种方式的运行结果完全一致:

Z =

     3     4     7     2     5     1     6     9     8
     6     8     5     4     3     9     2     7     1
     1     2     9     7     8     6     4     3     5
     8     3     6     9     7     5     1     2     4
     9     7     1     8     2     4     3     5     6
     4     5     2     6     1     3     9     8     7
     7     1     3     5     6     2     8     4     9
     2     9     8     1     4     7     5     6     3
     5     6     4     3     9     8     7     1     2

        但在运行时间上,两种方法存在差异,某次测试中,方法1的运行时间为0.638127秒,方法2的运行时间为0.473180秒,避免循环的使用提高了25.85%的运行效率。

        减少循环语句的使用,在小规模问题中效率提升可能不是很明显,但如果优化问题比较复杂,约束也很复杂,如果可以把尽量减少循环语句的思想应用到实际编程中,效率提升可能是非常大的。虽然思考如何减少循环语句可能要废很多脑细胞,但我觉得应该会挺值得。(我自己经历过一个优化问题求解需要8个小时左右,每次等待结果、调试代码都非常痛苦,将近半个月都没有调好,后来想通了,花了两三天的时间优化代码,把运行时间缩短到了1个半小时左右,很快就调试成功了)

3.测试题

3.1测试1

使用矩阵形式的约束条件求解下列优化问题:

max z=3x1+x2

s.t. x1-x2≥-2

x1-2x2≤3

3x1+2x2≤14

x1≥0, x2≥0

3.2测试2

使用Yalmip工具箱求下列数独问题的解:

3.3测试3

        改写下面的代码以避免使用循环语句,并对比两种方式的代码运行时间。

clc
clear
yalmip('clear')
 
tic
n = 50;
a = rand(n,n,n);
x = sdpvar(n,n,n);
z = 0;
for k = 1:n
    for kk = 1:n
        for kkk = 1:n
            z = z + a(k,kk,kkk) * x(k,kk,kkk);
        end
    end
end
toc

3.4测试题参考答案

        第三章测试题的参考答案可以从下面的链接中获取:

https://download.csdn.net/download/weixin_44209907/88062937

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/775635.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何通过nvm管理多个nodejs版本

随着前端项目的越来越多&#xff0c;不同项目使用的nodejs版本可能不一样&#xff0c;导致在切换不同项目时需要更换不同的nodejs版本&#xff0c;非常麻烦。本次推荐使用nvm进行多个nodejs版本的统一管理。 1、nvm的下载 nvm全称Node Version Manager&#xff0c;即Node版本管…

科技政策 | 2023年广东省省级企业技术中心(第22批)认定开始啦!

原创 | 文 BFT机器人 原文链接&#xff1a; http://gdii.gd.gov.cn/zwgk/tzgg1011/content/post_4218083.html 各企业请注意&#xff0c;2023年广东省省级企业技术中心&#xff08;第22批&#xff09;认定已经开始了&#xff0c;广东省工业和信息化厅接收资料截止时间为2023年…

【Java基础教程】Java学习路线攻略导图——史诗级别的细粒度归纳,持续更新中 ~

Java学习路线攻略导图 上篇 前言1、入门介绍篇2、程序基础概念篇3、包及访问权限篇4、异常处理篇5、特别篇6、面向对象篇7、新特性篇8、常用类库篇 前言 &#x1f37a;&#x1f37a; 各位读者朋友大家好&#xff01;得益于各位朋友的支持和关注&#xff0c;我的专栏《Java基础…

Python实战项目——物流行业数据分析(二)

今天我们对物流行业数据进行简单分析&#xff0c;数据来源&#xff1a;某企业销售的6种商品所对应的送货及用户反馈数据 解决问题&#xff1a; 1、配送服务是否存在问题 2、是否存在尚有潜力的销售区域 3、商品是否存在质量问题 分析过程&#xff1a; 依旧先进行数据处理 一…

vue Duplicate keys detected: ‘‘. This may cause an update error. found in

错误原因&#xff1a; 在使用v-for的时候&#xff0c;都要必须加上一个唯一的key值&#xff0c;key的值写成一样的了。所以就导致了警告。尽量不要使用index下标作为key值 换成后台数据返回的id或者i*随机数作为key值就好

linux中快速定位软件安装位置

linux中快速定位软件安装位置步骤如下&#xff1a; 根据进程的名字定位进程ID ps -ef | grep redis通过进程id查找软件安装位置 ll -l /proc/100788/cwd原理说明&#xff1a; linux中进程启动后&#xff0c;会在/proc/目录下新建进程工作目录; 目录规范为&#xff1a;/proc/…

寻找下一个生成式 AI 独角兽,亚马逊云科技创业加速器火热招募中!

生成式AI让人工智能技术又一次破圈&#xff0c;带来了机器学习被大规模采用的历史转折点。它正在掀起新一轮的科技革命&#xff0c;为人类带来前所未有的颠覆性的影响&#xff0c;而诸多创业者也应势而上&#xff0c;寻求创新机遇。生成式AI可以创造全新的客户体验、提高企业内…

将数字孪生系统接入 CesiumJS,能为智慧城市项目带来怎样的改变?

数字孪生系统接入 CesiumJS 的契机&#xff0c;正是智慧城市项目的需要。因为许多智慧城市项目中包含了大量地形、倾斜摄影、DOM、DEM 等 GIS 数据&#xff0c;那么为了能够在数字孪生系统中导入这些 GIS 数据&#xff0c;同时让这些数据在以可视化形式表现出来后&#xff0c;还…

C++-17. 电话号码的字母组合

题目来源&#xff1a;力扣 题目描述&#xff1a; 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。 示例 1&#xff1a; 输…

【MySQL】数据不存在则插入

系列文章 C#底层库–MySQLBuilder脚本构建类&#xff08;select、insert、update、in、带条件的SQL自动生成&#xff09; 本文链接&#xff1a;https://blog.csdn.net/youcheng_ge/article/details/129179216 C#底层库–MySQL数据库操作辅助类&#xff08;推荐阅读&#xff0…

全面认识二极管,一篇文章就够了

电子设计基础元器件 二极管&#xff0c;小小二极管&#xff0c;大大用途。 ... 矜辰所致目录 前言一、二极管基础知识1.1 什么是二极管1.2 二极管的组成1.3 二极管的原理 二、二极管特性2.1 伏安特性曲线图2.2 温度的影响2.3 关于击穿 三、 二极管的参数正向连续电流和平均整…

银行金融风险管理面试问题汇总(附答案)

最近有些学员在咨询换工作的事&#xff0c;包括一些金融上市公司的高管。我收集了一些金融风险管理面试问题相关资料&#xff0c;希望能帮助大家。记得收藏此文章&#xff0c;以防之后找不到文章。 风险经理识别和分析潜在的公司风险&#xff0c;并找到减少或避免风险的方法。…

pve (群辉、软路由、win/linux)折腾日记

目录 生命不息&#xff0c;折腾不止名词解释硬件参数装机PVE安装下载pveultraISO 把镜像写入u盘rufus把镜像写入U盘bios设置U盘启动安装pve系统 ssh连接pvepve的使用安装pvetools安装ubuntu-server系统ubuntu更换国内源ubuntu安装docker更改docker国内源docker环境下安装青龙 安…

了解 MySQL 的存储引擎

点击上方↑“追梦 Java”关注&#xff0c;一起追梦&#xff01; 存储引擎的主要工作就是与文件系统进行数据交互&#xff0c;比如我们常用的 InnoDB 引擎。 MySQL 的存储引擎是插件式的&#xff0c;应用程序无需针对不同的存储引擎进行对应的编码操作&#xff0c;MySQL 提供了一…

什么是布道师?看完这篇文章你就懂了

布道师这个术语可能对许多人来说还比较陌生&#xff0c;但实际上&#xff0c;布道师在软件行业中扮演着非常重要的角色。他们是软件产品的积极倡导者和用户之间的桥梁&#xff0c;致力于传递好消息、收集反馈&#xff0c;并与用户建立良好的关系。在本文中&#xff0c;我们将深…

Linux —— 查看进程命令及进程优先级

目录 一&#xff0c;查看进程命令 1&#xff0c;ps 命令 ps axj ps aux ps l ps -l 2&#xff0c;top 命令 3&#xff0c;ptree 命令 4&#xff0c;pgrep 命令 三&#xff0c;进程优先级 PRI NI 一&#xff0c;查看进程命令 ps、top、pstree、grep&#xff1b; 1&…

腾讯云 Finops Crane 开发者集训营 - 云成本优化一站式解决方案实践

一、 相关活动介绍&#xff1a; 自从上次参加完CSDN联合腾讯云发起的《云原生之降本增效》活动后&#xff0c;只是停留聚焦在优秀实践方法论、资源与弹性、架构设计上的了解&#xff0c;本次《腾讯云 Finops Crane 开发者集训营》是深入了解并实践基于 FinOps 框架开展的一个成…

001-Spring简要原理分析

Bean的生产 class到beanDefinition beanDefinition到Bean Bean查找流程 根据类型找找到多个根据名称找 AOP 在实例化后创建代理对象返回 把之前创建的Bean塞入代理对象的 target 字段中 事务 利用AOP代理掉数据源 在提交事务的时候 关闭自动提交手动提交事务异常回滚事…

【力扣算法16】之 18. 四数之和 python

文章目录 问题描述示例1示例2提示 思路分析代码分析完整代码详细分析运行效果截图调用示例运行结果 完结 问题描述 给你一个由 n 个整数组成的数组 nums &#xff0c;和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[…

MySQL Schema 比较同步工具汇总(2023 版)

数据库 schema 比较工具使你能够识别关系数据库中对象结构的差异&#xff0c;并在多个数据库中同步你的特定对象。它通常用于以下情况&#xff1a; 将数据库变更从私有分支合并到团队的主分支在同构数据库中保持 schema 一致性构建新的数据库测试环境根据应用需求将数据库 sch…