Поиск корня с сопутствующей матрицей

Я хотел бы найти все действительные корни одномерного многочлена. Например, я мог бы использовать алгоритм Дженкинса-Трауба, но я хочу научиться решать его с помощью сопутствующей матрицы.

Я знаю, как превратить многочлен в сопутствующую матрицу, и я нашел скрипт, который выполняет декомпозицию QR: http://quantstart.com/articles/QR-Decomposition-with-Python-and-NumPy

И тут я теряюсь: что делать дальше? Я думаю, что мне нужно вычислить несколько разложений, но когда я это делаю, я всегда получаю один и тот же результат (очевидно). Я также читал, что может быть полезно сначала преобразовать сопутствующую матрицу в форму Хессенберга, но как? Потом есть "сдвиги" - какие они?

Я также нашел http://www.nr.com/webnotes/nr3web17.pdf, но поскольку я ничего не понимаю, я хотел бы знать, есть ли какой-либо более простой метод (даже если он медленнее или менее стабилен).

Другими словами: чтение http://en.wikipedia.org/wiki/QR_algorithm

  • "пусть A будет реальной матрицей, для которой мы хотим вычислить собственные значения"
    хорошо, это моя сопутствующая матрица, верно?

  • "мы вычисляем QR-разложение Ak=QkRk"
    , которое будет Q, R = householder(A) из самой первой ссылки, верно?

  • "Тогда мы образуем Ak+1 = RkQk"
    легко, просто перемножьте R и Q

  • «При определенных условиях[2] матрицы Ak сходятся к треугольной матрице, форме Шура матрицы A. Собственные значения треугольной матрицы перечислены на диагонали, и проблема собственных значений решена».
    ...wait , какая? Я попытался:

    for i in range(100):
        Q, R = householder(A)
        A = mult_matrix(R, Q)
    

но, похоже, нет никакого прогресса, и я не вижу никаких чисел, даже близких к правильным корням.

Пожалуйста, кто-нибудь может объяснить мне это?

PS: я не хочу слепо использовать LAPACK или что-то подобное, так как хочу понять, как это работает, хотя бы в очень упрощенном виде.

PPS: есть также http://adorio-research.org/wordpress/?p=184 (хотя не уверен, чем он отличается от первого метода...)


person Ecir Hana    schedule 17.11.2013    source источник


Ответы (1)


Если ваша сопутствующая матрица является матрицей преобразования коэффициентов линейной полиномиальной операции, которая отображает q(x) в x*q(x) mod p(x)

где p(x)=x^(n+1)+p_n*x^n+...+p_1*x+p_0.

В явном виде A имеет вид

0 0 0 ... 0 -p_0
1 0 0 ... 0 -p_1
0 1 0 ... 0 -p_2
. . . ... . . . 
0 0 0 ... 1 -p_n

который уже находится в форме Хессенберга. Поскольку эта форма сохраняется во время алгоритма QR, вы можете использовать QR-разложение с поворотами Гивенса, где происходят только повороты, близкие к диагонали.

В несмещенном алгоритме QR вы должны наблюдать заметное развитие, по крайней мере, в правом нижнем блоке 3x3.

Если вы возьмете одно из собственных значений нижнего правого блока 2x2 и вычтете его из каждого диагонального элемента, то вы получите сдвинутые алгоритмы QR согласно Фрэнсису. Сдвиг s, вычитаемое число, является текущей наилучшей оценкой наименьшего собственного значения. Обратите внимание, что, вполне вероятно, вы покинули реальную область и должны выполнять вычисления со сложными матричными элементами. Вы должны сохранить сдвиг в памяти и добавить к нему любой новый сдвиг на последующих шагах, а также добавить комбинированный сдвиг обратно к любому найденному собственному значению.

Разделение матрицы происходит всякий раз, когда любой из поддиагональных элементов практически равен нулю. Если разделение происходит в последней строке, то последняя диагональная запись является собственным значением сдвинутой матрицы (A-s*I). Если разделение отделяет последний блок 2x2, то можно легко определить его собственные значения, которые снова являются собственными значениями сдвинутой матрицы.

Если разделение происходит где-то еще, алгоритм QR рекурсивно применяется к диагональным блокам отдельно.

  • Приложение I

Сходимость всех вариантов алгоритма измеряется сходимостью элементов ниже диагонали к нулю.

Базовый алгоритм имеет геометрическую сходимость в этих поддиагональных элементах, геометрический фактор входа в (i, i-1) представляет собой долю размеров собственных значений в позициях i-1 и i. Нуль будет достигнут быстро везде, где есть большой скачок.

Сопряженные комплексные собственные значения имеют одинаковый размер, поэтому алгоритм создаст блок 2x2 на диагонали, решит квадратное характеристическое уравнение этого блока, чтобы получить соответствующие собственные значения.

Большие диагональные блоки будут иметь место для нескольких или сгруппированных собственных значений.

Приложение II

это линия

   alpha = -cmp(x[0],0) * norm(x)

в процедуре домовладельца. В большинстве случаев x[0] не будет точно равным 0, поэтому это создает знак. Однако в случае сопутствующей матрицы, x[0]==0 по построению, поэтому знак не создается, альфа получает неправильное значение 0. Измените его на более прозаичный

    alpha = norm(x)
    if x[0] < 0: alpha = -alpha

и это работает хорошо.

