Ефективне обчислення зворотного кореня матричного квадратного


15

Поширеною проблемою статистики є обчислення квадратного кореня, оберненого симетричної позитивної певної матриці. Який був би найефективніший спосіб обчислення цього?

Я натрапив на які - то літератури (який я ще не читав), а деякий випадковий R код тут , який я відтворюють тут для зручності

# function to compute the inverse square root of a matrix
fnMatSqrtInverse = function(mA) {
  ei = eigen(mA)
  d = ei$values
      d = (d+abs(d))/2
      d2 = 1/sqrt(d)
      d2[d == 0] = 0
      return(ei$vectors %*% diag(d2) %*% t(ei$vectors))
}

Я не зовсім впевнений, що розумію лінію d = (d+abs(d))/2. Чи існує більш ефективний спосіб обчислення зворотного кореня матричного квадратного? Функція R eigenвикликає LAPACK .


d(d+|d|)/2max(d,0)A1/2A1/2х

@DanielShapero Дякуємо за ваш коментар Отже, якщо у мене є матриця PSD, мені ця лінія не потрібна? Моя програма вимагає обчислення квадратичних форм, таких як . A1/2BA1/2
чакраварти

Я не знайомий з R, але з даного рядка 7 я припускаю, що він має логічну індексацію, як Matlab. Якщо так, я пропоную вам переписати рядок 5 як d[d<0] = 0, що є більш виразним.
Федеріко Полоні

Чи правильний цей код? Я провів це на простому прикладі в matlab і виявив, що відповідь неправильна. Моя матриця є позитивно визначеною, але точно не симетричною. Будь ласка, дивіться мою відповідь нижче: Я передав код в matlab.
roni

Відповіді:


10

Код, який ви опублікували, використовує власне значення розкладання симетричної матриці для обчисленняA1/2 .

Заява

d = (d + abs (d)) / 2

ефективно приймає будь-який негативний запис у d і встановлює його на 0, залишаючи в спокої негативні записи. Тобто будь-яке негативне власне значенняA трактується так, ніби воно було 0. Теоретично всі власні значення A повинні бути невід'ємними, але на практиці звичайно бачити невеликі негативні власні значення при обчисленні власних значень нібито позитивного певного коваріаційна матриця, майже сингулярна.

Якщо вам дійсно потрібен зворотний симетричний матричний квадратний корінь , а досить низький (не більший, ніж скажімо, 1000 на 1000), то це приблизно так само добре, як і будь-який метод, який ви можете використовувати. AA

У багатьох випадках можна замість цього використовувати коефіцієнт Холеського, оберненого матриці коваріації (або практично такий же самий коефіцієнт Холеського самої матриці коваріації.) Обчислення коефіцієнта Холеського, як правило, на порядок швидше, ніж обчислення розкладу власного значення для щільні матриці та набагато ефективніші (як для обчислювального часу, так і для необхідного зберігання) для великих та розріджених матриць. Таким чином, використання факторизації Холеського стає дуже бажаним, коли великий і рідкий. A


6
Відповідь Брайана дає добру пораду: скористайтеся замість цього фактором Холеського (якщо зможете). Є ще одна оптимізація, яку ви можете зробити, крім того: не обчислюйте матрицю PSD . Часто ви отримуєте з обчислень типу , з прямокутним. У цьому випадку досить , щоб обчислити QR - розкладання , щоб отримати Холецького фактор з , з набагато більшою точністю. ААА=БТБББRА
Федеріко Полоні

5

На мій досвід, полярно-ньютонський метод Хіггема працює набагато швидше (див. Главу 6 функцій матриць Н. Хігхема). У цій короткій моїй замітці є сюжети, які порівнюють цей метод із методами першого порядку. Також наводяться цитати до кількох інших матрично-квадратних кореневих підходів, хоча в основному полярна ітерація Ньютона, здається, працює найкраще (і уникає проведення обчислень власного вектора).

% compute the matrix square root; modify to compute inverse root.
function X = PolarIter(M,maxit,scal)
  fprintf('Running Polar Newton Iteration\n');
  skip = floor(maxit/10);
  I = eye(size(M));
  n=size(M,1);
  if scal
    tm = trace(M);
    M  = M / tm;
  else
    tm = 1;
  end
  nm = norm(M,'fro');

  % to compute inv(sqrt(M)) make change here
  R=chol(M+5*eps*I);

  % computes the polar decomposition of R
  U=R; k=0;
  while (k < maxit)
    k=k+1;
    % err(k) = norm((R'*U)^2-M,'fro')/nm;
    %if (mod(k,skip)==0)
    %  fprintf('%d: %E\n', k, out.err(k));
    %end

    iU=U\I;
    mu=sqrt(sqrt(norm(iU,1)/norm(U,1)*norm(iU,inf)/norm(U,inf)));
    U=0.5*(mu*U+iU'/mu);

   if (err(k) < 1e-12), break; end
  end
  X=sqrt(tm)*R'*U;
  X = 0.5*(X+X');
end

0

Оптимізуйте свій код:

Варіант 1 - Оптимізуйте свій код R:
a. Ви можете apply()функціонувати, dщо буде max(d,0)і d2[d==0]=0в одному циклі.
б. Спробуйте працювати ei$valuesбезпосередньо.

Варіант 2 - Використовуйте C ++:
Перепишіть всю функцію в C ++ за допомогою RcppArmadillo. Ви все одно зможете зателефонувати йому від Р.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.