2026a

# 数学


# 数组复制

M 语言

在 M 语言中,将数组赋值给另一个变量时,会发生复制。

A = [1,2,3];
B = A;
A(1) = 10;
B(1)
ans =

     1

Julia 语言

在 Julia 语言中,将数组赋值给另一个变量时,不会发生复制。

A = [1,2,3];
B = A;
A[1] = 10;
B[1]
10

根据结果可以发现,B 的第一个值随着 A 的第一个值改动而改动,所以需要使用 copy 函数进行数组复制。

A = [1,2,3];
B = copy(A);
A[1] = 10;
B[1]
1

# 数组赋值

M 语言

如果要对不连续索引赋值,需要先创建位置向量变量。

A = [1 2;3 4];
Ind = [1,3,4];
A(Ind) = [1.5,9.5,11.5]
ans =

    1.5000    9.5000
    3.0000   11.5000

Julia 语言

如果是要对数组中的不连续的坐标进行赋值,则可以使用传入向量或位置索引方式进行赋值。对矩阵 A 中的第一个、第三个、第四个数据赋值。

A = [1.0 2.0;3.0 4.0];
A[[1,3,4]] = [1.5,9.5,11.5]
A
2×2 Matrix{Float64}:
 1.5   9.5
 2.5  11.5

数组赋值和数组索引息息相关,由于 Syslab 中的大部分数组均为动态数组,所以能够被索引的坐标均可执行赋值操作。

# 数组索引

在基础用法的第 2 节中提到了数组索引的基础用法,本小节针对自动填充数组、删除数组值、删除行或列功能进行讲解。

# 自动填充数组

M 语言

在 M 语言中,允许对数组长度以外的部分进行索引和赋值,并在未赋值的部分补充 0。

a = [1 2 3;4 5 6;7 8 9];
a(:,4) = zeros(3,1)
a =

     1     2     3     0
     4     5     6     0
     7     8     9     0
c = [1 2 3;4 5 6;7 8 9];
c(4,:) = zeros(1,3)
c =

    1     2     3
    4     5     6
    7     8     9
    0     0     0

Julia 语言

在 Syslab 中,数组创建后各维度的长度均已确定,索引时如果超出各维度最大范围,则会引发错误,故而并不能通过对超出最大范围的坐标进行赋值来实现自动填充数组。可以使用以下 2 种方法实现数组填充:

  1. 通过 hcat、vcat 方式进行矩阵拼接。

    a = [1 2 3;4 5 6;7 8 9]
    b = zeros(3,1)
    res1 = hcat(a,b)
    
    3×4 Matrix{Float64}:
    1.0  2.0  3.0  0.0
    4.0  5.0  6.0  0.0
    7.0  8.0  9.0  0.0
    
    c = zeros(1,3)
    res2 = vcat(a,c)
    
    4×3 Matrix{Float64}:
    1.0  2.0  3.0
    4.0  5.0  6.0
    7.0  8.0  9.0
    0.0  0.0  0.0
    

    注意

    使用 hcat、vcat 函数时,需要确保拼接的维度长度一致。

  2. 预分配内存,使用 zeros、ones 等函数创建最终所需要的矩阵大小,然后利用数组赋值进行填充。

    A = [1 2;4 5]
    B = [1 3;5 7]
    res1 = zeros(4,4)
    res1[1:2,1:2] = A
    res1[3:4,3:4] = B
    res1
    
    4×4 Matrix{Float64}:
    1.0  2.0  0.0  0.0
    4.0  5.0  0.0  0.0
    0.0  0.0  1.0  3.0
    0.0  0.0  5.0  7.0
    

# 删除数组值

M 语言

在 M 语言中,允许通过对索引数组赋值为空 ([]) 的方式删除数组值。

A = [1 2 3 ; 4 5 6;7 8 9];
A(:,2) = []
A =

     1     3
     4     6
     7     9
A = rand(1024,1024);
A(:,1:3:1024) = [];
size(A)
ans =

        1024         682

Julia 语言

在 Syslab 中,由于数组维度在创建时被固定,故而并不支持对索引数组赋值为空的方式删除数组值这类操作。需要利用数组索引的方式重新创建数组。

剔除矩阵 A 的第二列,并保留变量名 A。

A = [1 2 3 ; 4 5 6;7 8 9];
A = A[:,[1,3]]
A
3×2 Matrix{Int64}:
 1  3
 4  6
 7  9

