2013-03-10 3 views
2

Я пишу некоторый код в python, который требует часто инвертирования больших квадратных матриц (100-200 строк/colums).альтернативы или ускорения для инверсии матрицы mpmath

Я нахожусь в пределе точности машины, поэтому начал использовать mpmath, чтобы сделать инверсию матрицы произвольной точности, но она очень медленная, даже с использованием gmpy.

Инвертирование случайных матриц размера 20, 30, 60 с точностью 30 (десятичная) занимает ~ 0,19, 0,60 и 4,61 секунды, тогда как те же операции в mathematica составляют 0,0084, 0,015 и 0,055 секунды.

Это использование python3 и mpmath 0.17 (не уверен в версии gmpy) на машине с аркой. Я не уверен, почему mpmath настолько медленнее, но есть ли какая-либо библиотека с открытым исходным кодом, которая будет приближаться к скоростям, которым математика управляет для этого (ровно 1/2, как быстро было бы хорошо)?

Мне не нужна произвольная точность - 128 бит, вероятно, будет достаточно хорошим. Я также просто не понимаю, как mpmath может быть намного медленнее. Он должен использовать совершенно другой алгоритм инверсии матрицы. Чтобы быть конкретным, я использую M**-1.

Есть ли способ заставить его использовать более быстрый алгоритм или ускорить его.

+0

Вы используете матрицу, обратную для решения набора уравнений? Если это так, то есть более эффективные методы, которые явно не требуют обратного. Разложение LU я считаю немного более эффективным. – Stuart

+0

Нет, я использую его в вариации проблемы линейного программирования, поэтому мне нужно обратное, чтобы явно определить функцию стоимости. На самом деле проблема заключается в том, что, поскольку стоимость получает очень малые точные обратные вызовы, может возникнуть множество проблем. но я думаю, что для 128-битной точности будет достаточно (по крайней мере, для моих текущих целей). – user2153813

+0

Конечно, мне не нужен фактический обратный, но мне нужно, чтобы он умножался на некоторые другие матрицы. Таким образом, он не совсем аналогичен решению A.x = b, так как мне нужно A^-1 * b, а b - не вектор. Но, может быть, есть способ обобщить поиск таких решений для матриц? OTOH Мне нужно делать это много раз, поэтому было бы лучше найти обратный. – user2153813

ответ

1

Я предполагаю, что двойная точность не является проблемой для точности конечного результата, но для некоторых матриц это вызывает проблему в промежуточных результатах инверсии. В этом случае давайте рассматривать результат нормальной квантовой (двойной точности) обратной как просто хорошее приближение, а затем использовать это как отправную точку для нескольких итераций метода ньютонов для решения обратной задачи.

Пусть матрица мы пытаемся перевернуть, и X наша оценка обратного. Итерации методы Ньютона просто состоит из:

X = X*(2I - AX) 

Для больших матриц усилия, чтобы вычислить несколько итераций выше почти незначителен по сравнению с отысканием инверсии, и это может значительно повысить точность окончательного результат. Попробуй.

BTW, I - это единичная матрица в приведенном выше уравнении.

EDIT, чтобы добавить код для проверки точности плавающих типов.

Этот код используется для проверки точности поплавкового типа.

x = float128('1.0') 
wun = x 
two = wun + wun 
cnt = 1 
while True: 
    x = x/two 
    y = wun + x 
    if y<=wun: break 
    cnt +=1 

print 'The effective number of mantissa bits is', cnt 
+0

Ну, я не уверен. Обратный номер numers производит, умножается на исходную матрицу, имеет нули, которые являются порядками 1е-15 или 1е-16 (как и ожидалось для double). Я думаю, что это на самом деле недостаточно. Линейная программа включает в себя замену строки матрицы и переоценку стоимости, и то, что я нахожу, заключается в том, что в какой-то момент изменение становится настолько маленьким, что стоимость больше не изменяется (хотя и должна). Я думаю, что это следствие низкой точности. Но, возможно, я могу использовать ваше предложение выше, чтобы ускорить вычисление mp.math обратного. – user2153813

