2017-10-25 32 views
1

Juliaで疎な対称ランダム行列を作成する簡単な方法はありますか? ジュリアは半開区間に均一に分布IID非ゼロ要素と(密度dの)[スパース] m行nランダム行列を作成」コマンドJuliaで疎な対称ランダム行列を作成

sprand(m,n,d)

[0を有します1)[0,1]。 "しかし、私がこれを伝える限り、必ずしも対称行列を返すわけではありません。

私は、自動的にスパース対称ランダム行列を作成し、MATLABの

R = sprandsym(n,density)

に相当するコマンドを探しています。このようなコマンドがまだ実装されていない場合は、sprand(m,n,d)によって返された行列を対称行列に変換するための回避策はありますか?

ありがとうございました!

答えて

2

マイケルBorregaardの回答にコメントで述べた余分なメモリの警告を回避するために、次の関数は、スパース行列を取り、下三角部分のエントリを削除します。 SparseMatrixCSCフォーマットが不慣れである場合、それはまた、フォーマットを操作する方法の良好な提示として働く:

function droplower(A::SparseMatrixCSC) 
    m,n = size(A) 
    rows = rowvals(A) 
    vals = nonzeros(A) 
    V = Vector{eltype(A)}() 
    I = Vector{Int}() 
    J = Vector{Int}() 
    for i=1:n 
     for j in nzrange(A,i) 
      rows[j]>i && break 
      push!(I,rows[j]) 
      push!(J,i) 
      push!(V,vals[j]) 
     end 
    end 
    return sparse(I,J,V,m,n) 
end 

使用例:SparseMatrixCSCに

julia> a = [0.5 1.0 0.0 ; 2.0 0.0 0.0 ; 0.0 0.0 0.0] 
3×3 Array{Float64,2}: 
0.5 1.0 0.0 
2.0 0.0 0.0 
0.0 0.0 0.0 

julia> b = sparse(a) 
3×3 SparseMatrixCSC{Float64,Int64} with 3 stored entries: 
    [1, 1] = 0.5 
    [2, 1] = 2.0 
    [1, 2] = 1.0 

julia> c = droplower(b) 
3×3 SparseMatrixCSC{Float64,Int64} with 2 stored entries: 
    [1, 1] = 0.5 
    [1, 2] = 1.0 

julia> full(Symmetric(c)) # note this is symmetric although c isn't 
3×3 Array{Float64,2}: 
0.5 1.0 0.0 
1.0 0.0 0.0 
0.0 0.0 0.0 
+0

はc対称ですか? – Liso

+0

@Liso 'c'は対称ではありませんが、' Symmetric(c) 'があり、行列の下三角部分に記憶空間を浪費しません。(最初の段落で伝えようとしたように) –

+0

' triu'(あなたの 'droplower'に対応)、' tril'は上三角形や下三角形を取得します。同様に、操作を実行する 'triu!'と 'tril! 'もあります。 – fredrikekre

3

あなたは可能性がSymmetric(sprand(10,10,0.4))

+0

ありがとうございました!結果として得られる行列は依然として疎であろうか?それとも対称(randn(m、n)))をしなければならないのですか? – miga89

+2

これはまだまばらです。対称行列型は他の行列をラップし、その下三角部分を無視します。ちょっと注意すれば、対称行列の下にある疎な行列にアクセスできないエントリを格納するのに使われる無駄なメモリです。 –

+1

@ miga89もう1つの注意点は、対称化後のスパース行列 - ベクトル積が遅いことです。詳細については、[この問題](https://github.com/JuliaLang/julia/pull/22200)を参照してください。 – Gnimuc

0

操作は、しばしば、最大効率のためにカスタマイズされる必要があります。

function symmetrize(A::SparseMatrixCSC) 
    m,n = size(A) 
    m == n || error("argument expected to be square matrix") 
    rows = rowvals(A) ; vals = nonzeros(A) 
    a = zeros(Int,n) ; b = zeros(Int,n) ; c = 0 
    for i=1:n 
     for j in nzrange(A, i) 
      if rows[j]>=i 
       if rows[j]==i a[i] += 1 ; c += 1 ; end 
       break 
      end 
      a[i] += 1 ; b[rows[j]] += 1 ; c += 2 
     end 
    end 
    c == 0 && return SparseMatrixCSC(n, n, ones(n+1), nrows, nvals) 
    ncolptr = Vector{Int}(n+1) 
    nrows = Vector{Int}(c) ; nvals = Vector{eltype(A)}(c) 
    idx = 1 
    for i=1:n 
     ncolptr[i] = idx 
     if a[i]==0 a[i] = idx ; idx += b[i] ; continue ; end 
     for j in (0:a[i]-1)+first(nzrange(A, i)) 
      nvals[idx] = vals[j] ; nrows[idx] = rows[j] ; idx += 1 
      rows[j] >= i && break 
      nvals[a[rows[j]]] = vals[j] ; nrows[a[rows[j]]] = i 
      a[rows[j]] += 1 
     end 
     a[i] = idx ; idx += b[i] 
    end 
    ncolptr[n+1] = idx 
    return SparseMatrixCSC(n, n, ncolptr, nrows, nvals) 
end 

とサンプルを実行します:だから、同じ上部と対称スパース行列を疎行列Aから取得するには、ここにカスタムバージョン(それは少し不可解ですが、作業は)です

julia> f = sprand(5,5,0.2) 
5×5 SparseMatrixCSC{Float64,Int64} with 5 stored entries: 
    [1, 1] = 0.981579 
    [3, 1] = 0.330961 
    [5, 1] = 0.527683 
    [4, 5] = 0.196898 
    [5, 5] = 0.579006 

julia> full(f) 
5×5 Array{Float64,2}: 
0.981579 0.0 0.0 0.0 0.0  
0.0  0.0 0.0 0.0 0.0  
0.330961 0.0 0.0 0.0 0.0  
0.0  0.0 0.0 0.0 0.196898 
0.527683 0.0 0.0 0.0 0.579006 

julia> full(symmetrize(f)) 
5×5 Array{Float64,2}: 
0.981579 0.0 0.0 0.0  0.0  
0.0  0.0 0.0 0.0  0.0  
0.0  0.0 0.0 0.0  0.0  
0.0  0.0 0.0 0.0  0.196898 
0.0  0.0 0.0 0.196898 0.579006 

このバージョンは他のものより速くなければなりませんが、ベンチマークを行う必要があります(また、forループには@inboundsが追加されています)。

+0

問題のコードをGnimucリンクにコメントすることができます。これは、実装しようとしていることのように読み込まれます –

関連する問題