如果数组维度较大或需要剔除的维度较多,可以使用 setdiff、filter 等集合相关操作,找到需要保留的坐标值,并进行索引。

A = rand(1024,1024)
index = setdiff(1:1024,1:3:1024)
A = A[:,index]
size(A)
(1024, 682)

# 矩阵操作

M 语言

在 M 语言中,许多矩阵操作函数默认沿矩阵第一维计算,同时第二个形参控制计算维度方向,如 sum 函数:

A = magic(4);
sum(A)
ans =

    34    34    34    34

将 sum 函数的第二个参数指定为 2 来计算行总和。

A = magic(4);
sum(A,2)
ans =

    34
    34
    34
    34

Julia 语言

在 Syslab 中,针对幻方矩阵 A = magic(4),如果沿任何行或列求和,或者沿两条主对角线中的任意一条求和,您将始终得到相同数字。

using TyMath
A = magic(4)
sum(A,dims = 1)
1×4 Matrix{Int64}:
 34  34  34  34

将 sum 函数的关键字参数 dims 指定为 2 来计算行总和。

sum(A,dims = 2)
4×1 Matrix{Int64}:
 34
 34
 34
 34

# 重新排列数组

Syslab 中的许多函数都可以提取现有数组的元素,然后按照不同的形状或顺序放置。这样有助于预处理数据,便于之后进行计算或分析。

# 转置和翻转

M 语言

A = magic(3)
A =

     8     1     6
     3     5     7
     4     9     2
B = A'
B =

     8     3     4
     1     5     9
     6     7     2

flipud 上下翻转矩阵的行,fliplr 左右翻转矩阵的列。

C = flipud(A)
C =

     4     9     2
     3     5     7
     8     1     6
D = fliplr(A)
D =

     6     1     8
     7     5     3
     2     9     4

Julia 语言

线性代数中常见的任务是转置矩阵,即将矩阵的行变成列,将列变成行。要实现此目的,可以使用 transpose 函数或 ' 运算符。

创建一个 3×3 矩阵并计算其转置。

using TyMath
A = magic(3)
3×3 Matrix{Int64}:
 8  1  6
 3  5  7
 4  9  2
B = transpose(A)
3×3 transpose(::Matrix{Int64}) with eltype Int64:
 8  3  4
 1  5  9
 6  7  2
B = A'
3×3 adjoint(::Matrix{Int64}) with eltype Int64:
 8  3  4
 1  5  9
 6  7  2

注意

transpose 函数是对矩阵转置,并非共轭转置,matlab 和 syslab 的 ' 是共轭转置。

reverse 函数搭配 dims 关键字参数实现翻转功能,dims = 1 上下翻转矩阵的行,dims = 2 左右翻转矩阵的列。

C =reverse(A,dims = 1)
3×3 Matrix{Int64}:
 4  9  2
 3  5  7
 8  1  6
D =reverse(A,dims = 2)
3×3 Matrix{Int64}:
 6  1  8
 7  5  3
 2  9  4

# 矩阵旋转

rot90 函数可以将矩阵逆时针旋转 90 度。

M 语言

A = [1 2; 3 4]
A =

   1 2 
   3 4
B = rot90(A)
B =

     2     4
     1     3

如果再旋转 3 次(使用第二个参量指定旋转次数),最后将得到原始矩阵 A。

C = rot90(B,3)
C =

     1     2
     3     4

Julia 语言

rotl90 函数可以将矩阵逆时针旋转 90 度,rotr 函数则是将矩阵顺时针旋转 90 度。

A = [1 2; 3 4]
2×2 Matrix{Int64}:
 1  2
 3  4
B = rotl90(A)
2×2 Matrix{Int64}:
 2  4
 1  3

如果再旋转 3 次(使用第二个参量指定旋转次数),最后将得到原始矩阵 A。

C = rotl90(B,3)
2×2 Matrix{Int64}:
 1  2
 3  4

# 排序

M 语言

A = magic(4)
A =

    16     2     3    13
     5    11    10     8
     9     7     6    12
     4    14    15     1
B = sort(A)
B =

     4     2     3     1
     5     7     6     8
     9    11    10    12
    16    14    15    13

按降序对每一行进行排序。第二个参量值 2 指定您希望逐行排序。

C = sort(A,2,'descend')
C =

    16    13     3     2
    11    10     8     5
    12     9     7     6
    15    14     4     1

要整行排序,请使用 sortrows 函数。例如,根据第一列中的元素按升序对 A 的各行排序。行的位置发生变化,但每一行中元素的顺序不变。