+0

Это может быть немного быстрее, чем mp.A ** (- 1). Я просто протестировал его сейчас на случайной матрице 200x200. Нормальное значение numpy inv (a) с плавающей запятой было быстрым, но, как вы указали, эквивалент mpmath был очень медленным. Затем я тестировал только одну итерацию вышеуказанного алгоритма, используя mpmath (начиная с результата обычного inv (A)), и улучшил mp.norm (A * X - mp.eye (200)) примерно с 1E-12 до 1E- 18. Таким образом, кажется возможным улучшение. Единственная проблема заключается в том, что с матрицами, что большие, даже просто умножения матрицы mpmath для вышеупомянутой итерации довольно медленные (но все же быстрее, чем инверсия mpmath) – Stuart

+0

Спасибо, это на самом деле похоже на реальную возможность. Точность, кажется, улучшается очень быстро ... даже одна итерация, кажется, доводит меня до довольно высокой точности. К сожалению, как вы говорите, умножение mpmath все еще довольно медленное, но, возможно, я могу найти другую библиотеку, которая бы быстро умножала матричное умножение. Спасибо за предложение! – user2153813

2

Линера-алгебра в mpmath довольно медленная, к сожалению. Есть много библиотек, которые решают эту проблему намного лучше (например, Sage). Тем не менее, как следует из предложения Стюарта, довольно просто сделать достаточно быстрое высокоточное матричное умножение в Python без установки каких-либо библиотек, используя арифметику с фиксированной точкой. Вот версия с использованием матриц mpmath для ввода и вывода:

def fixmul(A, B, prec): 
    m = A.rows; p = B.rows; n = B.cols; 
    A = [[A[i,j].to_fixed(prec) for j in range(p)] for i in range(m)] 
    B = [[B[i,j].to_fixed(prec) for j in range(n)] for i in range(p)] 
    C = [([0] * n) for r in range(m)] 
    for i in range(m): 
     for j in range(n): 
      s = 0 
      for k in range(p): 
       s += A[i][k] * B[k][j] 
      C[i][j] = s 
    return mp.matrix(C) * mpf(2)**(-2*prec) 

В 256-битной точностью, это умножает две матрицы 200х200 в 16 раз быстрее, чем mpmath для меня. Также нетрудно написать так называемую процедуру инверсии матрицы. Конечно, если элементы матрицы очень большие или очень маленькие, вы хотите сначала их масштабировать.Более твердым решением было бы написать собственные функции матрицы, используя типы с плавающей запятой в gmpy, что должно быть существенно быстрым.

+0

Спасибо, но ускорение мне понадобится значительно больше. Мне нужно, чтобы шаг инверсии оставался на долю секунды даже для матриц размером 100-200. Гибридное 128-битное решение, которое я разместил в комментариях к Стюарту, делает инверсию ~ 1/100 секунды для N = 150 (в то время как mpmath будет принимать _much_ дольше) с коэффициентом усиления 3-4 десятичных разряда. Этого может быть достаточно, хотя я хочу, чтобы float128 действительно был 128-битным. Думаю, я мог бы реализовать выше в gmp или просто использовать C и подключить его к python. – user2153813

+0

Ну, я раз умножаю матрицу 200x200 с 128-битной точностью до 4,4 секунды в Mathematica и 3,3 секунды в Sage (обратные матрицы полной матрицы стоят примерно одинаково), а одно матричное умножение с указанным выше кодом занимает всего 2,7 секунды. Я бы оценил, что использование GMP или MPFR в C приведет к тому, что до 0,5 - 1 секунды. Если вам нужно, чтобы это произошло за долю секунды, лучше всего, наверное, изучить двойную или квад-двойную арифметику. –

0

Multiprecision toolbox for MATLAB обеспечивает следующие моменты времени с использованием 128-битной точности (Core i7 930):

20х20 - 0,007 сек

30х30 - 0,019 сек

60x60 - 0,117 сек

200x200 - 3.2 сек

Обратите внимание, что эти цифры намного ниже для современных процессоров.