Files
playbook/skills/tsl-syntax-reference/references/22_matrix_deep_dive.md
T

936 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# TSL 矩阵深水专题
文档类型:语法深水专题
是否可直接用于生成代码:是
是否含可直接照写示例:是
是否含不可照写反例:是
这一篇只讲矩阵专用语法主干:矩阵初始化、数列构造、矩阵逆/广义逆、矩阵乘除乘方、矩阵转置、矩阵拼接、矩阵尺寸与索引、矩阵遍历、子矩阵和 `mfind` 查找。它和 [12_matrix_and_collections.md](12_matrix_and_collections.md) 的分工是:`12` 讲普通数组与集合关系,这一篇讲矩阵专用构造、运算、遍历、子矩阵和矩阵查找接口。
## 本篇职责
回答”怎样直接构造全零矩阵、全一矩阵、随机矩阵、单位矩阵、空矩阵和数列数组,怎样写矩阵逆/广义逆,怎样进行矩阵乘除乘方,怎样转置矩阵,怎样拼接矩阵,怎样拿到矩阵的行数、列数、行索引和列索引,怎样遍历矩阵、取/改子矩阵,以及怎样用 `mfind` 找到或替换符合条件的单元格”。
## 智能体矩阵深水判断流程
1. 先判断要写矩阵初始化、数列构造、矩阵逆/广义逆、矩阵尺寸与索引读取、矩阵遍历、子矩阵,还是 `mfind` 查找/替换。
2. 基础数组和矩阵样比较先回看 `12_matrix_and_collections.md`
3. `mrows` / `mcols` / `msize` 等函数只照文档返回形态写。
4. 需要逐单元执行语句块时用 `matrix::begin ... end`;需要把表达式结果写回每个单元时用 `matrix ::= expression`
5. 需要遍历到嵌套数组最深层时用 `matrix:.begin ... end``matrix:.= expression`
6. 子矩阵范围使用 `row_start:row_end``:`、下标数组和列范围组合;不要把字符串键当作子矩阵范围序号。
7. `mfind(...)` 用于把符合条件的单元格转换成下标列表,或同时返回原值/替换原值。
8. 不要把列索引数组误当成单个数字。
9. 没有对应代码块时不要发明矩阵深水写法。
## 核心规则
- 矩阵初始化函数的参数规格使用 `tsl-api-reference` skill 按名查询;本页只保留矩阵行为示例和返回形态边界。
- `zeros(...)``ones(...)``rand(...)``nils(...)``eye(...)` 都可以直接用于矩阵初始化。
- `zeros(3)``ones(3)``nils(2)` 这类单参数写法可以直接生成一维结果。
- `zeros(2, 3)``rand(2, 3)` 这类双参数写法可以直接生成二维矩阵。
- `zeros(2, array("A", "B"))` 这种写法可以直接生成带列名的二维结果。
- `eye(3)` 生成的是 `3 x 3` 单位矩阵,不是一维数组。
- `->` 用来生成数列;默认步长是 `1`,也可以显式传入步长和索引数组。
- 在矩阵语境里,`!A` 是一元倒数运算符作用于矩阵的形态,用于矩阵逆/广义逆;非方阵输入可以返回行列数互换后的广义逆结果。
- `msize(matrix_value)` 返回 `array(行数, 列数)`
- `msize(matrix_value, 1)` 返回行索引数组和列索引数组。
- `mrows(matrix_value)` / `mcols(matrix_value)` 默认返回数量;第二个参数写成 `1` 时返回索引数组。
- `mrows(matrix_value, 1)` / `mcols(matrix_value, 1)` 的返回值可用于索引匹配;不要把它们当成数量。
- `matrix::begin ... end` 是矩阵遍历语句块,最多按二维遍历;语句块里可用 `mcell``mrow``mcol`
- `matrix ::= expression` 是矩阵遍历赋值,把表达式结果逐单元写回原矩阵;它不是语句块。
- `matrix:.begin ... end` 是深度遍历语句块;对嵌套数组会遍历到最深节点。
- `matrix:.= expression` 是深度遍历赋值;需要对不规则嵌套数组逐叶子节点写回时使用。
- 遍历时需要维度信息可用 `mIndexCount`;需要第 `n` 维下标可用 `mIndex(n)`
- 子矩阵提取可以写 `matrix[row_start:row_end, col_start:col_end]``matrix[:, col_range]``matrix[row_index_array, col_index_array]`
- 子矩阵赋值可以写成单个标量,也可以写成同结构矩阵;赋值矩阵应和目标子矩阵形状匹配。
- 子矩阵也可以接 `::=` 做逐单元赋值。
- `mfind(matrix)` 返回真值单元格下标;一维数组的无条件 `mfind` 返回一维下标数组。
- `mfind(matrix, condition)` 返回符合条件的下标行;二维矩阵下每行形如 `array(row_index, col_index)`
- `mfind(matrix, condition, 1)` 在每个下标行末尾追加原单元值。
- `mfind(matrix, condition, ret_value, replacement)` 会把符合条件的单元格替换成 `replacement`,并返回替换前的匹配信息。
- `mfindSparse(matrix, condition)` 用于嵌套数组或稀疏结构,返回包含完整深层路径的下标行。
## 可直接照写示例
### 矩阵初始化
代码块身份:可直接照写示例
```tsl
zeros_1d := zeros(3);
zeros_2d := zeros(2, 3);
ones_1d := ones(3);
nils_1d := nils(2);
eye_2d := eye(3);
rand_2d := rand(2, 3);
named_zeros := zeros(2, array("A", "B"));
writeLn(length(zeros_1d));
writeLn(mrows(zeros_2d));
writeLn(mcols(zeros_2d));
```
结果说明:
- `zeros(3)` 的长度是 `3`,前三个元素依次是 `0``0``0`
- `zeros(2, 3)` 的行数是 `2`、列数是 `3`,第一行前三个元素是 `0``0``0`
- `ones(3)` 的前三个元素依次是 `1``1``1`
- `nils(2)` 可直接生成长度为 `2` 的结果
- `eye(3)` 的行数是 `3`、列数是 `3`,并且 `(0,0)``(1,1)``(2,2)``1``(0,1)``(1,0)``0`
- `rand(2, 3)` 的行数是 `2`、列数是 `3`
- `zeros(2, array("A", "B"))` 的行数是 `2`、列数是 `2`,并且 `named_zeros[0]["A"]``named_zeros[0]["B"]``named_zeros[1]["A"]``named_zeros[1]["B"]` 都是 `0`
代码块身份:输出片段
```text
3
2
3
```
### `->` 数列数组初始化
默认步长为 `1`
代码块身份:可直接照写示例
```tsl
seq_default := 1 -> 5;
```
结果说明:
- `seq_default``array(1, 2, 3, 4, 5)`
显式指定步长:
代码块身份:可直接照写示例
```tsl
seq_step := array(2.5, 0.5) -> 5;
```
结果说明:
- `seq_step` 的长度是 `6`
- 六个元素依次是 `2.5``3``3.5``4``4.5``5`
显式指定索引数组:
代码块身份:可直接照写示例
```tsl
seq_indexed := array(0, 1, array("A", "B", "C", "D", "E", "F")) -> 5;
```
结果说明:
- `seq_indexed` 的长度是 `6`
- `seq_indexed["A"]``seq_indexed["F"]` 依次是 `0``1``2``3``4``5`
### 矩阵一元倒数 / 逆 / 广义逆:`!A`
方阵输入返回普通矩阵逆:
代码块身份:可直接照写示例
```tsl
matrix_value := array((1, 2), (3, 4));
inverse_value := !matrix_value;
writeLn(mrows(inverse_value));
writeLn(mcols(inverse_value));
writeLn(inverse_value[0][0]);
writeLn(inverse_value[0][1]);
writeLn(inverse_value[1][0]);
writeLn(inverse_value[1][1]);
```
代码块身份:输出片段
```text
2
2
-2
1
1.5
-0.5
```
非方阵输入返回广义逆:
代码块身份:可直接照写示例
```tsl
matrix_value := array((1, 2, 3), (4, 5, 6));
inverse_value := !matrix_value;
writeLn(mrows(inverse_value));
writeLn(mcols(inverse_value));
writeLn(inverse_value[0][0]);
writeLn(inverse_value[0][1]);
writeLn(inverse_value[1][0]);
writeLn(inverse_value[1][1]);
writeLn(inverse_value[2][0]);
writeLn(inverse_value[2][1]);
```
代码块身份:输出片段
```text
3
2
-0.944444444444444
0.444444444444444
-0.111111111111111
0.111111111111111
0.722222222222222
-0.222222222222222
```
说明:
- `array((1, 2, 3), (4, 5, 6))``2 x 3` 矩阵样数组。
- `!matrix_value` 返回的是 `3 x 2` 广义逆结果。
- 生成矩阵逆/广义逆时写 `!matrix_value`;不要把它改写成 `1 / matrix_value`
- `!` 不表示逻辑非;逻辑非回 [06_expressions_and_operators.md](06_expressions_and_operators.md) 使用 `not`
### `msize`、`mrows`、`mcols`
代码块身份:可直接照写示例
```tsl
matrix_rows := array(
("A": 1, "B": 2),
("A": 11, "B": 22),
("A": 21, "B": 32)
);
size_info := msize(matrix_rows);
size_index := msize(matrix_rows, 1);
row_count := mrows(matrix_rows);
row_index := mrows(matrix_rows, 1);
col_count := mcols(matrix_rows);
col_index := mcols(matrix_rows, 1);
```
结果说明:
- `msize(matrix_rows)` 返回 `array(3, 2)`
- `msize(matrix_rows, 1)` 的第一项是 `array(0, 1, 2)`,第二项是 `array("A", "B")`
- `mrows(matrix_rows)` 返回 `3`
- `mrows(matrix_rows, 1)` 返回 `array(0, 1, 2)`
- `mcols(matrix_rows)` 返回 `2`
- `mcols(matrix_rows, 1)` 返回 `array("A", "B")`
### 矩阵遍历:`::` 与 `::=`
`::` 执行语句块:
代码块身份:可直接照写示例
```tsl
matrix_value := array((1, 2, 3), (4, 5, 6));
sum_value := 0;
matrix_value::begin
sum_value += mcell;
end
writeLn(sum_value);
```
代码块身份:输出片段
```text
21
```
`::=` 把表达式结果逐单元写回:
代码块身份:可直接照写示例
```tsl
matrix_value := array((1, 2), (3, 4));
matrix_value ::= mrow * 10 + mcol;
writeLn(matrix_value[0][0]);
writeLn(matrix_value[0][1]);
writeLn(matrix_value[1][0]);
writeLn(matrix_value[1][1]);
```
代码块身份:输出片段
```text
0
1
10
11
```
说明:
- `mcell` 是当前单元格值。
- `mrow` 是当前行下标。
- `mcol` 是当前列下标。
- `::=` 右侧写表达式,不写 `begin ... end` 语句块。
### 深度遍历:`:.` 与 `:.=`
`:.` 会遍历到嵌套数组的最深节点:
代码块身份:可直接照写示例
```tsl
nested_value := array(10, 12, ("A": array(30), "B": 22), ("A": array(31, 32), "B": 23));
deep_count := 0;
nested_value:.begin
deep_count += 1;
end
writeLn(deep_count);
```
代码块身份:输出片段
```text
7
```
`:.=` 会把表达式结果写回最深节点:
代码块身份:可直接照写示例
```tsl
values := array(-1, 2, -3);
values:.= abs(mcell);
writeLn(values[0]);
writeLn(values[1]);
writeLn(values[2]);
```
代码块身份:输出片段
```text
1
2
3
```
### 子矩阵
按行列范围提取:
代码块身份:可直接照写示例
```tsl
matrix_value := array((1, 2, 3), (4, 5, 6), (7, 8, 9));
sub_value := matrix_value[1:2, 0:1];
writeLn(mrows(sub_value));
writeLn(mcols(sub_value));
writeLn(sub_value[0][0]);
writeLn(sub_value[0][1]);
writeLn(sub_value[1][0]);
writeLn(sub_value[1][1]);
```
代码块身份:输出片段
```text
2
2
4
5
7
8
```
按下标数组提取:
代码块身份:可直接照写示例
```tsl
matrix_value := array((1, 2, 3), (4, 5, 6), (7, 8, 9));
sub_value := matrix_value[array(0, 2), array(1, 2)];
writeLn(sub_value[0][0]);
writeLn(sub_value[0][1]);
writeLn(sub_value[1][0]);
writeLn(sub_value[1][1]);
```
代码块身份:输出片段
```text
2
3
8
9
```
子矩阵赋值:
代码块身份:可直接照写示例
```tsl
matrix_value := array((1, 2, 3), (4, 5, 6), (7, 8, 9));
matrix_value[0:1, 1:2] := array((10, 11), (12, 13));
writeLn(matrix_value[0][1]);
writeLn(matrix_value[0][2]);
writeLn(matrix_value[1][1]);
writeLn(matrix_value[1][2]);
```
代码块身份:输出片段
```text
10
11
12
13
```
子矩阵逐单元赋值:
代码块身份:可直接照写示例
```tsl
matrix_value := array((1, 2), (3, 4));
matrix_value[0:1, 0:1] ::= mrow * 10 + mcol;
writeLn(matrix_value[0][0]);
writeLn(matrix_value[0][1]);
writeLn(matrix_value[1][0]);
writeLn(matrix_value[1][1]);
```
代码块身份:输出片段
```text
0
1
10
11
```
### `mfind` 与 `mfindSparse`
一维数组无条件查找会返回一维下标数组:
代码块身份:可直接照写示例
```tsl
values := array(1, 0, 2, 0, 3);
indexes := mfind(values);
writeLn(length(indexes));
writeLn(indexes[0]);
writeLn(indexes[1]);
writeLn(indexes[2]);
```
代码块身份:输出片段
```text
3
0
2
4
```
二维矩阵按条件查找:
代码块身份:可直接照写示例
```tsl
matrix_value := array((1, 0), (2, 3));
indexes := mfind(matrix_value, mcell >= 2);
writeLn(length(indexes));
writeLn(indexes[0][0]);
writeLn(indexes[0][1]);
writeLn(indexes[1][0]);
writeLn(indexes[1][1]);
```
代码块身份:输出片段
```text
2
1
0
1
1
```
第三个参数写成 `1` 时,每行末尾追加原单元值:
代码块身份:可直接照写示例
```tsl
matrix_value := array((1, 0), (2, 3));
matches := mfind(matrix_value, mcell >= 2, 1);
writeLn(matches[0][0]);
writeLn(matches[0][1]);
writeLn(matches[0][2]);
writeLn(matches[1][0]);
writeLn(matches[1][1]);
writeLn(matches[1][2]);
```
代码块身份:输出片段
```text
1
0
2
1
1
3
```
第四个参数用于替换符合条件的单元格:
代码块身份:可直接照写示例
```tsl
matrix_value := array((1, 0), (2, 3));
matches := mfind(matrix_value, mcell >= 2, 1, 100);
writeLn(matches[0][2]);
writeLn(matches[1][2]);
writeLn(matrix_value[1][0]);
writeLn(matrix_value[1][1]);
```
代码块身份:输出片段
```text
2
3
100
100
```
`mfindSparse` 返回深层路径:
代码块身份:可直接照写示例
```tsl
nested_value := array(10, ("A": 0, "B": array(2)), 0);
indexes := mfindSparse(nested_value, mcell = 2);
writeLn(length(indexes));
writeLn(length(indexes[0]));
writeLn(indexes[0][0]);
writeLn(indexes[0][1]);
writeLn(indexes[0][2]);
```
代码块身份:输出片段
```text
1
3
1
B
0
```
### 矩阵乘法、除法、乘方:`:*`、`:/`、`:^`
`:*` 是矩阵乘法(区别于逐元素乘 `*`):
代码块身份:可直接照写示例
```tsl
a := array((1, 2), (3, 4));
b := array((5, 6), (7, 8));
element_wise := a * b;
matrix_multiply := a :* b;
writeLn("逐元素乘 (0,0):", element_wise[0][0]);
writeLn("矩阵乘 (0,0):", matrix_multiply[0][0]);
writeLn("矩阵乘 (0,1):", matrix_multiply[0][1]);
writeLn("矩阵乘 (1,0):", matrix_multiply[1][0]);
writeLn("矩阵乘 (1,1):", matrix_multiply[1][1]);
```
代码块身份:输出片段
```text
逐元素乘 (0,0): 5
矩阵乘 (0,0): 19
矩阵乘 (0,1): 22
矩阵乘 (1,0): 43
矩阵乘 (1,1): 50
```
说明:
- `*` 是逐元素乘(element-wise),`a * b``(0,0)``1 * 5 = 5`
- `:*` 是真正的矩阵乘法,`a :* b``(0,0)``1*5 + 2*7 = 19`
- 矩阵乘法要求左矩阵列数等于右矩阵行数
`:/` 是矩阵除法(等价于 `A :* !B`):
代码块身份:可直接照写示例
```tsl
a := array((1, 2), (3, 4));
b := array((2, 0), (0, 2));
result := a :/ b;
writeLn(result[0][0]);
writeLn(result[0][1]);
writeLn(result[1][0]);
writeLn(result[1][1]);
```
代码块身份:输出片段
```text
0.5
1
1.5
2
```
`:\` 是矩阵左除(等价于 `!A :* B`,常用于解线性方程组):
代码块身份:可直接照写示例
```tsl
a := array((2, 0), (0, 4));
b := array((4), (8));
result := a :\ b;
writeLn(result[0][0]);
writeLn(result[1][0]);
```
代码块身份:输出片段
```text
2
2
```
说明:
- `:\` 左除用于解线性方程组 `A * X = B`,等价于 `X = A^(-1) * B`
- **右侧 `b` 必须是列向量**(用 `array((4), (8))` 而非 `array(4, 8)`
- `a :\ b` 返回 `array((2.0), (2.0))`,即 `X` 的列向量
- 当 A 行数 > 列数时返回最小二乘解,行数 < 列数时返回一个可行解
`:^` 是矩阵乘方(`A :^ 2` 等价于 `A :* A`):
代码块身份:可直接照写示例
```tsl
a := array((1, 1), (0, 1));
pow2 := a :^ 2;
manual := a :* a;
writeLn("pow (0,0):", pow2[0][0]);
writeLn("pow (0,1):", pow2[0][1]);
writeLn("pow (1,1):", pow2[1][1]);
writeLn("manual (0,1):", manual[0][1]);
```
代码块身份:输出片段
```text
pow (0,0): 1
pow (0,1): 2
pow (1,1): 1
manual (0,1): 2
```
复合赋值算符:
代码块身份:可直接照写示例
```tsl
a := array((1, 2), (3, 4));
b := array((1, 0), (0, 1));
a :*= b;
writeLn(a[0][0]);
```
代码块身份:输出片段
```text
1
```
说明:
- `:*=``:/=``:\=``:^=` 分别是矩阵乘、除、左除、乘方的复合赋值形式
- `a :*= b` 等价于 `a := a :* b`
### 基础函数的矩阵广播与异常处理参数
多参数基础函数支持逐参数广播:
代码块身份:可直接照写示例
```tsl
data := array(1.55, 2.99, 3.85);
precision := array(-1, 0, 0);
result := RoundTo(data, precision);
writeLn(result[0]);
writeLn(result[1]);
writeLn(result[2]);
```
代码块身份:输出片段
```text
1.6
3
4
```
说明:
- `RoundTo(data, precision)` 对两个数组逐元素配对:`RoundTo(1.55, -1)``1.6``RoundTo(2.99, 0)``3.0`
- 规则:为每个参数寻找一个或一组匹配者,逐参数广播
基础函数尾部可追加异常处理参数 `ErrDefine``ErrReplace`
代码块身份:可直接照写示例
```tsl
data := array(4, -1, 9);
result := sqrt(data, 1, -999);
writeLn(tostn(result));
```
代码块身份:输出片段
```text
array(2.0,NAN,3.0)
```
说明:
- `sqrt(data, 1, -999)` 中,第二参数 `ErrDefine=1` 表示允许 NIL 值不允许错误值
- `ErrReplace=-999` 是错误位置的替换值(本例中 `-1` 的平方根为错误,但 `ErrDefine=1` 保留为 NAN
- `ErrDefine` 取值:`0`=不允许错误和 NIL、`1`=允许 NIL 不允许错误、`2`=错误值保留为原值
- `ErrReplace``ErrDefine=0``1` 时生效,用于替换错误/NIL 位置
另一个例子:
代码块身份:可直接照写示例
```tsl
data := array(1, nil, "AAA", -100);
result := abs(data, 0, -999);
writeLn(tostn(result));
```
代码块身份:输出片段
```text
array(1,-999,-999,100)
```
说明:
- `abs(data, 0, -999)` 中,`ErrDefine=0` 不允许错误和 NIL
- `nil``"AAA"` 都被替换成 `-999`
- 对于多参数基础函数,`ErrDefine``ErrReplace` 总是可以作为可选参数添加在最后
### 矩阵转置:反引号 `` ` ``
单次转置交换行列:
代码块身份:可直接照写示例
```tsl
a := array((1, 2, 3), (4, 5, 6));
transposed := `a;
writeLn("原矩阵行数:", mrows(a));
writeLn("原矩阵列数:", mcols(a));
writeLn("转置后行数:", mrows(transposed));
writeLn("转置后列数:", mcols(transposed));
writeLn("转置 (0,0):", transposed[0][0]);
writeLn("转置 (1,0):", transposed[1][0]);
writeLn("转置 (2,0):", transposed[2][0]);
```
代码块身份:输出片段
```text
原矩阵行数: 2
原矩阵列数: 3
转置后行数: 3
转置后列数: 2
转置 (0,0): 1
转置 (1,0): 2
转置 (2,0): 3
```
一维数组转置成列向量:
代码块身份:可直接照写示例
```tsl
b := array(1, 2, 3);
col_vector := `b;
writeLn("一维长度:", length(b));
writeLn("列向量行数:", mrows(col_vector));
writeLn("列向量列数:", mcols(col_vector));
```
代码块身份:输出片段
```text
一维长度: 3
列向量行数: 3
列向量列数: 1
```
双转置把一维数组变成行向量(常用于 `union` 追加行):
代码块身份:可直接照写示例
```tsl
b := array(1, 2, 3);
row_vector := ``b;
writeLn("行向量行数:", mrows(row_vector));
writeLn("行向量列数:", mcols(row_vector));
writeLn("行向量 (0,0):", row_vector[0][0]);
writeLn("行向量 (0,1):", row_vector[0][1]);
writeLn("行向量 (0,2):", row_vector[0][2]);
```
代码块身份:输出片段
```text
行向量行数: 1
行向量列数: 3
行向量 (0,0): 1
行向量 (0,1): 2
行向量 (0,2): 3
```
说明:
- `` `a `` 是后缀算符,写在矩阵变量或表达式之后
- 一维数组 `b` 转置一次成列向量(3行1列),转置两次成行向量(1行3列)
- 双转置技巧常配合 `union` 逐行追加数据
### 矩阵拼接:`union`、`&=`、`|`、`:|`
`union` 按行拼接(一维或二维):
代码块身份:可直接照写示例
```tsl
a := array(1, 2, 3);
b := array(4, 5, 6);
result := a union b;
writeLn(length(result));
writeLn(result[0]);
writeLn(result[3]);
writeLn(result[5]);
```
代码块身份:输出片段
```text
6
1
4
6
```
`&=``union` 的复合赋值形式(注意不是 `union=`):
代码块身份:可直接照写示例
```tsl
a := array(1, 2, 3);
b := array(4, 5, 6);
a &= b;
writeLn(length(a));
writeLn(a[5]);
```
代码块身份:输出片段
```text
6
6
```
`|` 按列拼接:
代码块身份:可直接照写示例
```tsl
a := array((1, 2), (3, 4));
b := array((5, 6), (7, 8));
result := a | b;
writeLn("列数:", mcols(result));
writeLn("(0,2):", result[0][2]);
writeLn("(1,3):", result[1][3]);
```
代码块身份:输出片段
```text
列数: 4
(0,2): 5
(1,3): 8
```
`:|` 对非完全矩阵补 `nil``|` 不补:
代码块身份:可直接照写示例
```tsl
a := array((1, 2, 3), (2, 3));
colon_result := a :| a;
bar_result := a | a;
writeLn("colon 结果列数:", mcols(colon_result));
writeLn("colon (1,2):", colon_result[1][2]);
writeLn("bar 结果 (1,2):", bar_result[1][2]);
```
代码块身份:输出片段
```text
colon 结果列数: 6
colon (1,2): nil
bar 结果 (1,2): 1
```
说明:
- `union` / `&=` 用于行方向拼接
- `|` / `:|` 用于列方向拼接
- 非完全矩阵(行长度不一致)用 `:|` 会在缺位补 `nil`,而 `|` 不补
- 对应的复合赋值形式:`&=`(行并)、`|=`(列并)、`:|=`(列并补 nil
## 默认生成模板
需要矩阵构造时,优先从这个最短模板开始:
代码块身份:可直接照写示例
```tsl
matrix_value := zeros(2, 3);
```
## 决策边界和禁止项
-`eye(3)` 当成一维数组。
-`!A` 当成逻辑非表达式。
-`*` 当成矩阵乘法;矩阵乘法使用 `:*`
-`:*``:/``:\``:^` 当成逐元素运算;逐元素运算使用 `*``/``^`
-`:\` 左除时,右侧用一维数组而非列向量;右侧必须用 `array((v1), (v2), ...)` 形式。
- 以为 `mrows(matrix_value, 1)``mcols(matrix_value, 1)` 返回的还是数量。
- 写带步长的 `->` 时,漏掉外层 `array(...)`
- 还在普通数组页里硬塞矩阵专用大小接口。
-`::=` 写成带 `begin ... end` 的语句块。
-`::` 期待遍历到任意深度;深度遍历使用 `:.`
- 子矩阵赋值时用形状不匹配的矩阵硬塞。
-`union` 的复合赋值写成 `union=`;正确写法是 `&=`
- 一维数组直接 `union` 期待得到二维结果;需要先双转置 ` `b `` 变成行向量。
- 在基础函数异常参数时用分号分隔;正确写法用逗号:`sqrt(data, 1, -999)`
代码块身份:反例 / 不可照写
```text
seq_value := 2.5, 0.5 -> 5;
```
上面这种写法不对。显式步长模式需要写成 `array(2.5, 0.5) -> 5`