D = sortrows(A)
D =

     4    14    15     1
     5    11    10     8
     9     7     6    12
    16     2     3    13

Julia 语言

对数组中的数据进行排序也是一项实用功能,Syslab 提供了几种排序方法。例如,sort 函数可以按升序 或降序对矩阵的每一行或每一列中的元素进行排序。创建矩阵 A,并按升序对 A 的每一列进行排序。

using TyMath
A = magic(4)
4×4 Matrix{Int64}:
 16   2   3  13
  5  11  10   8
  9   7   6  12
  4  14  15   1
B = sort(A,dims = 1)
4×4 Matrix{Int64}:
  4   2   3   1
  5   7   6   8
  9  11  10  12
 16  14  15  13

关键字参数 rev = true 指定按降序对每一行进行排序。关键字参数 dims 指定为 2 逐行排序。

C = sort(A,dims = 2,rev = true)
4×4 Matrix{Int64}:
 16  13  3  2
 11  10  8  5
 12   9  7  6
 15  14  4  1

# 查找满足条件的数组元素

# 应用单个条件

M 语言

rng("default") 
A = randi(15,5)
A =

    13     2     3     3    10
    14     5    15     7     1
     2     9    15    14    13
    14    15     8    12    15
    10    15    13    15    11

使用小于号关系运算符 < 确定 A 中的哪些元素小于 9。将结果存储在 B 中。

B = A < 9
B =

  5×5 logical 数组

   0   1   1   1   0
   0   1   0   1   1
   1   0   0   0   0
   0   0   1   0   0
   0   0   0   0   0

结果为一个逻辑矩阵。B 中的每个值均为逻辑值 1 (true) 或逻辑值 0 (false),表示 A 的对应元素是否满足条件 A < 9。例如,A(1,1) 为 13,因此 B(1,1) 为逻辑值 0 (false)。但是,A(1,2) 为 2,因此 B(1,2) 为逻辑值 1 (true)。

虽然 B 包含有关 A 中哪些元素小于 9 的信息,但 B 不会指出这些元素的具体值是多少。您可以使用 B 创 建 A 的索引,而不必逐元素比较这两个矩阵。

A(B)
ans =

     2
     2
     5
     3
     8
     3
     7
     1

结果为一个由 A 中小于 9 的元素组成的列向量。由于 B 为逻辑矩阵,因此该运算称为逻辑索引。在本例中,用作索引的逻辑数组与它正在索引的数组的大小相同,但这不是必需的。

某些问题需要符合条件的数组元素的位置信息,而非其实际值。在此示例中,您可以使用 find 函数查找 A 中小于 9 的所有元素。

I = find(A < 9)
I =

     3
     6
     7
    11
    14
    16
    17
    22

Julia 语言

要应用单个条件,请首先创建一个 5×5 矩阵,该矩阵包含介于 1 和 15 之间的随机整数。将随机数生成器重置为默认状态,以实现可再现性。

using TyMath
Rng = MT19937ar(5489)
A = randi(Rng,15,5,5)
5×5 Matrix{Int64}:
 13   2   3   3  10
 14   5  15   7   1
  2   9  15  14  13
 14  15   8  12  15
 10  15  13  15  11

使用小于号关系运算符 < 确定 A 中的哪些元素小于 9。由于是针对矩阵中每个元素的计算,故而还是需要 (.) 运算符进行向量化处理。将结果存储在 B 中,返回为 Bool 类型数组。

B = A .< 9
5×5 BitMatrix:
 0  1  1  1  0
 0  1  0  1  1
 1  0  0  0  0
 0  0  1  0  0
 0  0  0  0  0

结果为一个 Bool 类型矩阵。B 中的每个值均为逻辑值 true 或逻辑值 false,表示 A 的对应元素是否满 足条件 A .< 9。例如,A[1,1] 为 13,因此 B[1,1] 为 false。但是,A[1,2] 为 2,因此 B[1,2] 为 true。

虽然 B 包含有关 A 中哪些元素小于 9 的信息,但 B 不会指出这些元素的具体值是多少。您可以使用 B 创建 A 的索引,而不必逐元素比较这两个矩阵。

A[B]
8-element Vector{Int64}:
 2
 2
 5
 3
 8
 3
 7
 1

结果为一个由 A 中小于 9 的元素组成的向量。由于 B 为 Bool 类型矩阵,因此该运算称为逻辑索引。在本例中,用作索引的 Bool 类型数组与它正在索引的数组的大小相同。

