2009-04-16 4 views
8

스파 스 매트릭스를 저장하는 응용 프로그램이 있습니다. 이 행렬에는 행렬의 주 대각선 주위에 대부분 존재하는 항목이 있습니다. 이런 종류의 희소 행렬을 효율적으로 처리 할 수있는 효율적인 알고리즘 (또는 기존 라이브러리)이 있는지 궁금합니다. 바람직하게는, 이것은 각각의 매트릭스 엔트리가 사용자 정의 타입이 될 수있는 일반적인 구현 일 것이다. 질문/응답에 응답.NET에서 스파 스 매트릭스를 저장하는 가장 좋은 방법

편집 :

내가 주 대각선 내가 행렬의 대부분의 특성은 대부분의 항목이 주 대각선으로 떨어져 클러스터 만이 할 수 있는지가 될 것을 의미 대부분의 주위에 말을

대각선에 가까운 0이어야하며 대각선에서 멀리 떨어진 0이 아닌 값이있을 수 있습니다. 나는 여기에서 '가장'의 경우에 대해 효율적인 것을 원한다.

무엇을이 용도로 사용합니까? 행의 모든 ​​값이나 열의 모든 값에 효율적으로 액세스 할 수 있어야합니다. 저장된 값은 부울 값입니다. 예는 다음과 같습니다 행의 모든 ​​진정한 값에 대한

  1. 진정한는 행의 모든 ​​거짓 값의 뭔가
  2. 에 열의 설정 모든 항목에 표시 foreach는 열 것은 무엇인가에 대한 항목을 설정

이전에 링크 된 목록으로 완료되었지만 구현하기가 매우 어려웠습니다. 스파 스 매트릭스를 사용하면 알고리즘을 향상시킬 수 있지만 '올바른'유형의 스파 스 매트릭스 알고리즘을 찾는 것이 어렵다는 것을 알았습니다.

p.s. 지금까지의 답변 주셔서 감사합니다.

+0

답을 업데이트했습니다. 공간 효율성보다 성능 효율성이 더 중요합니까? "희소 행렬을 효율적으로 처리 할 수있는 방법"이라고 말하면 사용 사례에서는 데이터에 액세스하는 여러 가지 방법에 대해 이야기합니다. –

+0

필자는 성능이 공간 효율성보다 중요하다고 말할 것입니다. 우리는 매우 많은 양의 데이터를 처리 할 것이므로 매트릭스가 더 빨라지면 많은 공간을 사용하지 않아도됩니다. –

답변

7

[셀의 행, 열]을 기준으로 색인을 사용할 수 있습니다. 데이터가 대각선에 있기 때문에 행 인덱스 및 관련 열 indeces를 데이터와 함께 저장하는 일반적인 방법은 최적이 아닙니다. T는 구조체 인 경우, 당신이 null이되지 않습니다 셀의 내용을 받고 이후 IsCellEmpty를 호출 할 수 있다는

public class SparseMatrix<T> 
    { 
     public int Width { get; private set; } 
     public int Height { get; private set; } 
     public long Size { get; private set; } 

     private Dictionary<long, T> _cells = new Dictionary<long, T>(); 

     public SparseMatrix(int w, int h) 
     { 
      this.Width = w; 
      this.Height = h; 
      this.Size = w * h; 
     } 

     public bool IsCellEmpty(int row, int col) 
     { 
      long index = row * Width + col; 
      return _cells.ContainsKey(index); 
     } 

     public T this[int row, int col] 
     { 
      get 
      { 
       long index = row * Width + col; 
       T result; 
       _cells.TryGetValue(index, out result); 
       return result; 
      } 
      set 
      { 
       long index = row * Width + col; 
       _cells[index] = value; 
      } 
     } 
    } 

    static void Main() 
    { 
     var sm = new SparseMatrix<int>(512, 512); 
     sm[42, 42] = 42; 
     int val1 = sm[13, 13]; 
     int val2 = sm[42, 42]; 

     Console.WriteLine("VAL1 = " + val1); // prints out 0 
     Console.WriteLine("VAL2 = " + val2); // prints out 42 

     Console.ReadLine(); 
    } 

참고하고 기본 값을가집니다 : 여기 당신이 그것을 할하는 데 사용할 수있는 몇 가지 코드입니다 그 타입에 대해서. 코드를 확장하여 Size 속성과 _cells.Count을 기반으로 한 빠른 "SparseRatio"를 제공 할 수도 있습니다.

편집 :

글쎄, 당신이 흥미있는 경우에 당신이 속도 대 공간의 트레이드 오프를 할 수있는 속도입니다. 사전이 하나만있는 대신 세 개를 가져라! 그것은 당신의 공간을 세배로 늘리지 만, 그것은 당신이 진정으로 쉽게 원하는 어떤 식 으로든 열거합니다. 당신은 모든 항목을 반복하려면

