0
点赞
收藏
分享

微信扫一扫

C++改写Matlab源码实践二之【传递表格数据】————附带详细讲解和示例


文章目录

  • ​​0 背景​​
  • ​​1 Matlab有用代码提取​​
  • ​​2 转换为C++​​
  • ​​2.1 设定变量类型​​
  • ​​2.2 预先和定义声明变量​​
  • ​​3 改写转换后的C++代码​​
  • ​​3.1 指定输入的文件​​
  • ​​3.2 改写处理`Data`和`Data1`结构的数据​​
  • ​​4 福利​​

0 背景

本文是Matlab代码转C++的第二篇,目的是把一个更为复杂的Matlab项目代码转换为C++,以便打包成动态链接库,以供Java或C++调用。转换的难点,在于需要大量改写转换后的代码,把固定的输入数据,转成可以指定文件的方法,并把对数据结构做适当的处理以便调用放获取数据。

以下是文件的目录结构,​​untitled.m​​​调用了从上往下的前三个​​.m​​​文件,并且​​untitled.m​​文件中的内容比较多,改写起来也不容易。

C++改写Matlab源码实践二之【传递表格数据】————附带详细讲解和示例_matlab

matlab运行后的结果(我们需要做的就是把matlab代码转成C++,然后使用其他语言调用C++代码,可以得到输出表格中的数据):

C++改写Matlab源码实践二之【传递表格数据】————附带详细讲解和示例_matlab_02

1 Matlab有用代码提取

以下为Matlab项目入口的​​untitled.m​​的部分原代码:

function varargout = untitled(varargin)
% UNTITLED MATLAB code for untitled.fig
% UNTITLED, by itself, creates a new UNTITLED or raises the existing
% singleton*.
%
% H = UNTITLED returns the handle to a new UNTITLED or the handle to
% the existing singleton*.
%
% UNTITLED('CALLBACK',hObject,eventData,handles,...) calls the local
% function named CALLBACK in UNTITLED.M with the given input arguments.
%
% UNTITLED('Property','Value',...) creates a new UNTITLED or raises the
% existing singleton*. Starting from the left, property value pairs are
% applied to the GUI before untitled_OpeningFcn gets called. An
% unrecognized property name or invalid value makes property application
% stop. All inputs are passed to untitled_OpeningFcn via varargin.
%
% *See GUI Options on GUIDE's Tools menu. Choose "GUI allows only one
% instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES

% Edit the above text to modify the response to help untitled