某些问题需要符合条件的数组元素的位置信息,而非其实际值。在此示例中,您可以使用 findall 函数查找 A 中小于 9 的所有元素。

I = findall(A .< 9)
8-element Vector{CartesianIndex{2}}:
 CartesianIndex(3, 1)
 CartesianIndex(1, 2)
 CartesianIndex(2, 2)
 CartesianIndex(1, 3)
 CartesianIndex(4, 3)
 CartesianIndex(1, 4)
 CartesianIndex(2, 4)
 CartesianIndex(2, 5)

findall 函数还可以使用函数式编程的调用方法,第一个参数传入标量计算结果返回为 Bool 类型的函数,第二个参数传入数组,可以避免先计算 Bool 类型数组再循环找到满足条件的过程,而是一次循环根据目标找到结果,更高效。

I = findall(<(9),A)
8-element Vector{CartesianIndex{2}}:
 CartesianIndex(3, 1)
 CartesianIndex(1, 2)
 CartesianIndex(2, 2)
 CartesianIndex(1, 3)
 CartesianIndex(4, 3)
 CartesianIndex(1, 4)
 CartesianIndex(2, 4)
 CartesianIndex(2, 5)

结果为一个由坐标向量组成的向量。每个索引描述 A 中一个小于 9 的元素的位置,因此实际上 A[I] 与 A[B] 返回的结果相同。差别在于 A[B] 使用索引,而 A[I] 使用线性索引。

# 应用多个条件

M 语言与 Julia 语言的 and、or 和 not 操作符不同。

操作符 M 语言 Julia 语言
and & &&
or | ||
not ~ !

M 语言

在 M 语言中,使用逻辑 and 运算符(由 & 表示)指定两个条件:元素必须小于 9 且大于 2。将这些条件指定为逻辑索引,以查看符合两个条件的元素。

A(A < 9 & A > 2)
ans =

     5
     3
     8
     3
     7

结果为 A 中同时符合这两个条件的元素的列表。务必使用单独的语句指定每个条件,并用逻辑运算符连接起来。例如,无法使用 A(2<A | A < 9)。

接下来,查找 A 中小于 9 且为偶数的元素。

A(A < 9 & ~mod(A,2))
ans =

     2
     2
     8

结果为 A 中小于 9 的所有偶数元素的列表。使用逻辑 not 运算符 ~ 将矩阵 mod(A,2) 转换为逻辑矩阵, 并在可被 2 整除(即偶数)的元素位置放置逻辑值 1 (true)。最后,查找 A 中小于 9、为偶数且不等于 2 的元素。

A(A < 9 & ~mod(A,2) & A ~=2)
ans =

     8

结果 8 小于 9,是偶数且不等于 2。该元素是 A 中符合所有三个条件的唯一元素。 使用 find 函数获取等于 8 的元素(符合这些条件)的索引。

find(A < 9 & ~mod(A,2) & A ~= 2)
I =

     14

结果指示 A(14) = 8。

Julia 语言

在 Julia 中,这些运算符要求输入为 Bool 类型,如果输入为数组的话,需要使用 (.) 运算符或 (@.) 运算符进行向量化处理。首先,使用逻辑 and 运算符(由 && 表示)指定两个条件:元素必须小于 9 且大于 2。将这些条件指定为逻辑索引,以查看符合两个条件的元素。

A[A .< 9 .&& A .> 2]
5-element Vector{Int64}:
 5
 3
 8
 3
 7

结果为 A 中同时符合这两个条件的元素的列表。务必使用单独的语句指定每个条件,并用逻辑运算符连接起来。

接下来,查找 A 中小于 9 且为偶数的元素。注意,在 Syslab 中,取反符号是 (!),向量化取反符号请使用 (.!)。

A[A .< 9 .&& .!mod.(A,2)]
ERROR: MethodError: no method matching !(::Int64)

上述代码运行报错原因为,mod 函数返回 Int 数组,而逻辑运算符和取反符要求输入为 Bool 类型。可以使用 iseven 函数计算是否为偶数。

A[A .< 9 .&& iseven.(A)]
3-element Vector{Int64}:
 2
 2
 8

最后,查找 A 中小于 9、为偶数且不等于 2 的元素。

A[A .<9 .&& iseven.(A) .&& A .!=2]
1-element Vector{Int64}:
 8

结果 8 小于 9,是偶数且不等于 2。该元素是 A 中符合所有三个条件的唯一元素。 使用 findall 函数获取等于 8 的元素(符合这些条件)的索引。构造一个匿名函数作为第一个参数。

