分離可能な整数2Dフィルター係数を分解する高速/効率的な方法


21

整数係数の特定の2Dカーネルが整数係数を持つ2つの1Dカーネルに分離可能かどうかをすばやく判断できるようにしたいと思います。例えば

 2   3   2
 4   6   4
 2   3   2

に分離可能です

 2   3   2

そして

 1
 2
 1

分離可能性の実際のテストは、整数演算を使用するとかなり簡単に思えますが、整数係数を使用した1Dフィルターへの分解はより困難な問題であることが判明しています。困難は、行または列間の比率が非整数(有理数)である可能性があるという事実にあるようです。たとえば、上記の例では、比率が2、1 / 2、3 / 2、および2/3です。

SVDのようなヘビーデューティアプローチを使用したくないのは、(a)ニーズに対して比較的計算コストが高く、(b)整数係数を決定するのに必ずしも役に立たないためです。

何か案は ?


さらに詳しい情報

係数は正、負、またはゼロの場合があり、いずれかまたは両方の1Dベクトルの合計がゼロである病理学的な場合があります。例えば

-1   2  -1
 0   0   0
 1  -2   1

に分離可能です

 1  -2   1

そして

-1
 0
 1

1
私は大学に戻ってこれを理解しようとしたことを覚えています。私はほとんど成功しましたが、どのように覚えていません。=)あなたがそれについて言及した今、私はそれについて考えることをやめられません!
フォノン

@フォノン:へー-よく考えて-これにインスピレーションを使うことができた。;-)
ポールR

doubleまたはfloat値に対して同じことを行うことは可能ですか?
ディエゴカタラーノ14年

@DiegoCatalano:以下のDenisの答え、および彼がmath.stackexchange.comでリンクしている質問を参照してください-浮動小数点係数のより一般的な場合にはうまくいくと思います。
ポールR 14年

@PaulR、電子メールでどのように連絡できますか?ありがとうございました。
ロイ

回答:


11

私は@Phonon答えを取り、行/列の合計ではなく一番上の行と左の列だけでGCDアプローチを使用するようにそれをいくらか修正しました。これは病理学的なケースをもう少し良く処理するようです。上の行または左の列がすべてゼロの場合でも失敗する可能性がありますが、この方法を適用する前にこれらのケースをチェックできます。

function [X, Y, valid] = separate(M)    % separate 2D kernel M into X and Y vectors 
  X = M(1, :);                          % init X = top row of M
  Y = M(:, 1);                          % init Y = left column of M
  nx = numel(X);                        % nx = no of columns in M
  ny = numel(Y);                        % ny = no of rows in M
  gx = X(1);                            % gx = GCD of top row
  for i = 2:nx
    gx = gcd(gx, X(i));
  end
  gy = Y(1);                            % gy = GCD of left column
  for i = 2:ny
    gy = gcd(gy, Y(i));
  end
  X = X / gx;                           % scale X by GCD of X
  Y = Y / gy;                           % scale Y by GCD of Y
  scale = M(1, 1) / (X(1) * Y(1));      % calculate scale factor
  X = X * scale;                        % apply scale factor to X
  valid = all(all((M == Y * X)));       % result valid if we get back our original M
end

感謝@Phononし、@Jason Rこのためのオリジナルのアイデア。


10

とった!MATLABコードを投稿すると、今夜または明日、説明が投稿されます

% Two original arrays
N = 3;
range = 800;
a = round( range*(rand(N,1)-0.5) )
b = round( range*(rand(1,N)-0.5) )

% Create a matrix;
M = a*b;
N = size(M,1);

% Sanity check
disp([num2str(rank(M)) ' <- this should be 1!']);

% Sum across rows and columns
Sa = M * ones(N,1);
Sb = ones(1,N) * M;

% Get rid of zeros
SSa = Sa( Sa~=0 );
SSb = Sb( Sb~=0 );

if isempty(SSa) | isempty(SSb)
    break;
end

% Sizes of array without zeros
Na = numel(SSa);
Nb = numel(SSb);

% Find Greatest Common Divisor of Sa and Sb.
Ga = SSa(1);
Gb = SSb(1);

for l=2:Na
    Ga = gcd(Ga,SSa(l));
