3

ブール値を保持するブースト スパース マトリックスを使用し、それらをマップに格納するための比較関数を作成しようとしています。とてもシンプルな比較機能です。基本的には、マトリックスを 2 進数 (ベクトルにフラット化した後) として見て、その数値の値に基づいて並べ替えるという考え方です。これは次の方法で実現できます。

for(unsigned int j = 0; j < maxJ; j++)
{
  for(unsigned int i = 0; i < maxI; i++)
  {
    if(matrix1(i,j) < matrix2(i,j) return true;
    else if(matrix1(i,j) > matrix2(i,j) return false;
  }
}
return false;

ただし、これはマトリックスがまばらであるため非効率的であり、同じ結果を得るために反復子を使用したいと考えています。イテレータを使用するアルゴリズムは単純に見えます。つまり、1) 各行列の最初の非ゼロ セルを取得し、2) 両方の j*maxJ+i を比較し、3) 等しい場合は、各行列の次の非ゼロ セルを取得して繰り返します。残念ながら、コードではこれは非常に面倒で、エラーが心配です。

私が疑問に思っているのは、(a)これを行うためのより良い方法はありますか?(b)両方の行列の「次のゼロ以外のセル」を取得する簡単な方法はありますか? 明らかに、1 つの疎行列を反復処理する場合のように、ネストされた for ループを使用することはできません。

ご協力いただきありがとうございます。

--

上記で提案したアルゴリズムが私の特定のアプリケーションで最適なソリューションであると思われるので、2 つのスパース行列で次の非ゼロ セルを取得する、トリッキーな部分のために開発したコードを投稿する必要があると考えました。このコードは理想的ではなく、あまり明確ではありませんが、改善方法がわかりません。誰かがバグを見つけた場合、またはそれを改善する方法を知っている場合は、コメントをいただければ幸いです。そうでなければ、これが他の誰かに役立つことを願っています。

typedef boost::numeric::ublas::mapped_matrix<bool>::const_iterator1 iter1;
typedef boost::numeric::ublas::mapped_matrix<bool>::const_iterator2 iter2;

// Grabs the next nonzero cell in a sparse matrix after the cell pointed to by i1, i2.
std::pair<iter1, iter2> next_cell(iter1 i1, iter2 i2, iter1 end) const
{
    if(i2 == i1.end())
    {
        if (i1 == end)
            return std::pair<iter1, iter2>(i1, i2);
        ++i1;
        i2 = i1.begin();
    }
    else
    {
        ++i2;
    }

    for(; i1 != end;)
    {
        for(; i2 != i1.end(); ++i2)
        {
            return std::pair<iter1, iter2>(i1,i2);
        }
        ++i1;
        if(i1 != end) i2 = i1.begin();
    }
    return std::pair<iter1, iter2>(i1, i2);
}
4

3 に答える 3

1

ちなみに、私はこの質問が好きです。

あなたが求めていると思うものを疑似コード化しましょう

declare list of sparse matrices ListA
declare map MatMAp with a sparse Matrix type mapping to a double, along with a
`StrictWeakMatrixOrderer` function which takes two sparse matrices.

Insert ListA into MatMap. 

質問: StrictWeakMatrixOrderer を効率的に記述するにはどうすればよいですか?

これはアプローチです。私はその場でこれを発明しています....


関数を定義しflatten()、平坦化された行列を事前計算して、平坦化されたベクトルをベクトル (またはランダムなインデックス上限を持つ別のコンテナー) に格納します。flatten()各行(または列)を前の行と連結するのと同じくらい簡単です(行/列を取得する定数時間関数がある場合、これは線形時間で実行できます)。

これにより、サイズが 10^6 程度の一連のベクトルが生成されます。これはトレードオフです。オンザフライで計算する代わりに、この情報を保存します。これは、多くの比較を行う場合に便利です。

ゼロには情報が含まれていることに注意してください。ゼロを削除すると、互いに等しい 2 つのベクトルが生成される可能性がありますが、それらの生成行列は等しくない場合があります。

次に、アルゴリズムの質問を「順序行列」から「順序ベクトル」に変換しました。行列の距離計量については聞いたことがありませんが、ベクトルの距離計量については聞いたことがあります。

「差の合計」順序付け、別名ハミング距離を使用できます。(異なる foreach 要素、1 を追加)。これは O(n) アルゴリズムになります。

for i = 0 to max.
  if(a[i] != b[i])
     distance++

return distance

ハミング距離はこれらの条件を満たす

d(a,b) = d(b,a)
d(a,a) = 0
d(x, z) <= d(x, y) + d(y, z) 

ここで、すぐに分析を行います....

  • 10^6行列の要素 (またはそれに対応するベクトル)。
  • O(n)距離メトリック。
    • しかし、それはO(n)比較です。各配列アクセスにO(m)時間があれば、O(n*(n+n)) = O(n^2)メトリックが得られます。だからあなたhave< O(n)アクセスできます。std::vector []SGIのSTLサイトによると、オペレーターは「任意の要素への償却された一定時間のアクセス」を提供することがわかりました。
  • を格納するのに十分なメモリがk*2*10^6あるk場合、 は管理している行列の数です。これは、線形である代わりに大量のメモリを使用する実用的なソリューションです。
于 2009-08-28T19:56:06.980 に答える
0

標準的なベクトル ノルムを使用せずに 1 つのベクトル (またはマトリックス) が別のベクトル (またはマトリックス) より小さいかどうかを比較するには、特別な演算子 (または特別なマッピング/ノルム) が必要になるため、boost::sparse_matrix にビットごとの要素ごとの演算子を実装することについて話しているように思えます。

私の知る限り、boost は 2 値行列用の特別な演算子を提供していません (疎な 2 値行列は言うまでもありません)。BLAS レベルの行列/ベクトル代数を使用して、これを簡単に解決できる可能性はほとんどありません。バイナリ行列は線形代数の分野で独自の場所を持っているため、トリックと定理がありますが、それらがあなたのソリューションよりも簡単であるとは思えません。

あなたの質問は次のように再定式化できます: 2d ビットマップで表される天文学的に大きな数値を効率的に並べ替えるにはどうすればよいですか (n=100 なので、100x100 要素は 2^10000 のような数値になります)。

良い質問 !

于 2009-08-28T17:52:57.163 に答える
0

(a)あなたが達成しようとしていることを完全には理解していませんが、両方の行列が同じインデックスで同じ値を持っているかどうかを比較したい場合は、要素ごとの行列乗算を使用するだけで十分です(スパースにも実装する必要があります) ):

matrix3 = element_prod (matrix1, matrix2);

そうすれば、各インデックスについて次のようになります。

0 (false) * 1 (true) = 0 (false)
0*0 = 0
1*1 = 1

したがって、結果のmatrix3にはソリューションが1行に含まれます:)

于 2009-08-27T14:53:34.637 に答える