armadillo是C++中非常好用的一个线性代数运算库,有着和matlab非常相似的语法,可以非常方便的将matlab代码转移到C++中。

但是单纯的armadillo库,运算性能比较有限,如果加上开源的openblas,会极大提高矩阵运算性能。百度了下,基本上都是在VS2019中使用armadillo和openblas的教程,我大多数时候写的都是一些小项目,用VS未免有些杀鸡用牛刀的感觉,还是VSCode,好看又好用。百度了下,还没有看到相关的VSCode配置armadillo+openblas的教程,摸索了一下,总结经验如下:

第一步:openblas官网下载编译好的版本,网址:https://github.com/xianyi/OpenBLAS/releases,解压到任意盘,最好不要有中文路径,避免出错。

根据自己的情况,下载64位或32位版本。

第二步:下载armadillo,只需要其中的include文件夹即可,然后放在项目文件夹下,用vscode打开该项目文件夹。

armadillo网址:https://arma.sourceforge.net/download.html

第三步:下载的部分基本结束了,下面主要就是配置VScode中的几个json文件:

这个是c_cpp_properties.json文件的配置,很好理解,主要就是include和openblas的路径配置。

然后是settins.json的配置,不好截图,我直接粘贴:

1
2
3
4
5
6
"code-runner.executorMap": {

"c": "cd $dir && gcc '$fileName' -o '$fileNameWithoutExt.exe' -Wall -g -O2 -static-libgcc -std=c11 -fexec-charset=UTF-8 && &'$dir$fileNameWithoutExt'",

"cpp": "cd $dir && g++ $fileName -o $fileNameWithoutExt -I C:/Users/Administrator/Desktop/cpp2/include/armadillo_bit -DARMA_DONT_USE_WRAPPER F:/OpenBLAS-0.3.21-x64/lib/libopenblas.lib -I C:/Users/Administrator/Desktop/cpp2/include && $dir$fileNameWithoutExt"
},

上面这段代码,主要是第二段的cpp设置,两个-I开头的是include文件夹的路径,和include中加上armadillo_bit的路径,中间那段,前边固定,后边是你下载的编译好的openblas对应的/lib/libopenblas.lib,静态链接库文件。

主要就是这两个文件的配置。

然后是测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#include <iostream>
#include <armadillo>

using namespace std;
using namespace arma;

// Armadillo documentation is available at:
// http://arma.sourceforge.net/docs.html

// NOTE: the C++11 "auto" keyword is not recommended for use with Armadillo objects and functions

int
main(int argc, char** argv)
{
//cout << amradillo -v << endl;
cout << "Armadillo version: " << arma_version::as_string() << endl;

// construct a matrix according to given size and form of element initialisation
mat A(2,3,fill::zeros);

// .n_rows and .n_cols are read only
cout << "A.n_rows: " << A.n_rows << endl;
cout << "A.n_cols: " << A.n_cols << endl;

A(1,2) = 456.0; // access an element (indexing starts at 0)
A.print("A:");

A = 5.0; // scalars are treated as a 1x1 matrix
A.print("A:");

A.set_size(4,5); // change the size (data is not preserved)

A.fill(5.0); // set all elements to a specific value
A.print("A:");

A = { { 0.165300, 0.454037, 0.995795, 0.124098, 0.047084 },
{ 0.688782, 0.036549, 0.552848, 0.937664, 0.866401 },
{ 0.348740, 0.479388, 0.506228, 0.145673, 0.491547 },
{ 0.148678, 0.682258, 0.571154, 0.874724, 0.444632 },
{ 0.245726, 0.595218, 0.409327, 0.367827, 0.385736 } };

A.print("A:");

// determinant
cout << "det(A): " << det(A) << endl;

// inverse
cout << "inv(A): " << endl << inv(A) << endl;

// save matrix as a text file
A.save("A.txt", raw_ascii);

// load from file
mat B;
B.load("A.txt");

// submatrices
cout << "B( span(0,2), span(3,4) ):" << endl << B( span(0,2), span(3,4) ) << endl;

cout << "B( 0,3, size(3,2) ):" << endl << B( 0,3, size(3,2) ) << endl;

cout << "B.row(0): " << endl << B.row(0) << endl;

cout << "B.col(1): " << endl << B.col(1) << endl;

// transpose
cout << "B.t(): " << endl << B.t() << endl;

// maximum from each column (traverse along rows)
cout << "max(B): " << endl << max(B) << endl;

// maximum from each row (traverse along columns)
cout << "max(B,1): " << endl << max(B,1) << endl;

// maximum value in B
cout << "max(max(B)) = " << max(max(B)) << endl;

// sum of each column (traverse along rows)
cout << "sum(B): " << endl << sum(B) << endl;

// sum of each row (traverse along columns)
cout << "sum(B,1) =" << endl << sum(B,1) << endl;

// sum of all elements
cout << "accu(B): " << accu(B) << endl;

// trace = sum along diagonal
cout << "trace(B): " << trace(B) << endl;

// generate the identity matrix
mat C = eye<mat>(4,4);

// random matrix with values uniformly distributed in the [0,1] interval
mat D = randu<mat>(4,4);
D.print("D:");

// row vectors are treated like a matrix with one row
rowvec r = { 0.59119, 0.77321, 0.60275, 0.35887, 0.51683 };
r.print("r:");

// column vectors are treated like a matrix with one column
vec q = { 0.14333, 0.59478, 0.14481, 0.58558, 0.60809 };
q.print("q:");

// convert matrix to vector; data in matrices is stored column-by-column
vec v = vectorise(A);
v.print("v:");

// dot or inner product
cout << "as_scalar(r*q): " << as_scalar(r*q) << endl;

// outer product
cout << "q*r: " << endl << q*r << endl;

// multiply-and-accumulate operation (no temporary matrices are created)
cout << "accu(A % B) = " << accu(A % B) << endl;

// example of a compound operation
B += 2.0 * A.t();
B.print("B:");

// imat specifies an integer matrix
imat AA = { { 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 } };

imat BB = { { 3, 2, 1 },
{ 6, 5, 4 },
{ 9, 8, 7 } };

// comparison of matrices (element-wise); output of a relational operator is a umat
umat ZZ = (AA >= BB);
ZZ.print("ZZ:");

// cubes ("3D matrices")
cube Q( B.n_rows, B.n_cols, 2 );

Q.slice(0) = B;
Q.slice(1) = 2.0 * B;

Q.print("Q:");

// 2D field of matrices; 3D fields are also supported
field<mat> F(4,3);

for(uword col=0; col < F.n_cols; ++col)
for(uword row=0; row < F.n_rows; ++row)
{
F(row,col) = randu<mat>(2,3); // each element in field<mat> is a matrix
}

F.print("F:");
getchar();
return 0;
}

测试代码结果截图

正常运行,大功告成!