end

for l=2:Nb
    Gb = gcd(Gb,SSb(l));
end

%Divide by the greatest common divisor
Sa = Sa / Ga;
Sb = Sb / Gb;

%Scale one of the vectors
MM = Sa * Sb;
Sa = Sa * (MM(1) / M(1));

disp('Two arrays found:')
Sa
Sb
disp('Sa * Sb = ');
Sa*Sb
disp('Original = ');
M

ありがとう-これはすごい-昨晩、係数の因数分解などを考えて目を覚ましていましたが、このようにGCDを使用する方がずっとシンプルでエレガントです。残念ながら、まだまだ解決すべき問題が1つあります。正の係数と負の係数の両方を使用する必要があり、これにより、例が悪化する可能性がありA=[-2 1 0 -1 2]; B=[2 -3 6 0 -1]; M=A'*B;ます。ここの問題はsum(A) = 0そうSb = [0 0 0 0 0]です。係数の絶対値の合計を使用するようにアルゴリズムを変更し、それが役立つかどうかを確認します。ご協力ありがとうございます。
ポールR

OK -それはあなたがまだGCDsを取得し、使用してスケーリングを行うことができますように見えるabs(M)、すなわちSa=abs(M)*ones(N,1); Sb=ones(1,N)*abs(M);、その後、上記のように続けますが、私はまだにサインを復元する方法を見ることができないSaSb終わり。上記の元の質問の問題を示す病理学的例を追加しました。
ポールR

私は今、実用的な解決策を持っていると思います-私はそれを別の答えとして投稿しましたが、基礎となるアイデアの功績はあなたにあります。再度、感謝します !
ポールR

7

たぶん私は問題を平凡にしていますが、それはあなたができるようです:

  • NMAa=01N1
  • j>0

    • aja0jrj
    • rj
    • rjaja0j0バツ
    • aja0
  • バツ

バツknorm=バツk=0N1バツ
  • バツnorm
    バツscaled=KバツnormK=12M
    KM

最もエレガントな方法ではなく、より良い方法がある可能性がありますが、動作し、実装が非常に簡単で、適度なサイズのマトリックスでは比較的高速である必要があります。


おかげで-詳細に行き詰まる前に、おそらくこの方向に向かっていたと思います。常にこの方法を使用してソリューションにたどり着くということは100%明確ではありませんが、とにかくこれをコーディングして、いくつかの例を試してみてください。私は、どちらが「最良の」ソリューションをもたらすかを見るために、行と列の両方に適用する必要があるかもしれないという予感を持っています。時間を割いて詳細を説明してくれてありがとう-それで忙しくなり、どのように機能するかをお知らせします。
ポールR

行の最初の要素の最大公約数を見つけて、それを使用して基底ベクトルを決定できませんでしたか?
ジム・クレイ

@JimClay:はい、その機能が利用できる場合、それは事実上あなたが最後にやっていることです。
ジェイソンR

3

バツyzA|Aバツyz|
バツ y z
yzバツバツ y z バツ y z  順番に。

( math.stackexchangeの分離可能な畳み込みの近似畳み込みから。)


1
説明のないリンクで質問に答えないようにしてください。回答に必要な詳細を説明し、参照用のリンクのみを含めることをお勧めします。その方法は、リンクが壊れても答えの本質的な詳細はまだそこにあります。
サム・マロニー

@SamMaloney:それが必要な理由はわかりません。リンクはすべてを詳細に説明します。引き続きQ&A検索でポップアップ表示されます。それではなぜですか?
ナレシュ

1
@Nareshスタック交換サイトの目標の1つは、将来の参考のために回答済みの質問のリポジトリを構築することであるため、これについてのみ言及します。したがって、この特定のリンクは別のSEサイトへのものであり、かなり安全であるべきだと理解していますが、数年後もまだ機能しているリンクを期待しないのが一般的なベストプラクティスです。。答えは、これらの「2つの簡単な方法の概要を与える何かがリンクの質問に起こっていても情報が保持されていることを確実にするよう私も言った、これはより多くの答えのリンクに関するベストプラクティスに関する一般的なコメントをしました。
サム・マロニー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.