findall(x -> (x <9 && iseven(x) && x !=2),A)
1-element Vector{CartesianIndex{2}}:
 CartesianIndex(4, 3)

结果指示 A[ans] = 8。

# 替换满足条件的值

M 语言

将 A 中大于 10 的所有值替换为数值 10。

A(A>10) = 10
A =

    10     2     3     3    10
    10     5    10     7     1
     2     9    10    10    10
    10    10     8    10    10
    10    10    10    10    10

结果为 A 中同时符合这两个条件的元素的列表。务必使用单独的语句指定每个条件,并用逻辑运算符连接 起来。例如,无法使用 A(2<A | A < 9)。 接下来,查找 A 中小于 9 且为偶数的元素。

A(A < 9 & ~mod(A,2))
ans =

     2
     2
     8

然后,将 A 中不等于 10 的所有值替换为 NaN 值。

A(A~=10) = NaN
A =

    10   NaN   NaN   NaN    10
    10   NaN    10   NaN   NaN
   NaN   NaN    10    10    10
    10    10   NaN    10    10
    10    10    10    10    10

最后,将 A 中的所有 NaN 值替换为 0,并对 A、~A 应用逻辑 not 运算符。

A(isnan(A)) = 0; 
C = ~A
C =

  5×5 logical 数组

   0   1   1   1   0
   0   1   0   1   1
   1   1   0   0   0
   0   0   1   0   0
   0   0   0   0   0

Julia 语言

有时,同时更改多个现有数组元素的值会很有用。将逻辑索引与简单的赋值语句一起使用,可替换数组中符合条件的值。

例如,将 A 中大于 10 的所有值替换为数值 10。

A[A.>10] .= 10
A
5×5 Matrix{Int64}:
 10   2   3   3  10
 10   5  10   7   1
  2   9  10  10  10
 10  10   8  10  10
 10  10  10  10  10

然后,将 A 中不等于 10 的所有值替换为 NaN 值。

A[A.!=10] .= NaN
ERROR: InexactError: Int64(NaN)

上述用法 Syslab 会报错,原因为 A 是 Int 数组,而 NaN 则是 Float 类型,传入 NaN 会导致原本数组中数据类型发生更改,这并不被允许。故而需要对 A 进行转换。

A = float(A)
A[A.!=10] .= NaN
A
5×5 Matrix{Float64}:
  10.0  NaN    NaN    NaN     10.0
  10.0  NaN     10.0  NaN    NaN
  NaN    NaN     10.0   10.0   10.0
  10.0   10.0  NaN     10.0   10.0
  10.0   10.0   10.0   10.0   10.0

最后,将 A 中的所有 NaN 值替换为 0。

A[isnan.(A)] .= 0
A
 5×5 Matrix{Float64}:
 10.0   0.0   0.0   0.0  10.0       
 10.0   0.0  10.0   0.0   0.0       
  0.0   0.0  10.0  10.0  10.0       
 10.0  10.0   0.0  10.0  10.0       
 10.0  10.0  10.0  10.0  10.0 

# 多维数组

# 创建多维数组

M 语言

要创建多维数组,可以先创建二维矩阵,然后再进行扩展。例如,首先定义一个 3×3 矩阵,作为三维数组中的第一页。

A = [1 2 3; 4 5 6; 7 8 9]
A =

     1     2     3
     4     5     6
     7     8     9

现在添加第二页。要完成此操作,可将另一个 3×3 矩阵赋给第三个维度中的索引值 2。语法 A(:,:,2) 在第 一个和第二个维度中使用冒号,以在其中包含赋值表达式右侧的所有行和所有列。

A(:,:,2) = [10 11 12; 13 14 15; 16 17 18]
A(:,:,1) =

     1     2     3
     4     5     6
     7     8     9


A(:,:,2) =

    10    11    12
    13    14    15
    16    17    18

cat 函数可用于构造多维数组。例如,在 A 后以串联方式添加第三页,由此创建一个新的三维数组 B。第一个参量指示要沿哪一个维度进行串联。

B = cat(3,A,[3 2 1; 0 9 8; 5 3 7])
B(:,:,1) =

     1     2     3
     4     5     6
     7     8     9


B(:,:,2) =

    10    11    12
    13    14    15
    16    17    18


B(:,:,3) =

     3     2     1
     0     9     8
     5     3     7

