【MPC】③二次规划求解器quadprog的win平台下C++动态库生成与使用

一、求解器quadprog生成C++动态链接库

(一)概述

MATLAB和C\C++混合编程,可以将MATLAB的M文件编译生成 C 代码和 C++ 代码。代码生成目标与 MATLAB 求解器不使用相同的数学核心函数库。因此,C++代码生成解可能不同于MATLAB求解器的解,尤其是对于病态问题。

要求

  • 所有 quadprog 输入矩阵(如 A、Aeq、lb 和 ub)都必须是满矩阵,而不能是稀疏矩阵。您可以使用 full 函数将稀疏矩阵转换为满矩阵。
  • lb 和 ub 参数的条目数必须与 H 中的列数相同,或必须为空 []。

(二)matlab安装MinGW64编译器

  • matlab推荐使用matlab2020a之后的版本
  • 编译器推荐使用MinGW64

参考:https://blog.csdn.net/qq_46467894/article/details/125291664

  • 下载软件

下载链接:https://sourceforge.net/projects/mingw-w64/files/

在这里插入图片描述

  • 环境配置
    此电脑-属性-高级系统设置-高级-环境变量-新建
    变量名:MW_MINGW64_LOC
    变量值:D:\Program Files\mingw64(上一步安装包解压的位置)
  • matlab配置C/Cpp编译器
    在这里插入图片描述
    选择mex -setup C++ 和MinGW64 Compiler

(三)C++ DLL库文件生成

参考:https://ww2.mathworks.cn/help/optim/ug/code-generation-for-quadprog-example.html

步骤一:生成matlab的二次规划求解代码。例如:创建C_QUADPROG.m

function X = C_QUADPROG(H,g,A_cons,b_cons,lb,ub)
%C_QUADPROG 输入六个参数,假设没有等式约束,即Aeq = [] 和 beq = []
X = quadprog(H,g,A_cons,b_cons,[],[],lb,ub);
end

步骤二:为m文件生成dll链接库

function X = C_QUADPROG(H,g,A_cons,b_cons,lb,ub)
%C_QUADPROG 输入六个参数,假设没有等式约束,即Aeq = [] 和 beq = []
X = quadprog(H,g,A_cons,b_cons,[],[],lb,ub)
end

参考:https://blog.csdn.net/m0_46427461/article/details/124181300

1、命令行输入:

mbuild -setup

在这里插入图片描述

2、选择” mex -setup C++ -client MBUILD “
在这里插入图片描述
3、命令行窗口输入>>deploytool,选择Library Compiler
在这里插入图片描述
4、添加m文件,运行package进行打包
在这里插入图片描述

二、quadprog动态库调用

(一)原理概述

1、win平台下dll、h、lib文件关系

参考:https://blog.csdn.net/weixin_43450564/article/details/109467939

(1)三者含义

  • .h:头文件 —— 编译时需要
  • .lib:静态链接库/动态链接库的导入库 —— 链接时需要
  • .dll:动态链接库 —— 运行时需要

(2)三者关系:

  • .h:声明函数接口
  • .dll:函数可执行代码
  • .lib:因为.lib有两个身份,分开讨论

lib文件详解:
如果作为动态链接库的导入库:告诉编译器,调用的函数在哪个dll文件中 —— 起到“桥梁”的作用。
如果作为静态链接库:函数的可执行代码也集成在其中。
导入库和静态库虽然都是以.lib作为结尾的,但是他们的区别很大,他们实质是不一样的东西。
静态库本身就包含了实际执行代码、符号表等;
而对于导入库而言,其实际的执行代码位于动态库中,导入库只包含了地址符号表等,确保程序找到对应函数的一些基本地址信息。
lib文件是必须在编译期就连接到应用程序中的,而dll文件是运行期才会被调用的。

2、VS调用动态库概述

(1)VS配置项含义

参考:https://blog.csdn.net/weixin_46879188/article/details/121641491

  • 包含目录:h文件所在的目录。没配置好,会提示:”找不到XXX.h文件“
  • 库目录:寻找lib文件的目录。没配置好,会提示:”找不到XXX.lib文件“
  • 附加依赖项:lib库。如果没配置好,会提示”会出现link error,大概是“未定义的函数XXX”。

(2)lib h dll VS工程目录配置

参考:https://blog.51cto.com/u_15346415/3671701
https://blog.csdn.net/qq_40462954/article/details/117564908

动态库的调用分为三步曲,建议一个工程后:

  • 将.dll与.lib与.h文件放在工程的同目录下
  • 在代码中导入头文件,解决资源方案管理器中也加入头文件
  • 调用动态库:分为显示调用和隐式调用

隐式调用包括:

  • 设置包含目录:属性==>配置属性==>VC++目录==>包含目录(填.h所在文件路径)
  • 设置库目录:属性==>配置属性==>VC++目录==>库目录(填.lib所在路径)
  • 设置附加依赖项:链接器==>输入==>附加依赖项==>添加.lib的名称(动态库.lib)

(二)win平台下quadprog动态库使用

