简介:
向量化建模是一种高效的数学建模和编程技术,它涉及到对向量、矩阵和更高维数组进行操作,以实现操作的同时性和批量处理。在优化和数据分析等领域,向量化建模可以极大地提高计算效率,特别是当涉及到大量的重复计算时。由于向量化建模具有表述优势、操作优势、计算性能、可扩展性等优势,使得其适合于解决很大一类实际问题
MindOpt APL (MindOpt Algebraic Programming Language, MAPL) 是一种高效且通用的代数建模语言,主要用于数学规划问题的建模,并支持调用多种求解器求解。它当前支持通用的线性、非线性、混合整数问题的建模。其语法贴近数学语言,与代数数学公式很接近,易学易写易读易维护。且MindOpt APL支持对接20+种优化求解器,可用一行命令就切换,大大提升了用户在优化问题求解环节的方案丰富度,降低风险和使用门槛。
那么MAPL是如何支持向量化建模的呢,让我们一起来看下文
MAPL中的向量化建模:
MAPL通过对向量/矩阵常量参数与变量的声明以及运用张量常量表达式的计算、向量/矩阵变量表达式的计算对问题进行建模
本篇我们介绍述向量/矩阵常量参数的声明以及运用张量常量表达式的计算的语法
其中常量参数的声明有三种方式
- 显式定义常量参数
声明一个 m × n m\times n m×n的矩阵式常量:
param matrix_name = [A_11, … , A_1n (n个实数) ; … (m行)A_n1, … , A_mn (n个实数) ];
声明一个 1 × m 1\times m 1×m向量式常量:
param vector_name = [a_11, **… , a_1n (n个实数) ];
- 使用MAPL的内置函数生成常量参数
param v = 内置函数名([param_list]);
- 从表格式csv文件中读取矩阵形式的常量参数
param v = read_csv([file_name,] [param_list]);
张量常量表达式的数学运算符列表如下:
类型 | 操作符 | 说明 | 是否支持标量 | 用例 |
---|---|---|---|---|
一元操作符 | + | 向量/矩阵加法 | 是 | A+B |
- | 向量/矩阵减法,或者参数求反 | 是 | A-B or -A | |
.* | 逐元素乘法 | 否 | A.*B | |
./ | 逐元素除法 | 否 | A./B | |
* | 向量/矩阵乘法 | 是 | A*B | |
' | 矩阵转置 | 否 | A' | |
/ | 向量/矩阵逐元素除以某标量 | 是 | A/2 | |
二元操作符 | .^ | 逐元素的p次幂 | 是 | A.^2 |
^ | 逐元素的p次幂 | 是 | A^2 | |
索引操作符 | [] | 获取指定位置的值 | 否 | A[3,5] |
其中“支持标量”的操作符,不仅可以支持标量间或者张量间的常规计算,也能以某种方式实现标量与张量之间的混合计算,浏览文档查看
语法示例:
- 显式定义常量参数:通过列出所有元素的值来创建矩阵或向量。例如,声明一个
m×n
矩阵的语法是param matrix_name = [A_11, ..., A_1n; ...; A_m1, ..., A_mn];
,声明一个1×m
向量的语法是param vector_name = [a_1, ..., a_n];
。- 获取参数属性:可以使用
.row
和.col
来获取矩阵/向量参数的行数和列数,例如获取矩阵X
的大小。
- 获取参数属性:可以使用
param vec = [1,3,5,7,9,11];
print "Shape of vec: ({},{})." % vec.row, vec.col;
param A =[1,2,3;
4,5,6;
7,8,9];
print "Shape of A: ({},{})." % A.row, A.col;
Shape of vec: (1,6).
Shape of A: (3,3).
- 参数的索引:可通过行/列号对向量/矩阵中的元素进行索引,索引从0开始。例如,对于向量
vec
,vec[4]
或vec[0,4]
都指向向量的第五个元素;对于矩阵A
,A[i-1,j-1]
指向矩阵的第i
行第j
列元素。
param A =[1,2,3;
4,5,6;
7,8,9];
#遍历输出所有大于等于5的项
for (i,j) in (1..A.row) * (1..A.col):
if A[i-1,j-1] >= 5 then print "A[{},{}]={}"%i,j,A[i-1, j-1];
A[2,2]=5
A[2,3]=6
A[3,1]=7
A[3,2]=8
A[3,3]=9
- 使用内置函数生成常量参数:MAPL 提供了一些内置函数如
ones, zeros, identity, random
和normal
来快速生成特定类型的向量/矩阵常量。例如,ones(3,7)
创建一个3x7的全1矩阵,random(3,7)
创建一个满足[0,1]均匀分布的3x7随机矩阵。
clear model;
print "ones matrix: ones(3,7)";
param one = ones(3,7);
print one;
print "--------------";
print "zeros matrix: zeros(3,7)";
param zero = zeros(3,7);
print zero;
print "--------------";
print "identity matrix: identity(4,4)";
param E = identity(4,4);
print E;
print "--------------";
print "random matrix: random(shape=(3,7), seed=12345)";
param X = random(shape=(3,7), seed=123456);
print X;
print "--------------";
print "normal matrix, (mu,sigma)=(-10,10): normal(shape=(3,7), mu=-10, sigma=10, seed=12345);";
param Y = normal(shape=(3,7), mu=-10, sigma=10, seed=123456);
print Y;
ones matrix: ones(3,7)
[[1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1]]
--------------
zeros matrix: zeros(3,7)
[[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0]]
--------------
identity matrix: identity(4,4)
[[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]]
--------------
random matrix: random(shape=(3,7), seed=12345)
[[0.51491, 0.89813, 0.70582, 0.77883, 0.93162, 0.62877, 0.33987],
[0.21579, 0.11833, 0.08322, 0.38544, 0.96056, 0.94246, 0.35274],
[0.17555, 0.15881, 0.95409, 0.14046, 0.03238, 0.84024, 0.81065]]
--------------
normal matrix, (mu,sigma)=(-10,10): normal(shape=(3,7), mu=-10, sigma=10, seed=12345);
[[ -0.47484, -9.64320, -0.25816, -2.80899, -8.15235, -3.80674, -21.38680],
[-16.41576, -5.56788, -11.10240, -11.66778, -4.98887, -13.55322, -13.37890],
[ -4.19033, -0.16199, -9.42198, -2.38052, -17.12964, -14.43160, -19.74602]]
- 从CSV文件中读取矩阵形式的常量参数:使用 read_csv 函数可以从CSV文件中读取数据并自动将其视为一个常量矩阵或向量。例如,
param X := read_csv("iris.data", use_col="0,1,2,3", skip =1);
会从iris.data
文件中读取前四列数据作为矩阵X。然后可以查询矩阵的形状信息,并通过索引访问其中的元素。
X,X,X,X,Y
5.1,3.5,1.4,0.2,1
4.9,3.0,1.4,0.2,1
4.7,3.2,1.3,0.2,1
4.6,3.1,1.5,0.2,1
5.0,3.6,1.4,0.2,1
5.7,3.0,4.2,1.2,-1
5.7,2.9,4.2,1.3,-1
6.2,2.9,4.3,1.3,-1
5.1,2.5,3.0,1.1,-1
5.7,2.8,4.1,1.3,-1
param X:= read_csv("iris.data", use_col="0,1,2,3", skip =1);
param y:= read_csv("iris.data", use_col=4,skip =1);
print "Shape of X is: ({},{})." % X.row, X.col;
print "Shape of y is: ({},{})." % y.row, y.col;
print "X[0,0] is {:.1f}" % X[0, 0];
print "X[9,2]*y[5] is {:.1f}" % X[9, 2] * y[5];
Shape of X is: (10,4).
Shape of y is: (10,1).
X[0,0] is 5.1
X[9,2]*y[5] is -4.1
表达式的计算示例(向量及矩阵乘法)更多示例:
param a = [1,2,3,4,5,6,7,8,9,10];
param b = [10,9,8,7,6,5,4,3,2,1];
print "a * b' is: ", a * b';
print "b'*a is:";
print b'*a;
a * b' is: 220
b'*a is:
[[ 10, 20, 30, 40, 50, 60, 70, 80, 90, 100],
[ 9, 18, 27, 36, 45, 54, 63, 72, 81, 90],
[ 8, 16, 24, 32, 40, 48, 56, 64, 72, 80],
[ 7, 14, 21, 28, 35, 42, 49, 56, 63, 70],
[ 6, 12, 18, 24, 30, 36, 42, 48, 54, 60],
[ 5, 10, 15, 20, 25, 30, 35, 40, 45, 50],
[ 4, 8, 12, 16, 20, 24, 28, 32, 36, 40],
[ 3, 6, 9, 12, 15, 18, 21, 24, 27, 30],
[ 2, 4, 6, 8, 10, 12, 14, 16, 18, 20],
[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]
一个案例代码示例:
线性支持向量机(Linear Support Vector Machine, SVM)是一种广泛应用于模式识别、分类以及回归问题的监督学习算法。SVM的核心思想是寻找一个最优的超平面,用以划分不同类别的数据点,同时最大化各类数据点到该超平面的最小间隔(margin)。
代码如下:
# 1.读取iris数据
param X:= read_csv("$data_path/iris.data", use_col="0,1,2,3");
param y:= read_csv("$data_path/iris.data", use_col=4);
param m = X.row;
param n = X.col;
# 2.LinearSVM问题建模
param rho = 0.2;
var w(n) >= -1 <= 1; # Bounded Model Parameter
var eps(m) >= 0;
minimize
w' * w + rho * sum(eps);
s.t.
eps >= 1 - X*w.*y;
# 3.调用开源求解器Ipopt求解
option solver ipopt;
solve;
# 4.验证并分析结果
param total_loss = rho * ones(1, m) * eps + w'*w;
param prec = 1/m * sum{i in 0..m-1}
if (sum{j in 0..n-1} (w[j]*X[i, j])) * y[i] > 0 then 1 else 0 end;
print "(Objective, Precision): ({:.2f}, {:.1f})" % total_loss, prec;
结果查看可浏览文档,介绍更全面!