繁体   English   中英

MATLAB:快速创建具有固定度数(行总和)的随机对称矩阵

[英]MATLAB: Fast creation of random symmetric Matrix with fixed degree (sum of rows)

我正在寻找一种快速创建具有以下特性的随机矩阵A方法:

  • A = transpose(A)
  • 所有i的A(i,i) = 0
  • 对于所有i,j的A(i,j) >= 0
  • sum(A) =~ degree ; 行总数由我要指定的分布随机分布(此处=~表示近似相等)。

分布degree来自矩阵orig ,特别是degree=sum(orig) ,因此我知道存在具有这种分布的矩阵。

例如: orig=[0 12 7 5; 12 0 1 9; 7 1 0 3; 5 9 3 0] orig=[0 12 7 5; 12 0 1 9; 7 1 0 3; 5 9 3 0]

orig =
 0    12     7     5
12     0     1     9
 7     1     0     3
 5     9     3     0

 sum(orig)=[24 22 11 17];

现在,一个可能的矩阵A=[0 11 5 8, 11 0 4 7, 5 4 0 2, 8 7 2 0]

A = 
 0    11     5     8
11     0     4     7
 5     4     0     2
 8     7     2     0

sum(A)=[24 22 11 17]

我已经尝试了一段时间,但不幸的是我的两个想法没有用:


版本1:

我将Nswitch次转换Nswitch两个随机元素: A(k1,k3)--; A(k1,k4)++; A(k2,k3)++; A(k2,k4)--; A(k1,k3)--; A(k1,k4)++; A(k2,k3)++; A(k2,k4)--; (以及转置元素)。

不幸的是, Nswitch = log(E)*E (其中E=sum(sum(nn)) ))是为了使矩阵非常不相关。 当我的E > 5.000.000 ,这是不可行的(特别是因为我至少需要10个这样的矩阵)。


版本2:

我根据从头开始的分布创建矩阵。 这个想法是,根据degree的分布, degree degree(i)数填充每一行i

nn=orig;
nnR=zeros(size(nn));
for i=1:length(nn)
    degree=sum(nn);
    howmany=degree(i);
    degree(i)=0;
    full=rld_cumsum(degree,1:length(degree));
    rr=randi(length(full),[1,howmany]);
    ff=full(rr);
    xx=i*ones([1,length(ff)]);
    nnR = nnR + accumarray([xx(:),ff(:)],1,size(nnR));
end
A=nnR;