快速扩展多维数组的另一种方法是将一个元素赋给一整页。例如,为数组 B 添加第四页,其中包含的值全部为零。

B(:,:,4) = 0
B(:,:,1) =

     1     2     3
     4     5     6
     7     8     9


B(:,:,2) =

    10    11    12
    13    14    15
    16    17    18


B(:,:,3) =

     3     2     1
     0     9     8
     5     3     7


B(:,:,4) =

     0     0     0
     0     0     0
     0     0     0

Julia 语言

要创建多维数组,可以先创建二维矩阵,然后再进行扩展。例如,首先定义一个 3×3 矩阵,作为三维数组中的第一页。

A1 = [1 2 3; 4 5 6; 7 8 9]
3×3 Matrix{Int64}:
 1  2  3
 4  5  6
 7  8  9

现在添加第二页。在 Syslab 中,需要提前分配内存,并不允许对未知位置进行索引,所以可以使用 zeros 函数提前创建 3 × 3 × 2 大小的数组。

A = zeros(3,3,2)
A[:,:,1] = A1
A[:,:,2] = [10 11 12; 13 14 15; 16 17 18]
A
3×3×2 Array{Float64, 3}:
[:, :, 1] =
 1.0  2.0  3.0
 4.0  5.0  6.0
 7.0  8.0  9.0

[:, :, 2] =
 10.0  11.0  12.0
 13.0  14.0  15.0
 16.0  17.0  18.0

cat 函数可用于构造多维数组。例如,在 A 后以串联方式添加第三页,由此创建一个新的三维数组 B。关键字参数指示要沿哪一个维度进行串联。

B = cat(A,[3 2 1; 0 9 8; 5 3 7],dims = 3)
[:, :, 1] =
 1.0  2.0  3.0
 4.0  5.0  6.0
 7.0  8.0  9.0

[:, :, 2] =
 10.0  11.0  12.0
 13.0  14.0  15.0
 16.0  17.0  18.0

[:, :, 3] =
 3.0  2.0  1.0
 0.0  9.0  8.0
 5.0  3.0  7.0

特别注意,Syslab 中并不允许自动扩展数组。

cat(B,zeros(3,3),dims = 3)
3×3×4 Array{Float64, 3}:
[:, :, 1] =
 1.0  2.0  3.0
 4.0  5.0  6.0
 7.0  8.0  9.0

[:, :, 2] =
 10.0  11.0  12.0
 13.0  14.0  15.0
 16.0  17.0  18.0

[:, :, 3] =
 3.0  2.0  1.0
 0.0  9.0  8.0
 5.0  3.0  7.0

[:, :, 4] =
 0.0  0.0  0.0
 0.0  0.0  0.0
 0.0  0.0  0.0

# 操作数组

M 语言

M(:,:,1) = [1 2 3; 4 5 6; 7 8 9]; 
M(:,:,2) = [0 5 4; 2 7 6; 9 3 1]
M(:,:,1) =

     1     2     3
     4     5     6
     7     8     9


M(:,:,2) =

     0     5     4
     2     7     6
     9     3     1

使用 permute 函数,通过在第二个参量中指定维度顺序,将每一页上的行下标和列下标交换。M 的原始行现在是列,原始列现在是行。

P1 = permute(M,[2 1 3])
P1(:,:,1) =

     1     4     7
     2     5     8
     3     6     9


P1(:,:,2) =

     0     2     9
     5     7     3
     4     6     1

同样,将 M 的行下标和列下标交换。

P2 = permute(M,[3 2 1])
P2(:,:,1) =

     1     2     3
     0     5     4


P2(:,:,2) =

     4     5     6
     2     7     6


P2(:,:,3) =

     7     8     9
     9     3     1

操作多维数组时,您可能会遇到某些数组有一个长度为 1 的多余维度。squeeze 函数可以执行另一种操作,消除长度为 1 的维度。例如,使用 repmat 函数创建一个 2×3×1×4 数组,其元素全部为 5,第三个维度的长度为 1。

A = repmat(5,[2 3 1 4])
A(:,:,1,1) =

     5     5     5
     5     5     5


A(:,:,1,2) =

     5     5     5
     5     5     5


A(:,:,1,3) =

     5     5     5
     5     5     5


A(:,:,1,4) =

     5     5     5
     5     5     5
szA = size(A)
szA =

     2     3     1     4
numdimsA = ndims(A)
numdimsA =

     4

Julia 语言