public class SparseMatrix<T> 
    { 
     public int Width { get; private set; } 
     public int Height { get; private set; } 
     public long MaxSize { get; private set; } 
     public long Count { get { return _cells.Count; } } 

     private Dictionary<long, T> _cells = new Dictionary<long, T>(); 

     private Dictionary<int, Dictionary<int, T>> _rows = 
      new Dictionary<int, Dictionary<int, T>>(); 

     private Dictionary<int, Dictionary<int, T>> _columns = 
      new Dictionary<int, Dictionary<int, T>>(); 

     public SparseMatrix(int w, int h) 
     { 
      this.Width = w; 
      this.Height = h; 
      this.MaxSize = w * h; 
     } 

     public bool IsCellEmpty(int row, int col) 
     { 
      long index = row * Width + col; 
      return _cells.ContainsKey(index); 
     } 

     public T this[int row, int col] 
     { 
      get 
      { 
       long index = row * Width + col; 
       T result; 
       _cells.TryGetValue(index, out result); 
       return result; 
      } 
      set 
      { 
       long index = row * Width + col; 
       _cells[index] = value; 

       UpdateValue(col, row, _columns, value); 
       UpdateValue(row, col, _rows, value); 
      } 
     } 

     private void UpdateValue(int index1, int index2, 
      Dictionary<int, Dictionary<int, T>> parent, T value) 
     { 
      Dictionary<int, T> dict; 
      if (!parent.TryGetValue(index1, out dict)) 
      { 
       parent[index2] = dict = new Dictionary<int, T>(); 
      } 
      dict[index2] = value; 
     } 
    } 

_cells를 사용 : 여기에 있음을 보여주고 새로운 코드입니다. 주어진 열의 모든 행을 사용하려면 _columns을 사용하십시오. 주어진 행의 모든 ​​열을 _rows으로 지정하면됩니다.

정렬 된 순서로 반복하려는 경우 LINQ를 혼합에 추가하거나 항목을 캡슐화하는 내부 클래스가있는 정렬 된 목록을 사용할 수 있습니다 (행 또는 열을 저장하고 IComparable<T>을 구현해야 함). 일하기 위하여 분류하기를 위해).

+0

고맙습니다. 사전을 사용한다고해서 행이나 열 전체에 효율적으로 액세스 할 수 있습니까? (어쩌면 Linq 그것을 사용하여 ...?). 위의 편집을 참조하십시오. –

+0

다른 옵션에 대한 업데이트를 참조하십시오.공간이 문제가되지 않는다면 여러 사전을 사용하여 더 빠른 액세스를 얻으려면 절충하십시오. –

+0

우수 제안, 고맙습니다. –

4

나는 Dictionary<int, Dictionary<int, object >> 충분할 것 같아요

은 여기에 무료로 하나입니다.

1

평범한 배열을 유지하는 클래스를 사용하여 행렬 행 사이에 적용된 수평 오프셋을 저장하고 행의 스트라이프를 정의하는 등의 방법으로 행해질 수 있다고 생각합니다. 유효한 엔트리의 수 따라서 대각선과 두 개의 이웃 요소 만 정의 된 큰 행렬의 경우 3 * 행 수의 배열을 만들고 줄무늬 폭으로 3을 저장합니다. 오프셋은 행렬의 크기에 따라 다릅니다.

저는 이미이 작업을 수행하고있는 것을 전혀 모릅니다.

+0

좋은 생각. 나는 그것을 다음과 같이 구현할 수 있습니다 : 긍정적 인 입력만을 가정 할 때 엔트리들 사이에 0 개의 엔트리의 수로서 음수를 처리 할 수 ​​있습니다. 그래서 다음 ... [1,2, -30,0,1,2, -29] ​​ 확대하여 [1,2,0,0 ...] [0,1,2,0 ...] [m * row + column] 배열은 mxn 행렬의 (행, 열) 오프셋입니다. –

1

다음은 일반적인 data structure schemas 목록입니다. 각각에는 장점과 단점이 있으며, 희소 매트릭스가 발생하는 약간 다른 종류의 문제에 적합합니다. 목록 <> 및 사전 <>과 같은 기존 데이터 구조 위에 구현하고 싶을 것입니다.

2

여기에 두 가지 질문이 있습니다

  • "주요 대각선은 대부분 주위에"너무 모호합니다. 요소가 밴드에 있으면 밴드 자체의 밴드 스토리지를 주 대각선에서 오프셋 된 벡터로 사용하십시오.요소가 주 대각선 근처에서 무작위로 흩어져있는 경우 밴드에 0이 포함될 수있는 줄무늬 형태를 사용하거나 요소와 요소의 위치 만 배열에 저장하는 순수한 스파 스 형식을 사용하십시오.

  • 매트릭스 란 무엇입니까? 귀하의 목표가 단순히 효율적인 스토리지 일 경우 모든 요소에 대한 빠른 액세스로 띠 모양이 효율적입니다. 행렬을 가지고 선형 대수를 수행 할 것이지만, 행렬 벡터가 곱해진 적이 결코 없다면, 줄무늬가있는 형태는 여전히 훌륭하게 작동 할 것입니다. 행렬 곱셈 또는 행렬 인수 분해 행렬을 사용하여 채우기가 문제가되는 경우 순수한 희소 형이 더 적합 할 수 있습니다. 예를 들어, 2 개의 줄무늬 행렬의 곱에는 추가 밴드가 있으므로 두 개의 삼중 행렬 행렬의 곱은 5 각형이됩니다. 인수 분해의 경우, 재정렬은 종종 필인을 최소화하는 데 유용합니다. (AMD는 하나의 선택 사항이지만 대략적인 최소 등급 순열이지만 다른 체계도 있습니다.)

관련 문제