冷めたコーヒー

Weniger, aber besser

フルランク行列をランダムに生成する手法(Python による実装付き)

フルランクな行列をランダムに生成する手法を教えて頂きました:

実装

手順:

  1. ランダムに対角行列 $D$ を生成する
  2. ランダムな直行行列 $Q$ を生成する
  3. 行列 $D$ を $Q$ によって相似変換する(i.e., $A = Q^\top D Q$)
from scipy.stats import ortho_group

def make_full_rank_matrix(d, seed=0):
    """
    >>> make_full_rank_matrix(3)
    array([[ 0.59537814,  0.03454805, -0.05188665],
           [ 0.03454805,  0.6643958 , -0.04420196],
           [-0.05188665, -0.04420196,  0.60699231]])
    """
    np.random.seed(seed)
    D = np.diag(np.random.rand(d))
    Q = ortho_group.rvs(dim=d)
    A = Q.T@D@Q
    return A
  
# test for whether the matrix made by the above method is full rank or not
num_iter = 10
success = 0
for seed in range(num_iter):
    d = 500
    S = make_full_rank_matrix(d, seed)
    if np.linalg.matrix_rank(S) == d:
        success += 1
print(success)

別の手法

次の手法で生成される行列を考える:

  1. $n\times k$ 次元の行列 $W$ をランダムに生成する
  2. 対角成分が正であるような対角行列 $D$ をランダムに生成する
  3. 行列 $B$ を $B = WW^\top + D$ で生成する
  4. 行列 $B$ を相似変換して行列 $A$ を得る,i.e., $A = \text{diag}[1/\sqrt{B_{ii}}] B \text{diag}[1/\sqrt{B_{ii}}]$.

実装:

def make_full_rank_matrix(d, k, seed=0):
    """
    >>> make_full_rank_matrix(3, 2)
    array([[1.        , 0.62140315, 0.74064102],
           [0.62140315, 1.        , 0.70247127],
           [0.74064102, 0.70247127, 1.        ]])
    """
    np.random.seed(seed)
    W = np.random.rand(d, k)
    B = W@W.T + np.diag(np.random.rand(d))
    A = np.diag(1/np.sqrt(np.diag(B))) @ B @ np.diag(1/np.sqrt(np.diag(B)))
    return A
  
# test for whether the matrix made by the above method is full rank or not
num_iter = 10
success = 0
for seed in range(num_iter):
    d = 500
    S = make_full_rank_matrix(d, seed)
    if np.linalg.matrix_rank(S) == d:
        success += 1
print(success)

この手法で生成される行列 $A$ の固有値は,$k$ の値によって特徴付けられる.図を見た方が早いと思うので,以下に $k = 100, 50, 20, 10, 5, 2$ のそれぞれの場合における固有値を大きい順に並べて図示した 図を載せておく(行列のサイズは $100\times 100$ である):

f:id:mirucacule:20210809143052p:plain

図のように,上記の手法で生成した $n\times n$ の行列 $A$ の固有値を大きい順に並べたとき,$k$ 番目に大きい固有値までは大きい値をとり,それ以降の固有値は微小の値をとる($k=2$ のときはそうでもないように見えるが...).

Reference