M = zeros(3,3,2)
M[:,:,1] = [1 2 3; 4 5 6; 7 8 9]; 
M[:,:,2] = [0 5 4; 2 7 6; 9 3 1];
M
3×3×2 Array{Float64, 3}:
[:, :, 1] =
 1.0  2.0  3.0
 4.0  5.0  6.0
 7.0  8.0  9.0

[:, :, 2] =
 0.0  5.0  4.0
 2.0  7.0  6.0
 9.0  3.0  1.0

使用 permutedims 函数,通过在第二个参量中指定维度顺序,将每一页上的行下标和列下标交换。M 的原始行现在是列,原始列现在是行。

P1 = permutedims(M,[2,1,3])
3×3×2 Array{Float64, 3}:
[:, :, 1] =
 1.0  4.0  7.0
 2.0  5.0  8.0
 3.0  6.0  9.0

[:, :, 2] =
 0.0  2.0  9.0
 5.0  7.0  3.0
 4.0  6.0  1.0

同样,将 M 的行下标和列下标交换。

P2 = permutedims(M,[3,2,1])
2×3×3 Array{Float64, 3}:
[:, :, 1] =
 1.0  2.0  3.0
 0.0  5.0  4.0

[:, :, 2] =
 4.0  5.0  6.0
 2.0  7.0  6.0

[:, :, 3] =
 7.0  8.0  9.0
 9.0  3.0  1.0

操作多维数组时,您可能会遇到某些数组有一个长度为 1 的多余维度。squeeze 函数可以执行另一种操作,消除长度为 1 的维度。例如,使用 repeat 函数创建一个 2×3×1×4 数组,其元素全部为 5,第三个维度的长度为 1。

A = repeat([5],2,3,1,4)
2×3×1×4 Array{Int64, 4}:
[:, :, 1, 1] =
 5  5  5
 5  5  5

[:, :, 1, 2] =
 5  5  5
 5  5  5

[:, :, 1, 3] =
 5  5  5
 5  5  5

[:, :, 1, 4] =
 5  5  5
 5  5  5
szA = size(A)
(2, 3, 1, 4)
numdimsA = ndims(A)
numdimsA = 4

# 线性代数

# 平方根

M 语言

使用 sqrt 函数可以方便地计算矩阵中每个元素的平方根。另一种方法是 A.^(1/2)。

A = [1 1 1
     1 2 3
     1 3 6];
sqrt(A)
ans =

    1.0000    1.0000    1.0000
    1.0000    1.4142    1.7321
    1.0000    1.7321    2.4495

这些按元素计算的根不同于矩阵平方根,后者计算得到的是另一个矩阵 B 以满足 A = BB。函数 sqrtm(A) 采用更精确的算法计算 A^(1/2)。sqrtm 中的 m 将此函数与 sqrt(A) 区分开来,后者与 A.^(1/2) 一样,以逐元素方式工作。

B = sqrtm(A)
B =

    0.8775    0.4387    0.1937
    0.4387    1.0099    0.8874
    0.1937    0.8874    2.2749

Julia 语言

在 Julia 语言中,sqrt 函数输入矩阵,计算的是矩阵平方根。如果计算矩阵每个元素平方根,需要使用 (.) 操作。

A = [1 1 1
     1 2 3
     1 3 6];
sqrt.(A)
3×3 Matrix{Float64}:
 1.0  1.0      1.0
 1.0  1.41421  1.73205
 1.0  1.73205  2.44949

计算矩阵平方根。

sqrt(A)
3×3 Matrix{Float64}:
 0.877485  0.438743  0.193713
 0.438743  1.00994   0.887426
 0.193713  0.887426  2.27485

# 特征值

M 语言

在 M 语言中,计算特征值分解使用 eig 函数。由于 M 语言的 nargout 机制,可以根据输出参数个数执行不同结果输出。

A = [0 -6 -1
     6 2 -16
    -5 20 -10];
lambda = eig(A)
lambda =

  -3.0710 + 0.0000i
  -2.4645 +17.6008i
  -2.4645 -17.6008i
[V,D] = eig(A)
V =

  -0.8326 + 0.0000i   0.2003 - 0.1394i   0.2003 + 0.1394i
  -0.3553 + 0.0000i  -0.2110 - 0.6447i  -0.2110 + 0.6447i
  -0.4248 + 0.0000i  -0.6930 + 0.0000i  -0.6930 + 0.0000i