教程主要参考: https://blog.csdn.net/m0_46427461/article/details/124181300
报错参考: https://blog.csdn.net/enjoybocai/article/details/105395683
https://blog.csdn.net/weixin_30845171/article/details/98335379

VS2017,创建C++控制台应用。将C_QUADPROG.dll,C_QUADPROG.lib、C_QUADPROG.h3个文件复制到工程目录下。解决方案平台改为X64.
在这里插入图片描述

1、工程配置

  • 包含目录
    选择“项目-属性-VC++目录-包含目录”,将matlab的头文件include文件夹路径添加进去,例如:“D:\Program Files\MATLAB\R2021b\extern\include”
  • 库文件
    选择“项目-属性-VC++目录-库目录”,将matlab的库文件lib文件夹路径添加进去,例如:“D:\Program Files\MATLAB\R2021b\extern\lib\win64\microsoft”
  • 附加依赖项
    选择“项目-属性-链接器-输入-附加依赖项”,添加C_QUADPROG.lib” 和“mclmcrrt.lib。,其中C_QUADPROG.lib是刚刚用Matlab生成的lib文件,mclmcrrt是调用MATLAB引擎的一个lib文件。

2、程序调试

(1)创建主函数
//#pragma comment(lib, "C_QUADPROG.lib")  //与在属性配置中“添加附加依赖项”的作用相同,前三行可以省去
 
//#pragma comment(lib, "mclmcr.lib")
//#pragma comment(lib, "mclmcrrt.lib")
 
#include <iostream>
#include "stdafx.h"
#include "C_QUADPROG.h"
#include <atlstr.h>
 
using namespace std;
 
int main()
 
{
	printf("进入main函数");
	//初始化DLL动态连接文件
	mclmcrInitialize();
	// 鉴定Matlab外部调用环境设置是否正确.
	if (!mclInitializeApplication(NULL, 0)) {
		cout << "error1" << endl;
		return -1;
	}
 
	C_QUADPROGInitialize();
	if (!C_QUADPROGInitialize()) {
		cout << "error2" << endl;
		return -1;
	}
 
	//输入矩阵、数组
	double H[3][3] = { {1,-1,1},{-1,2,-2},{1,-2,4} };
	double g[3][1] = { {-7},{-12},{-15} };
	double A[1][3] = {1, 1, 1};
	double b[1] = {1};
	double lb[3][1] = { {-10},{-10},{-10} };
	double ub[3][1] = { {10},{10},{10} };
 
	//输出矩阵、数组
	//double x_out[2];
	//double fval_out[1];
 
	//为QUADASSINPROG函数创建输入参数矩阵
	mxArray* Input_H = mxCreateDoubleMatrix(3, 3, mxREAL);
	//将输入矩阵、数组拷贝至QUADASSINPROG输入参数
	memcpy(mxGetPr(Input_H), (void*)H, sizeof(H));
 
	mxArray* Input_g = mxCreateDoubleMatrix(3, 1, mxREAL);
	memcpy(mxGetPr(Input_g), (void*)g, sizeof(g));
 
	mxArray* Input_A = mxCreateDoubleMatrix(1, 3, mxREAL);
	memcpy(mxGetPr(Input_A), (void*)A, sizeof(A));
 
	mxArray* Input_b = mxCreateDoubleMatrix(1, 1, mxREAL);
	memcpy(mxGetPr(Input_b), (void*)b, sizeof(b));
 
	mxArray* Input_lb = mxCreateDoubleMatrix(3, 1, mxREAL);
	memcpy(mxGetPr(Input_lb), (void*)lb, sizeof(lb));
 
	mxArray* Input_ub = mxCreateDoubleMatrix(3, 1, mxREAL);
	memcpy(mxGetPr(Input_ub), (void*)ub, sizeof(ub));
 
	mxArray* Input[6] = { Input_H, Input_g, Input_A, Input_b, Input_lb, Input_ub };
	mxArray* Output[2];
 
	//调用Matlab中的函数 function [x, fval] = QUADASSINPROG(H, C, A, b, lb)以测试
	mlxC_QUADPROG( 1, Output, 6, Input);
 
	//为QUADASSINPROG函数创建输出参数指针
	mxArray* x = mxCreateDoubleMatrix(1, 3, mxREAL);    //输出的x的大小也要随输入矩阵的大小更改
	//mxArray* fval = mxCreateDoubleMatrix(1, 1, mxREAL);
 
	//将输出参数传递给输出参数指针
	x = Output[0];
	//fval = Output[1];
 
	double *x_out = mxGetPr(x);   //x_out是DLL开始前定义的double数组;x是DLL开始后定义的mxArray数组
	//double *fval_out = mxGetPr(fval);
 
	memcpy(x, mxGetPr(x), sizeof(x));
	//memcpy(fval, mxGetPr(fval), sizeof(fval));
 
 
	CString resultStr;
	resultStr.Format("控制量结果:% f % f % f ", x_out[0], x_out[1], x_out[2]);
 
	cout << resultStr << endl;
	cout << "结束" << endl;
 
	//char anyKey;
	//cin >> anyKey;
	C_QUADPROGTerminate(); //结束DLL库
	system("pause");
	return 0;
}
(2)添加头文件

