创建和初始化矩阵和向量
有若干种方式声明和初始化矩阵和向量。可以根据用途将其分为若干种类别。
- 声明时不指定大小
- 声明时指定大小
- 声明时包含初始化
- 静态创建方法
- 非静态(重新)配置和初始化方法
最简单的创建方法是不指定大小的声明,即不为数据分配内存。对于这种情况,只需指定变量的类型和名称:
matrix matrix_a; // matrix of type double
matrix<double> matrix_a1; // double type matrix inside function or class templates
matrix<float> matrix_a2; // float matrix
vector vector_v; // vector of type double
vector<double> vector_v1; // another notation of a double-type vector creation
vector<float> vector_v2; // vector of type float
|
然后你可以更改创建的对象的大小,并以所需的值填充。它们也可用于内置矩阵和向量方法以获取计算结果。所有这些方法将在本章的各节中分组讨论。
你可以在指定大小的情况下声明矩阵或向量。这将分配内存并不进行任何初始化。对于这种情况,在圆括号中的变量名称后面,指定大小(对于矩阵,第一个是行数,第二个是列数):
matrix matrix_a(128, 128); // you can specify as parameters
matrix<double> matrix_a1(nRows, nCols); // both constants and variables
matrix<float> matrix_a2(nRows, 1); // analog of column vector
vector vector_v(256);
vector<double> vector_v1(nSize);
vector<float> vector_v2(nSize +16); // expression as a parameter
|
创建对象的第三种方法是带初始化的声明。在此情况下,矩阵和向量的大小由花括号中指示的初始化系列确定:
matrix matrix_a = {{0.1, 0.2, 0.3}, {0.4, 0.5, 0.6}};
matrix<double> matrix_a1 =matrix_a; // must be matrices of the same type
matrix<float> matrix_a2 = {{1, 2}, {3, 4}};
vector vector_v = {-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5};
vector<double> vector_v1 = {1, 5, 2.4, 3.3};
vector<float> vector_v2 =vector_v1; // must be vectors of the same type
|
还有一些静态方法可创建指定大小的矩阵和向量并以某种方式进行初始化(特别是针对某种规范形式)。以下列出了所有这些方法,且具有类似的原型(向量和矩阵的唯一差别是没有第二维度)。
static matrix<T> matrix<T>::Eye∫Tri(const ulong rows, const ulong cols, const int diagonal = 0);
static matrix<T> matrix<T>::Identity∫Ones∫Zeros(const ulong rows, const ulong cols);
static matrix<T> matrix<T>::Full(const ulong rows, const ulong cols, const double value);
- Eye 构造一个在指定对角线上为 1、其余位置为 0 的矩阵
- Tri 构造一个在指定对角线及其下方为 1、其余位置为 0 的矩阵
- Identity 构造一个指定大小的单位矩阵
- Ones 构造一个以 1 填充的矩阵(或向量)
- Zeros 构造一个以 0 填充的矩阵(或向量)
- Full 构造一个所有元素均以给定值填充的矩阵(或向量)
如果必要,你可以将任何现有矩阵转换为一个单位矩阵,并应为该矩阵应用一个非静态方法 Identity(无参数)。
我们来以实操的方式演示这些方法:
matrix matrix_a = matrix::Eye(4, 5, 1);
matrix<double> matrix_a1 = matrix::Full(3, 4, M_PI);
matrixf matrix_a2 = matrixf::Identity(5, 5);
matrixf<float> matrix_a3 = matrixf::Ones(5, 5);
matrix matrix_a4 = matrix::Tri(4, 5, -1);
vector vector_v = vector::Ones(256);
vectorf vector_v1 = vector<float>::Zeros(16);
vector<float> vector_v2 = vectorf::Full(128, float_value);
|
此外,还有以下非静态方法可以用给定值初始化矩阵/向量:Init 和 Fill。
void matrix<T>::Init(const ulong rows, const ulong cols, func_reference rule = NULL, ...)
void matrix<T>::Fill(const T value)
Init 方法的一个重要优势(构造函数也具备)是能够在参数中指定一个初始化函数,用于根据给定规则填充矩阵/向量的元素(参见下面的示例)。
可通过在 rules 参数中指定不带引号的标识符(这不是 typedef (*pointer)(...) 意义上的指针,也不是具有名称的字符串),将对该函数的引用传递到大小之后。
该初始化函数的第一个参数必须包含对被填充对象的引用,并且还可以具有附加参数:在此情况下,它们的值被传递给 Init 或传递给函数引用之后的一个构造函数。如果 rule 链接未指定,则将直接创建一个指定维数的矩阵。
Init 方法还允许更改矩阵配置。
我们使用几个简短例子来了解上述内容。
matrix m(2, 2);
m.Fill(10);
Print("matrix m \n", m);
/*
matrix m
[[10,10]
[10,10]]
*/
m.Init(4, 6);
Print("matrix m \n", m);
/*
matrix m
[[10,10,10,10,0.0078125,32.00000762939453]
[0,0,0,0,0,0]
[0,0,0,0,0,0]
[0,0,0,0,0,0]]
*/
|
这里的 Init 方法用于调整已经初始化的矩阵的大小,结果新元素被填充了随机值。
下面的函数以指数级增加的数字填充矩阵。
template<typename T>
void MatrixSetValues(matrix<T> &m, const T initial = 1)
{
T value = initial;
for(ulong r = 0; r < m.Rows(); r++)
{
for(ulong c = 0; c < m.Cols(); c++)
{
m[r][c] = value;
value *= 2;
}
}
}
|
然后它可用于创建矩阵。
void OnStart()
{
matrix M(3, 6, MatrixSetValues);
Print("M = \n", M);
}
|
执行结果为:
M =
[[1,2,4,8,16,32]
[64,128,256,512,1024,2048]
[4096,8192,16384,32768,65536,131072]]
|
在此情况下,构造函数调用时未在函数标识符后指定初始化函数的参数值,因此使用默认值 (1)。但是我们可以为相同的 MatrixSetValues 传递一个初始值 -1,其将以一个负行填充矩阵。
matrix M(3, 6, MatrixSetValues, -1);
|