但是,虽然sum(A')=degreesum(A)系统地偏离degree ,但我无法找到原因。

较小的degree偏差当然是可以的,但是在某些地方包含大量矩阵的粒子似乎存在系统性偏差。


如果有人可以向我展示版本1的快速方法,版本2中分布的系统偏差的原因,或者以其他方式创建此类矩阵的方法,我将非常高兴。 谢谢!


编辑:

这是matsmath提出的解决方案中的问题:假设您有矩阵:

orig = 
 0    12     3     1
12     0     1     9
 3     1     0     3
 1     9     3     0

其中r(i)=[16 22 7 13]

  • 步骤1:r(1)= 16,我的随机整数分区是p(i)= [0 7 3 6]。
  • 步骤2:检查是否所有p(i)<= r(i)。
  • 第三步:

我的随机矩阵开始看起来像

A = 
 0    7     3     6
 7    0     .     .
 3    .     0     .
 6    .     .     0

新的行总和向量rnew = [r(2)-p(2),...,r(n)-p(n)] = [15 4 7]

第二次迭代(此处出现问题):

  • 步骤1:rnew(1)= 15,我的随机整数分区为p(i)= [0 AB]:rnew(1)= 15 = A + B。
  • 步骤2:检查所有p(i)<= rnew(i),得出A <= 4,B <= 7。 因此A + B <= 11,但是A + B必须为15。 矛盾 :-/

编辑2:

这是(据我所知)代表David Eisenstat发布的解决方案的代码:

orig=[0 12 3 1; 12 0 1 9; 3 1 0 3; 1 9 3 0];
w=[2.2406 4.6334 0.8174 1.6902];
xfull=zeros(4);

for ii=1:1000
    rndmat=[poissrnd(w(1),1,4); poissrnd(w(2),1,4); poissrnd(w(3),1,4); poissrnd(w(4),1,4)];
    kkk=rndmat.*(ones(4)-eye(4)); % remove diagonal
    hhh=sum(sum(orig))/sum(sum(kkk))*kkk; % normalisation
    xfull=xfull+hhh;
end

xf=xfull/ii;
disp(sum(orig)); % gives [16    22     7    13]
disp(sum(xf));   % gives [14.8337    9.6171   18.0627   15.4865] (obvious systematic problem)
disp(sum(xf'))   % gives [13.5230   28.8452    4.9635   10.6683] (which is also systematically different from [16, 22, 7, 13]

第一种方法(基于版本2)

让您的行总和向量由矩阵orig [r(1),r(2),...,r(n)]给出。

Step 1. Take a random integer partition of the integer r(1) into exactly n-1 parts, say p(2), p(3), ..., p(n)
Step 2. Check if p(i)<=r(i) for all i=2...n. If not, go to Step 1.
Step 3. Fill out your random matrix first row and colum by the entries 0, p(2), ... , p(n), and consider the new row sum vector [r(2)-p(2),...,r(n)-p(n)].

用n-1阶矩阵重复这些步骤。

关键是,您一次随机分配一行,并将问题减少为搜索大小减小了一个的矩阵。


正如OP在评论中指出的那样,这种幼稚的算法失败了。 原因是所讨论的矩阵在其条目上具有其他必要条件,如下所示:

事实:

如果A是一个行总​​和为[r(1), r(2), ..., r(n)]的orig矩阵,则对于每个i=1..n必然满足r(i)<=-r(i)+sum(r(j),j=1..n)

也就是说,任何行总和,例如第i个, r(i) ,最多必须与其他行总和(不包括r(i) )一样大。

鉴于此,可以修改算法。 请注意,在步骤2b中。 我们检查新的行总和向量是否具有上述属性。

Step 1. Take a random integer partition of the integer r(1) into exactly n-1 parts, say p(2), p(3), ..., p(n)
Step 2a. Check if p(i)<=r(i) for all i=2...n. If not, go to Step 1.
Step 2b. Check if r(i)-p(i)<=-r(i)+p(i)+sum(r(j)-p(j),j=2..n) for all i=2..n. If not, go to Step 1.
Step 3. Fill out your random matrix first row and colum by the entries 0, p(2), ... , p(n), and consider the new row sum vector [r(2)-p(2),...,r(n)-p(n)].

第二种方法(基于版本1)

我不确定这种方法是否可以为您提供随机矩阵,但是肯定可以为您提供不同的矩阵。

这里的想法是在本地更改orig矩阵的某些部分 ,以保持其所有属性的方式。

您应该在主对角线下方寻找一个随机的2x2子矩阵,该子矩阵包含严格为正的项,例如[[a,b],[c,d]]并用r[[a+r,br],[cr,d+r]] 您也可以在主对角线上方进行相同的更改,以保持新矩阵对称。 这里的要点是条目内的更改彼此“抵消”。

当然,应该以br>=0cr>=0的方式选择r

您也可以遵循此想法来修改较大的子矩阵。 例如,您可以选择3个随机行坐标r1r2r2和3个随机列坐标c1c2c3 ,然后按以下方式在orig矩阵的9个位置(ri,cj)更改:您更改了3x3子矩阵[[abc],[def], [ghi]][[ar b+rc] [d+re fr], [g hr i+r]] 您可以在转置的位置执行相同的操作。 再次,必须以使得ar>=0fr>=0hr>=0的方式选择随机值r 而且, c1r1以及c3r3必须是不同的,因为您不能更改矩阵orig的主对角线中的0项。

您可以一遍又一遍地重复这样的事情,比如说100次,直到找到看起来随机的东西。 请注意,此想法使用的事实是您具有解决方案的现有知识,这是矩阵orig ,而第一种方法根本不使用此类知识。

由于足以大致保留度数序列,因此让我提出一个随机分布,其中根据Poisson分布选择对角线上方的每个条目。 我的直觉是,我们希望找到权重w_i ,以使i != ji,j条目具有均值w_i*w_j (所有对角线条目均为零)。 这给了我们非线性方程组:

for all i, (sum_{j != i} w_i*w_j) = d_i,

其中d_ii 等效地,

for all i, w_i * (sum_j w_j) - w_i^2 = d_i.

可以通过从w_i = d_i / sqrt(sum_j d_j)的初始解采用如下所述的牛顿法来解决后者。

一旦有了w_i ,就可以使用poissrnd重复采样一次生成多个Poisson分布的样本。


(如果有时间,我将尝试在numpy中实现。)

对于4 x 4问题的方程组的雅可比矩阵为

(w_2 + w_3 + w_4) w_1               w_1               w_1
w_2               (w_1 + w_3 + w_4) w_2               w_2
w_3               w_3               (w_1 + w_2 + w_4) w_3
w_4               w_4               w_4               (w_1 + w_2 + w_3).

通常,令A为对角矩阵,其中A_{i,i} = sum_j w_j - 2*w_i u = [w_1, ..., w_n]'v = [1, ..., 1]' 雅可比行列式可以写成J = A + u*v' Sherman-Morrison公式给出逆

                              A^-1*u*v'*A^-1
J^-1 = (A + u*v')^-1 = A^-1 - -------------- .
                              1 + v'*A^-1*u

对于牛顿步骤,我们需要为给定的y计算J^-1*y y 使用上述公式,可以在时间O(n)直接完成此操作。 如果有机会,我会添加更多细节。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM