当我看到belisarius对于具有元素均匀分布的非奇异整数矩阵生成的问题时,我正在研究Dana Randal的一篇论文“高效随机非奇异矩阵生成”。所提出的算法是递归的,并涉及生成低维矩阵并将其分配给给定的子矩阵。我使用
以下是代码:
它确实生成一个非奇异矩阵,并具有矩阵元素的均匀分布,但需要p是质数:
编辑 那么让我简化我的问题。给定矩阵
我希望这件事可以更有效率地完成,这也是我在提问中所寻求的。
Insert
和Transpose
的组合来完成它,但可能存在更有效的方法。您会如何做呢?以下是代码:
Clear[Gen];
Gen[p_, 1] := {{{1}}, RandomInteger[{1, p - 1}, {1, 1}]};
Gen[p_, n_] := Module[{v, r, aa, tt, afr, am, tm},
While[True,
v = RandomInteger[{0, p - 1}, n];
r = LengthWhile[v, # == 0 &] + 1;
If[r <= n, Break[]]
];
afr = UnitVector[n, r];
{am, tm} = Gen[p, n - 1];
{Insert[
Transpose[
Insert[Transpose[am], RandomInteger[{0, p - 1}, n - 1], r]], afr,
1], Insert[
Transpose[Insert[Transpose[tm], ConstantArray[0, n - 1], r]], v,
r]}
]
NonSingularRandomMatrix[p_?PrimeQ, n_] := Mod[Dot @@ Gen[p, n], p]
它确实生成一个非奇异矩阵,并具有矩阵元素的均匀分布,但需要p是质数:
In[10]:= Timing[NonSingularRandomMatrix[101, 300];]
Out[10]= {0.421, Null}
编辑 那么让我简化我的问题。给定矩阵
m
的小矩阵可以按以下方式计算:
MinorMatrix[m_?MatrixQ, {i_, j_}] :=
Drop[Transpose[Drop[Transpose[m], {j}]], {i}]
这是删除了第i
行和第j
列的原始矩阵。
我现在需要创建一个n
乘以n
的矩阵,在位置{i,j}
上放置给定的小矩阵mm
。我在算法中使用的是:
ExpandMinor[minmat_, {i_, j_}, v1_,
v2_] /; {Length[v1] - 1, Length[v2]} == Dimensions[minmat] :=
Insert[Transpose[Insert[Transpose[minmat], v2, j]], v1, i]
例子:
In[31]:= ExpandMinor[
IdentityMatrix[4], {2, 3}, {1, 2, 3, 4, 5}, {2, 3, 4, 4}]
Out[31]= {{1, 0, 2, 0, 0}, {1, 2, 3, 4, 5}, {0, 1, 3, 0, 0}, {0, 0, 4,
1, 0}, {0, 0, 4, 0, 1}}
我希望这件事可以更有效率地完成,这也是我在提问中所寻求的。
根据blisarius的建议,我研究了通过ArrayFlatten
实现ExpandMinor
的方法。
Clear[ExpandMinorAlt];
ExpandMinorAlt[m_, {i_ /; i > 1, j_}, v1_,
v2_] /; {Length[v1] - 1, Length[v2]} == Dimensions[m] :=
ArrayFlatten[{
{Part[m, ;; i - 1, ;; j - 1], Transpose@{v2[[;; i - 1]]},
Part[m, ;; i - 1, j ;;]},
{{v1[[;; j - 1]]}, {{v1[[j]]}}, {v1[[j + 1 ;;]]}},
{Part[m, i ;;, ;; j - 1], Transpose@{v2[[i ;;]]}, Part[m, i ;;, j ;;]}
}]
ExpandMinorAlt[m_, {1, j_}, v1_,
v2_] /; {Length[v1] - 1, Length[v2]} == Dimensions[m] :=
ArrayFlatten[{
{{v1[[;; j - 1]]}, {{v1[[j]]}}, {v1[[j + 1 ;;]]}},
{Part[m, All, ;; j - 1], Transpose@{v2}, Part[m, All, j ;;]}
}]
In[192]:= dim = 5;
mm = RandomInteger[{-5, 5}, {dim, dim}];
v1 = RandomInteger[{-5, 5}, dim + 1];
v2 = RandomInteger[{-5, 5}, dim];
In[196]:=
Table[ExpandMinor[mm, {i, j}, v1, v2] ==
ExpandMinorAlt[mm, {i, j}, v1, v2], {i, dim}, {j, dim}] //
Flatten // DeleteDuplicates
Out[196]= {True}
Insert
等这样的Mathematica内置函数是不可变的,它们会创建一个副本。特别是对于较大的矩阵,正是这种复制使得代码效率低下。你唯一的朋友是Part
,以向量化的方式用来就地修改矩阵。对于手头的这个案例,我在下面发布了一个解决方案。至于是否可以从中提取出一些通用函数来执行你所要求的一般任务,我还不知道,但似乎是很有可能的。 - Leonid Shifrin