def companion_matrix(p):
    n=len(p)-1
    C=[[float(i+1 == j) for i in xrange(n-1)] for j in xrange(n)]
    for j in range(n): C[j].append(-p[n-j]/p[0])
    return C


def QR_roots(p):
    n=len(p)-1
    A=companion_matrix(p)
    for k in range(10+n):
        print "step: ",k+1," after ",(k+1)*(5+n), "iterations"
        for j in range(5+n):
            Q,R=householder(A)
            A=mult_matrix(R,Q)
        print("below diagonal")
        pprint([ A[i+1][i] for i in range(n-1) ])
        print("diagonal")
        pprint([ A[i][i] for i in range(n) ])
        print("above diagonal")
        pprint([ A[i][i+1] for i in range(n-1) ])


p=[ 1, 2, 5, 3, 6, 8, 6, 4, 3, 2, 7]
QR_roots(p)

#for a case with multiple roots at 1 and 4
#p= [1,-11,43,-73,56,-16]
#QR_roots(p)
person Lutz Lehmann    schedule 11.12.2013
comment
Большое спасибо за ответ! К сожалению, я полностью согласен с тем, что вы можете использовать QR-разложение. Что это вообще за обороты? Думаю, мне придется перечитать статью еще раз. Больше всего меня беспокоит то, что первое связанное QR-разложение вообще не развивается. Почему? Тем не менее, второй связанный QR-разложение работает! По моему ограниченному пониманию, достаточно ли сделать Q, R = decomp(A) и A = R x Q? Все сдвиги и тому подобное предназначены только для повышения скорости сходимости и стабильности, верно? Каковы шаги самой минимальной процедуры? - person Ecir Hana; 11.12.2013
comment
Да, это основной алгоритм. Можете ли вы проверить, что QxR действительно возвращает исходную матрицу A? На данный момент не обращайте внимания на данные повороты, было бы интереснее, если бы вы могли рассказать о поведении нижнего правого блока 3x3. [Удален предыдущий комментарий и добавлено содержание к ответу выше.] - person Lutz Lehmann; 11.12.2013
comment
Да, это приводит к исходному A. Но я думаю, это потому, что Q является единичной матрицей. Другими словами, когда я делаю RxQ, это всегда приводит к исходной сопутствующей матрице (когда я использую первую ссылку. Со второй ссылкой это работает, как я уже упоминал). - person Ecir Hana; 11.12.2013
comment
См. Приложение II, код предполагает, что x[0] никогда не имеет точного значения 0, что неверно в случае сопутствующих матриц. - person Lutz Lehmann; 11.12.2013
comment
Потрясающе, это работает! Большое спасибо! Небольшое примечание: когда я использую if x[0] < 0: alpha = -alpha, для комплексных чисел не определено отношение порядка. Я изменил его на if x[0].real < 0: alpha = -alpha, и, похоже, он работает. Как вы думаете, это правильное решение? - person Ecir Hana; 12.12.2013
comment
В результате получается знак +1 или -1, так что это работает. Но: ... Размышления Хаусхолдера и QR-разложения для сложных матриц намного сложнее. По сути, используется знак x[0]/abs(x[0]) с дополнительными положениями для x=0. Но проверьте это, если результирующее отражение поменяет местами x и e. - person Lutz Lehmann; 12.12.2013
comment
Кстати, а откуда 10+2*n? Эмпирические тесты? - person Ecir Hana; 12.12.2013
comment
Лишь бы что-нибудь росло с размером матрицы. При попытке его было слишком мало, поэтому я добавил внутренний цикл, чтобы увидеть некоторый прогресс между выходами. За выбором нет глубокой науки. - person Lutz Lehmann; 12.12.2013
comment
Привет! Могу я спросить вас еще об одном? У меня проблема с многочленом x^2-4, так как он не сходится, диагонали выше и ниже просто меняются местами. Я думаю, что это та же проблема (?), что и здесь stackoverflow.com/questions/22261772/power-iteration . Могу ли я что-нибудь с этим сделать? Я думал, что эта матрица-компаньон по поиску корней будет постоянно находить все корни, но теперь кажется, что, по крайней мере, на данный момент, она довольно чувствительна... - person Ecir Hana; 08.03.2014
comment
Алгоритм QR останавливается, если дефляция путем разбиения на диагональные блоки заканчивается матрицей 2x2 или 1x1. Затем решается случай 2x2 путем нахождения характеристического полинома и решения характеристического уравнения. Поэтому нет смысла применять этот метод к квадратичным полиномам. - person Lutz Lehmann; 08.03.2014
comment
Хорошо спасибо! Поэтому, если я попробую x^4-2x^+1, это тоже не сработает, но это потому, что дефляция снова разбивает матрицу на два блока 2x2. Верно? (Кстати, в диагональной печати должно быть A[i][i], а не A[1][i]) - person Ecir Hana; 08.03.2014
comment
Спасибо, исправлено. Как объяснялось в другом потоке, в итерации мощности собственные пространства собственных значений одной и той же величины не разделяются, все они вносят вклад в вектор итерации. Сдвиг (на небольшое случайное число или выполнение двух итераций, один раз вверх на небольшое число и один раз вниз) матрицы разделит собственные пространства, но тогда вектор итераций все равно будет блуждать в собственном пространстве наибольшего собственного значения, если только который имеет размерность 1. С кратностью вам нужен метод, основанный на пространстве Крылова, для определения полного собственного пространства. - person Lutz Lehmann; 08.03.2014