将matlab生成的头文件,添加到工程项目中
在这里插入图片描述

3、报错信息解决方案

(1)缺少stdafx.h头文件

主要因为工程缺少头文件,在电脑搜索相应的头文件,将缺少的所有头文件全部加入项目中。最后一共添加这么多个头文件。
在这里插入图片描述

(2)未定义标识符 “CString”

需要添加头文件#include <atlstr.h>。
同时,需要将“项目-属性-常规”
MFC的使用改为:在共享DLL中使用MFC
公共语言运行时支持:使用多字节字符集

在这里插入图片描述

(3)找不到mclmcrrt9_11.dll

在电脑中检索到mclmcrrt9_11.dll,复制粘贴到工程目录下。

(4)An Error has occurred while trying to initialize the MATLAB Runtime.

报错信息:
An Error has occurred while trying to initialize the MATLAB Runtime.
The error is: Fatal error loading library C:\Users\zhangzhiwei\source\repos\testmatlab\testmatlab\libmat.dll Error: 找不到指定的模块。
因为电脑上存有多个版本的Matlab系统,将C_QUADPROG.dll 复制到项目目录\x64\Debug文件夹下,运行生成的exe文件,即可。

4、成功的结果

在这里插入图片描述

  • 25
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 40
    评论
二次规划是指优化一个二次函数的问题,通常形式如下: $$\min_{\boldsymbol{x}} \frac{1}{2} \boldsymbol{x}^T \boldsymbol{Q} \boldsymbol{x} + \boldsymbol{c}^T \boldsymbol{x}$$ 其中 $\boldsymbol{x} \in \mathbb{R}^n$ 是优化变量,$\boldsymbol{Q} \in \mathbb{S}^n$ 是一个对称正定矩阵,$\boldsymbol{c} \in \mathbb{R}^n$ 是一个向量。 带约束的二次规划则是在上述问题的基础上,增加一些约束条件,例如: $$\begin{aligned} \min_{\boldsymbol{x}} \quad & \frac{1}{2} \boldsymbol{x}^T \boldsymbol{Q} \boldsymbol{x} + \boldsymbol{c}^T \boldsymbol{x} \\ \text{s.t.} \quad & A\boldsymbol{x} \geq \boldsymbol{b} \\ & \boldsymbol{x} \geq \boldsymbol{0} \end{aligned}$$ 其中 $A$ 和 $\boldsymbol{b}$ 分别是一个矩阵和一个向量,表示线性约束条件,$\geq$ 表示大于等于的约束。 现在我们考虑一个带约束的二次规划实例: $$\begin{aligned} \min_{x_1,x_2} \quad & 2x_1^2 + x_2^2 + 3x_1 - 2x_2 + 1 \\ \text{s.t.} \quad & -x_1 + x_2 \geq 1 \\ & x_1 + x_2 \leq 2 \\ & x_2 \geq 0 \end{aligned}$$ 我们可以将其转化为标准形式: $$\begin{aligned} \min_{\boldsymbol{x}} \quad & \frac{1}{2} \boldsymbol{x}^T \boldsymbol{Q} \boldsymbol{x} + \boldsymbol{c}^T \boldsymbol{x} \\ \text{s.t.} \quad & A\boldsymbol{x} \geq \boldsymbol{b} \\ & \boldsymbol{x} \geq \boldsymbol{0} \end{aligned}$$ 其中 $$\boldsymbol{x} = \begin{bmatrix} x_1 \\ x_2 \end{bmatrix}, \quad \boldsymbol{Q} = \begin{bmatrix} 4 & 0 \\ 0 & 2 \end{bmatrix}, \quad \boldsymbol{c} = \begin{bmatrix} 3 \\ -2 \end{bmatrix}, \quad A = \begin{bmatrix} -1 & 1 \\ 1 & 1 \\ 0 & -1 \end{bmatrix}, \quad \boldsymbol{b} = \begin{bmatrix} -1 \\ 2 \\ 0 \end{bmatrix}$$ 我们可以使用优化求解该问题,例如利用 C++ 的优化 Eigen: ```cpp #include <iostream> #include <Eigen/Dense> #include <Eigen/QuadProg.h> int main() { // 定义变量和矩阵 Eigen::Matrix<double, 2, 2> Q; Eigen::Matrix<double, 2, 1> c; Eigen::Matrix<double, 3, 2> A; Eigen::Matrix<double, 3, 1> b; Eigen::Matrix<double, 2, 1> x; // 初始化矩阵 Q << 4, 0, 0, 2; c << 3, -2; A << -1, 1, 1, 1, 0, -1; b << -1, 2, 0; // 设置求解 Eigen::QuadProgDense<double> solver; solver.settings().setPrintLevel(0); // 求解 solver.solve(Q, c, A, b, Eigen::Matrix<double, 0, 0>(), Eigen::Matrix<double, 0, 1>(), x); // 输出结果 std::cout << "Solution: " << std::endl << x << std::endl; return 0; } ``` 输出结果为: ``` Solution: 0.500000 1.500000 ``` 即最优解为 $x_1=0.5$,$x_2=1.5$。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 40
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

后厂村路蔡徐坤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值