Швидкий / ефективний спосіб розкласти відокремлені цілочисельні 2D-коефіцієнти фільтра


21

Я хотів би мати можливість швидко визначити, чи є поділене ядро ​​2D цілочисельних коефіцієнтів на два 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, оскільки (а) він порівняно обчислювально дорогий для моїх потреб і (б) він все ще не обов'язково допомагає визначити цілочисельні коефіцієнти.

Будь-які ідеї?


ДОПОМОГА ІНФОРМАЦІЯ

Коефіцієнти можуть бути позитивними, негативними або нульовими, і можуть бути патологічні випадки, коли сума одного або обох 1D векторів дорівнює нулю, наприклад

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

є роздільним на

 1  -2   1

і

-1
 0
 1

1
Я пам’ятаю, як намагався зрозуміти це ще в коледжі. Я майже досяг успіху, але не пам'ятаю як. =) Я не можу перестати думати про це зараз, коли ти це згадав!
Фонон

@Phonon: хе - добре продовжуй думати - я міг би використати натхнення на цьому. ;-)
Пол R

Чи можна зробити те ж саме, але для подвійних чи плаваючих значень?
Дієго Каталано

@DiegoCatalano: див. Відповідь Дениса нижче, а також питання, на яке він посилається, на math.stackexchange.com - я думаю, що це може працювати для більш загального випадку коефіцієнтів з плаваючою комою.
Пол Р

@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, як це, набагато простіше та елегантніше. На жаль, ще є одна зморшка, щоб виправити її - вона повинна працювати як з позитивними, так і з негативними коефіцієнтами, і це може призвести до вироджених випадків, наприклад A=[-2 1 0 -1 2]; B=[2 -3 6 0 -1]; M=A'*B;. Проблема тут у тому, що sum(A) = 0так Sb = [0 0 0 0 0]. Я спробую змінити ваш алгоритм, щоб він використовував суму абсолютних значень коефіцієнтів і побачив, чи допомагає це. Ще раз дякую за вашу допомогу.
Пол Р

Гаразд - схоже, ви все одно можете отримати GCD та зробити масштабування за допомогою abs(M), тобто, Sa=abs(M)*ones(N,1); Sb=ones(1,N)*abs(M);а потім продовжувати, як зазначено вище, але я не можу ще зрозуміти, як відновити знаки Sa, Sbнаприкінці. Я додав патологічний приклад, який ілюструє проблему в первинному питанні вище.
Пол Р

Я думаю, що зараз у мене є робоче рішення - я опублікував це як окрему відповідь, але заслуга вам належить до основної ідеї. Знову дякую !
Пол Р

7

Можливо, я дорікаю проблему, але, здається, ви могли:

  • NMAaii=0,1,,N1
  • j>0

    • aja0jrj
    • rj
    • rjaja0j0x
    • aja0
  • x

xk,norm=xkmini=0N1xi
  • xnorm
    xscaled=Kxnorm,K=1,2,,M
    KM

Це не найвишуканіший метод, і, ймовірно, є кращий спосіб, але він повинен працювати, досить простий у здійсненні і повинен бути відносно швидким для матриць скромного розміру.


Дякую - я думаю, що я, мабуть, прямував у чомусь подібному напрямку до того, як занурився в деталі. Мені не на 100% зрозуміло, що ви завжди знайдете рішення за допомогою цього методу, але все одно, я, мабуть, повинен це зашифрувати і спробувати його з кількома прикладами. У мене є думка, що, можливо, потрібно застосувати як рядкові, так і стовпчикові, щоб побачити, що дає найкраще рішення. Дякуємо, що знайшли час, щоб розглянути деталі - я зайнявся цим і повідомлю, як це виходить.
Пол Р.

Не могли б ви знайти найбільшого спільного дільника перших елементів рядків і використати його для визначення базового вектора?
Джим Клей

@JimClay: Так, це ефективно, що ви робите наприкінці, якщо у вас є така функціональність.
Джейсон Р.

3

хуzА|А-хуz|
х у z
уzхх у z х у z ... у свою чергу.

(Від наближених згортків до суми розділених згортків на math.stackexchange.)


1
Намагайтеся не відповідати на запитання за допомогою незрозумілих посилань. Краще пояснити необхідні деталі у своїй відповіді та включити посилання лише для довідки; таким чином, якщо посилання порушує істотні деталі відповіді, все ще є.
Сем Малоні

@SamMaloney: Я не бачу причини, чому це потрібно. Посилання пояснює все докладно. Він все ще з’явиться в пошуку запитань та запитань. То чому б і ні?
Нареш

1
@Naresh Я згадую лише про це, оскільки одна з цілей сайтів обміну стеками - створити сховище відповідей на запитання для подальшого ознайомлення. Тож як я розумію, що саме ця посилання на інший веб-сайт і повинна бути досить безпечною, загальною найкращою практикою не вважати посилання, які все ще працюють через кілька років. Надаючи загальний контур цих "двох простих методів" у відповіді, це забезпечить збереження інформації, навіть якщо щось трапиться із пов'язаним питанням. Як я вже говорив, це було більше загальним коментарем щодо найкращих практик щодо посилань у відповідях.
Сем Малоні
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.