% Last Modified by GUIDE v2.5 25-May-2022 11:48:46

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name', mfilename, ...
'gui_Singleton', gui_Singleton, ...
'gui_OpeningFcn', @untitled_OpeningFcn, ...
'gui_OutputFcn', @untitled_OutputFcn, ...
'gui_LayoutFcn', [] , ...
'gui_Callback', []);
if nargin && ischar(varargin{1})
gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
[varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT


% --- Executes just before untitled is made visible.
function untitled_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% varargin command line arguments to untitled (see VARARGIN)
set(handles.Dimension,'String','');
set(handles.Numbers,'String','');
set(handles.Clusters,'String','');
set(handles.Iteration,'String','');
% Choose default command line output for untitled
handles.output = hObject;

% Update handles structure
guidata(hObject, handles);

% UIWAIT makes untitled wait for user response (see UIRESUME)
% uiwait(handles.figure1);


% --- Executes on button press in Load.
function Load_Callback(hObject, eventdata, handles)
% hObject handle to Load (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% 数据载入控制
global data;
global data1;
[f,p]=uigetfile('*.mat');
filepath=[p,f]; %filepath即为文件路径
load(filepath);
data = Data;
data1 = Data1;
set(handles.Dimension,'String',num2str(size(Data,2)));
set(handles.Numbers,'String',num2str(size(Data,1)));

% --- Executes on button press in Reset.
function Reset_Callback(hObject, eventdata, handles)
% hObject handle to Reset (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
set(handles.Dimension,'String','');
set(handles.Numbers,'String','');
set(handles.Clusters,'String','');
set(handles.Iteration,'String','');

% --- Executes on button press in Perform.
function Perform_Callback(hObject, eventdata, handles)
% hObject handle to Perform (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
global data;
global data1;
Cope = get(handles.Iteration,'String');
if isempty(Cope)
pause(0.25);
h=msgbox('请先填写最大迭代次数(50-500)');
uiwait(h,5);
else
[~,~,Phi] = PROMETHEE(data);
% clf;
% axes();
bar(handles.Net,Phi)
box off
% set(gca,'XTick',[20 40 60 80 100 120 140 160])
set(get(gca,'YLabel'),'String','The Net Outranking Flow','FontSize',16,'FontWeight','demi','LineWidth',1.5,'FontName','Times New Roman');
T=str2num(get(handles.Iteration,'String'));
[Ss,Uu,V,objFcn,ddmin,times,iter] = myfcm(Phi', T);
% figure(2)
% clf;
bar(handles.ObjFunction,Ss)
box off
set(gca,'Xtick',[1 2 3 4 5 6 7 8 9],'XTicklabel',num2str([2 3 4 5 6 7 8 9 10]'))
ylabel('Objective Function','FontSize',16,'FontWeight','demi','LineWidth',1.5,'FontName','Times New Roman')
xlabel('Number of Clusters','FontSize',16,'FontWeight','demi','LineWidth',1.5,'FontName','Times New Roman')
[~,OptClus]=min(Ss);
set(handles.Clusters,'String',num2str(OptClus+1));
membership = Uu{2};
for i=1:size(data,1)
[~,Label(i)]=max(membership(:,i));
end
% res1 = cell(length(find(Label==3)),1);
% res2 = cell(length(find(Label==2)),1);
% res3 = cell(length(find(Label==1)),1);
% res4 = cell(length(find(Label==4)),1);
% res5 = cell(length(find(Label==5)),1);
% OFva1 = cell(length(find(Label==3)),1);
% OFva2 = cell(length(find(Label==2)),1);
% OFva3 = cell(length(find(Label==1)),1);
% OFva4 = cell(length(find(Label==4)),1);
% OFva5 = cell(length(find(Label==5)),1);
% OFva
Resnet = cell(1,3);
Resnet{1} = Phi(find(Label==1));
Resnet{2} = Phi(find(Label==2));
Resnet{3} = Phi(find(Label==3));

meanOF = [mean(Resnet{1}) mean(Resnet{2}) mean(Resnet{3})];
[~,iii] = sort(meanOF,'descend');
[~,c]=sort(Resnet{iii(1)},'descend');
indexc = find(Label==iii(1));
indexc = indexc(c);
[~,c]=sort(Resnet{iii(3)},'descend');
indexc3 = find(Label==iii(3));
indexc3 = indexc3(c);
[~,c]=sort(Resnet{iii(2)},'descend');
indexc2 = find(Label==iii(2));
indexc2 = indexc2(c);
% OFval1=Phi(indexc);
% OFval3=Phi(indexc3);
% OFval2=Phi(indexc2);

Result1 = cell(size(data,1),1);
Result1{1} = 'rank 1';
for i=2:length(indexc)+1
Result1{i}=data1{indexc(i-1)};
end
% Num = size(data,1);
% xlswrite('Res1.xls',res1,2,'A1');
% xlswrite('Res1.xls',OFval1,1,['A',num2str(length(res11)+1)]);

Result1{1+length(indexc)} = 'rank 2';
for i=2:length(indexc2)+1
Result1{i+length(indexc)}=data1{indexc2(i-1)};
% OFval2{i}=Phi(indexc2(i));
end
% xlswrite('Res1.xls',res2,1,'C1');
% xlswrite('Res1.xls',OFval2,2,['A',num2str(length(res22)+1)]);
Result1{1+length(indexc)+length(indexc2)} = 'rank 3';
for i=2:length(indexc3)+1
Result1{i+length(indexc)+length(indexc2)}=data1{indexc3(i-1)};
% OFval3{i}=Phi(indexc3(i));
end
% for i=1:length(res22)+length(res33)+length(res11)
% Result1{i}
% end
% xlswrite('Res1.xls',Result1);
% Res1=xlsread('Res1.xls');%读取文件datafile.xlsx,并存入data中
set(handles.ResultTable,'data',Result1);%将data中的文件以Data的形式设置在句柄为uitable1的表格中。
end
% xlswrite('Res1.xls',OFval3,3,['A',num2str(length(res33)+1)]);


% 净值

下面是转换后的代码(找到原代码中输出的部分,然后做适当修改后,改写成方法,该方法可以调用其他方法):

function [Result1, Clusters, Phi, Ss] = Perform(data,data1,T)
[~,~,Phi] = PROMETHEE(data);
[Ss,Uu,~,~,~,~] = myfcm(Phi', T);
[~,OptClus] = min(Ss);
Clusters = OptClus+1;
membership = Uu{2};

dataSize=size(data,1);
Label=coder.nullcopy(zeros(1,dataSize));
for i=1:dataSize
[~,Label(i)]=max(membership(:,i));
end
Resnet = cell(1,3);
Resnet{1} = Phi(Label==1);
Resnet{2} = Phi(Label==2);
Resnet{3} = Phi(Label==3);

meanOF = [mean(Resnet{1}) mean(Resnet{2}) mean(Resnet{3})];
[~,iii] = sort(meanOF,'descend');
[~,c]=sort(Resnet{iii(1)},'descend');
indexc = find(Label==iii(1));
indexc = indexc(c);
[~,c]=sort(Resnet{iii(3)},'descend');
indexc3 = find(Label==iii(3));
indexc3 = indexc3(c);
[~,c]=sort(Resnet{iii(2)},'descend');
indexc2 = find(Label==iii(2));
indexc2 = indexc2(c);

Result1 = cell(dataSize,1);
for i=1:dataSize
Result1{i}='000';
end

Result1{1} = 'rank 1';


for i=2:length(indexc)+1
Result1{i}=data1{indexc(i-1)};
end

Result1{1+length(indexc)} = 'rank 2';
for i=2:length(indexc2)+1
Result1{i+length(indexc)}=data1{indexc2(i-1)};
end
Result1{1+length(indexc)+length(indexc2)} = 'rank 3';
for i=2:length(indexc3)+1
Result1{i+length(indexc)+length(indexc2)}=data1{indexc3(i-1)};
end
end

2 转换为C++

参考之前的方法,做C++代码转换,需要注意的时,在设定变量类型时,需要做适当修改,不能使用原始的自动化生成的变量。

2.1 设定变量类型

如果使用了自动检测的,就会爆出如下的错误:

C++改写Matlab源码实践二之【传递表格数据】————附带详细讲解和示例_c++代码_03


这是改写前的数据类型:

C++改写Matlab源码实践二之【传递表格数据】————附带详细讲解和示例_matlab_04


这是改写后的数据类型:

C++改写Matlab源码实践二之【传递表格数据】————附带详细讲解和示例_c++_05

2.2 预先和定义声明变量

这是原始版本:

indexc = find(Label==iii(1));
indexc = indexc(c);

Result1{1} = 'rank 1';
for i=2:length(indexc)+1
Result1{i}=data1{indexc(i-1)};
end

这是改写后的版本:

Result1 = cell(dataSize,1);
dataSize=size(data,1);

for i=1:dataSize
Result1{i}='000';
end

Result1{1} = 'rank 1';
for i=2:length(indexc)+1
Result1{i}=data1{indexc(i-1)};
end

3 改写转换后的C++代码

转换出来的C++代码的示例代码并不能直接使用,我们需要对其进行修改。

下面是转换后的示例代码​​example/main.cpp​​(只有固定的输入【定死了的.mat文件】、输出):

static void main_Perform()
{
coder::array<cell_wrap_0, 2U> data1;
coder::array<cell_wrap_0, 1U> Result1;
coder::array<double, 2U> Phi;
coder::array<double, 2U> data;
double Ss[9];
double Clusters;
// Initialize function 'Perform' input arguments.
// Initialize function input argument 'data'.
data = argInit_UnboundedxUnbounded_real_T();
// Initialize function input argument 'data1'.
data1 = argInit_1xUnbounded_cell_wrap_0();
// Call the entry-point 'Perform'.
Perform(data, data1, argInit_real_T(), Result1, &Clusters, Phi, Ss);
}

下面我们进行改写。

3.1 指定输入的文件

需要读取的​​ranking.mat​​文件的结构如下:

C++改写Matlab源码实践二之【传递表格数据】————附带详细讲解和示例_c++代码_06

​Data1​​中存储100个字符串大学名称:

C++改写Matlab源码实践二之【传递表格数据】————附带详细讲解和示例_c++代码_07

​Data​​​中则是一个​​100x5​​的分数矩阵:

C++改写Matlab源码实践二之【传递表格数据】————附带详细讲解和示例_c++_08

我们使用​​mat.h​​​中的方法,读取​​mat​​文件并判断结构:

const char* matPath= "/Users/mac/Matlab/UniversityRankTest/codegen/lib/Perform/ranking.mat";  

MATFile* pmatFile = matOpen(matPath, "r");

if (pmatFile == NULL)
{
printf("mat数据读取失败!");
return ;
}

matData = matGetVariable(pmatFile, "Data");

if (matData == NULL)
{
printf("结构体中Data数据不存在!");
return ;
}

matData1 = matGetVariable(pmatFile, "Data1");

if (matData1 == NULL)
{
printf("结构体中Data1数据不存在!");
return ;
}

matClose(pmatFile);

3.2 改写处理Data和Data1结构的数据

下面是改写处理​​Data​​的数据(把写死的维度数据,改成变动的实际获取;被注释的部分为原始代码):

coder::array<double, 2U> argInit_UnboundedxUnbounded_real_T(mxArray* data)
{
coder::array<double, 2U> result;
// Set the size of the array.
// Change this size to the value that the application requires.

//原始部分
result.set_size(2, 2);

int N = mxGetN(data);
int M = mxGetM(data);
result.set_size(M, N);

double* test = mxGetPr(data);

//原始部分
// Loop over the array to initialize each element.
// for (int idx0{0}; idx0 < result.size(0); idx0++) {
// for (int idx1{0}; idx1 < result.size(1); idx1++) {
// // Set the value of the array element.
// // Change this value to the value that the application requires.
// result[idx0 + result.size(0) * idx1] = argInit_real_T();
// }
// }

for (int idx0{0}; idx0 < M; idx0++) {
for (int idx1{0}; idx1 < N; idx1++) {
// Set the value of the array element.
// Change this value to the value that the application requires.
result[idx0 + M * idx1] = test[idx0 + M * idx1];
// std::cout<<result[idx0 + M * idx1]<<" ";
}
}

return result;
}

下面是改写处理​​Data1​​的数据:

coder::array<cell_wrap_0, 2U> argInit_1xUnbounded_cell_wrap_0(mxArray* data)
{
coder::array<cell_wrap_0, 2U> result;
// Set the size of the array.
// Change this size to the value that the application requires.

//原始部分
result.set_size(1, 2);

int N = mxGetN(data);
result.set_size(1, N);

//原始部分
// Loop over the array to initialize each element.
// for (int idx0{0}; idx0 < 1; idx0++) {
// for (int idx1{0}; idx1 < result.size(1); idx1++) {
// // Set the value of the array element.
// // Change this value to the value that the application requires.
// result[idx1] = argInit_cell_wrap_0();
// }
// }

for (int idx1{0}; idx1 < N; idx1++) {
mxArray * test = mxGetCell(data, idx1);
result[idx1] = argInit_cell_wrap_0(test);
}

return result;
}

//获得元包中的字符串数据
cell_wrap_0 argInit_cell_wrap_0(mxArray* data)
{
cell_wrap_0 result;
// Set the value of each structure field.
// Change this value to the value that the application requires.
//result.f1 = argInit_1xUnbounded_char_T();

std::string str = mxArrayToString(data);

int N = mxGetN(data);

result.f1 = argInit_1xUnbounded_char_T(str, N);

return result;

//下面为原始数据
// cell_wrap_0 result;
// // Set the value of each structure field.
// // Change this value to the value that the application requires.
// result.f1 = argInit_1xUnbounded_char_T();
// return result;
}

//逐个获取大学字符串数据
coder::array<char, 2U> argInit_1xUnbounded_char_T(std::string data, int N)
{
coder::array<char, 2U> result;
// Set the size of the array.
// Change this size to the value that the application requires.
result.set_size(1, 2);
result.set_size(1, N);

// Loop over the array to initialize each element.
// for (int idx0{0}; idx0 < 1; idx0++) {
// for (int idx1{0}; idx1 < result.size(1); idx1++) {
// // Set the value of the array element.
// // Change this value to the value that the application requires.
// result[idx1] = argInit_char_T();
// }
// }

for (int idx1{0}; idx1 < N; ++idx1) {
result[idx1] = data[idx1];
//std::cout<<result[idx1]<<" ";
}

return result;
}

最后是获得double数组的数据:

//ss数据
for (int i = 0; i < 9; ++i) {
SsData[i] = Ss[i];
}

bestGroupNum = Clusters;//最佳分组
//phi数据
for (int idx0{0}; idx0 < 100; idx0++) {
PhiData[idx0] = Phi[idx0];
}

最后,我们来对比一个原始版本(Matlab自动生成的代码)和改写后的代码版本:

原始版本:

static void main_Perform()
{
coder::array<cell_wrap_0, 2U> data1;
coder::array<cell_wrap_0, 1U> Result1;
coder::array<double, 2U> Phi;
coder::array<double, 2U> data;
double Ss[9];
double Clusters;
// Initialize function 'Perform' input arguments.
// Initialize function input argument 'data'.
data = argInit_UnboundedxUnbounded_real_T();
// Initialize function input argument 'data1'.
data1 = argInit_1xUnbounded_cell_wrap_0();
// Call the entry-point 'Perform'.
Perform(data, data1, argInit_real_T(), Result1, &Clusters, Phi, Ss);
}

改写后的代码版本:

void main_Perform(int iterationNum, const char* matPath, char** univRank, double PhiData[], double SsData[], double& bestGroupNum)
{
coder::array<cell_wrap_0, 2U> data1;
coder::array<cell_wrap_0, 1U> Result1;
coder::array<double, 2U> Phi;
coder::array<double, 2U> data;
// double Phi[100];
double Ss[9];
double Clusters;

mxArray* matData = NULL;
mxArray * matData1 = NULL;

MATFile* pmatFile = matOpen(matPath, "r");

if (pmatFile == NULL)
{
printf("mat数据读取失败!");
return ;
}

matData = matGetVariable(pmatFile, "Data");

if (matData == NULL)
{
printf("结构体中Data数据不存在!");
return ;
}

matData1 = matGetVariable(pmatFile, "Data1");

if (matData1 == NULL)
{
printf("结构体中Data1数据不存在!");
return ;
}

matClose(pmatFile);

// Initialize function 'Perform' input arguments.
// Initialize function input argument 'data'.
data = argInit_UnboundedxUnbounded_real_T(matData);
// Initialize function input argument 'data1'.
data1 = argInit_1xUnbounded_cell_wrap_0(matData1);

// Call the entry-point 'Perform'.
Perform(data, data1, iterationNum, Result1, &Clusters, Phi, Ss);

// for(int i = 0;i < 101;i++){
// univRank[i] = (char*)malloc(sizeof (char) * 256);
// }

for(int i = 0;i < 101;i++){
univRank[i] = (char*)malloc(sizeof (char) * 256);
}

for (int i = 0; i < 101; ++i) {
std::string tmp = Result1[i].f1.operator std::string();
strcpy(univRank[i], tmp.c_str());
}

for (int i = 0; i < 9; ++i) {
SsData[i] = Ss[i];
}

bestGroupNum = Clusters;

for (int idx0{0}; idx0 < 100; idx0++) {
PhiData[idx0] = Phi[idx0];
}


}

4 福利

​​matlab原码、c++转换后代码的资源链接​​, 提取码: 5vjp


举报

相关推荐

0 条评论