D =

  -3.0710 + 0.0000i   0.0000 + 0.0000i   0.0000 + 0.0000i
   0.0000 + 0.0000i  -2.4645 +17.6008i   0.0000 + 0.0000i
   0.0000 + 0.0000i   0.0000 + 0.0000i  -2.4645 -17.6008i

Julia 语言

在 Julia 语言中,计算特征值分解使用 eigen 函数。同时提供 eigvals 和 eigvecs 函数分别计算特征值和特征向量。

A = [0 -6 -1
     6 2 -16
    -5 20 -10];
lambda = eigvals(A)
3-element Vector{ComplexF64}:
  -3.070950351248293 + 0.0im
 -2.4645248243758573 - 17.60083096447099im
 -2.4645248243758573 + 17.60083096447099im
D,V = eigen(A)
D = 3-element Vector{ComplexF64}:
  -3.070950351248293 + 0.0im
 -2.4645248243758573 - 17.60083096447099im
 -2.4645248243758573 + 17.60083096447099im

 V = 3×3 Matrix{ComplexF64}:
 -0.832608+0.0im   0.200267+0.139359im   0.200267-0.139359im
 -0.355342+0.0im  -0.211043+0.644721im  -0.211043-0.644721im
 -0.424848+0.0im  -0.693014-0.0im       -0.693014+0.0im

可以看到,在 Julia 中特征值以向量形式输出而非对角矩阵。

事实上,eigen 返回 Eigen 结构体类型。

typeof(eigen(A))
Eigen{ComplexF64, ComplexF64, Matrix{ComplexF64}, Vector{ComplexF64}}

Eigen 中包含 values 和 vectors 成员,分别对应特征值和特征向量。

# 奇异值

M 语言

在 M 语言中,使用 svd 函数计算奇异值分解,且默认为完整的奇异值分解。由于 M 语言的 nargout 机制,可以根据输出参数个数执行不同结果输出。

A = [9 4 
     6 8 
     2 7];

完整的奇异值分解为

[U,S,V] = svd(A)
U =

   -0.6105    0.7174    0.3355
   -0.6646   -0.2336   -0.7098
   -0.4308   -0.6563    0.6194


S =

   14.9359         0
         0    5.1883
         0         0

V =

   -0.6925    0.7214
   -0.7214   -0.6925       

计算精简分解。

[U,S,V] = svd(A,"econ")
U =

   -0.6105    0.7174
   -0.6646   -0.2336
   -0.4308   -0.6563


S =

   14.9359         0
         0    5.1883


V =

   -0.6925    0.7214
   -0.7214   -0.6925

Julia 语言

在 Julia 语言中,使用 svd 函数计算奇异值分解,同时提供 svdvals 计算奇异值,默认为精简分解,可以使用 full 关键字参数控制完整分解和精简分解计算。

A = [9 4 
     6 8 
     2 7];
U,S,V = svd(A,full = true)
3×3 Matrix{Float64}:
 -0.610499   0.717438   0.335519
 -0.664591  -0.233606  -0.709751
 -0.430824  -0.656286   0.619419

2-element Vector{Float64}:
 14.935916399133795
  5.188294644494102

2×2 adjoint(::Matrix{Float64}) with eltype Float64:
 -0.692538   0.721381
 -0.721381  -0.692538

计算精简分解。

U,S,V = svd(A)
U = 3×2 Matrix{Float64}:
 -0.610499   0.717438
 -0.664591  -0.233606
 -0.430824  -0.656286

S = 2-element Vector{Float64}:
 14.935916399133795
  5.188294644494102

V = 2×2 adjoint(::Matrix{Float64}) with eltype Float64:
 -0.692538   0.721381
 -0.721381  -0.692538

# 随机数

M 语言

在 M 语言中,通常使用 rng 函数全局控制随机数生成。

rng("default")
A = rand(3,1)
A =

    0.8147
    0.9058
    0.1270    

计算精简分解。

rng(1234,"mt19937ar")
A = rand(3,1)
A =

    0.1915
    0.6221
    0.4377

Julia 语言

在 Julia 语言中,使用 MT19937ar、MCG16807 等函数生成对应算法的随机数种子类型,作为参数传入 rand、randi、randn 等随机数生成器中,控制随机数生成。

Rng = MT19937ar(5489)
A = rand(Rng,3)
3-element Vector{Float64}:
 0.8147236863931789
 0.9057919370756192
 0.12698681629350606
Rng = MT19937ar(1234)
A = rand(Rng,3)
3-element Vector{Float64}:
 0.1915194503788923
 0.6221087710398319
 0.4377277390071145