Русская Википедия:Итерация Арнольди

Материал из Онлайн справочника
Перейти к навигацииПерейти к поиску

Шаблон:Нет источников В численной линейной алгебре итерация Арнольди является алгоритмом вычисления собственных значений. Арнольди находит приближение собственных значений и собственных векторов матриц общего вида(возможно не эрмитовой) с помощью построения ортонормированного базиса подпространства Крылова.

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

Если алгоритм применяется на эрмитовых матрицах, то он сводится к алгоритму Ланцоша. Итерация Арнольди была придумана Уолтером Эдвином Арнольди в 1951 г.

Подпространство Крылова и степенной метод

Итуитивным методом нахождения наибольшего (по модулю) собственного значения данной матрицы <math>A</math> размерами <math>m \times m</math> является степенной метод: начать с произвольного начального вектора <math>b</math>, вычислить <math>Ab, A^2b, A^3b, \dots</math>, нормирую результат после каждого вычисления.

Эта последовательность сходится к собственному вектору соответствующего собственного значения <math>\lambda_1</math> с максимальным модулем. Это наводит на мысль, что много вычислений тратится впустую, т.к. в итоге используется лишь конечный результат <math>A^{n - 1}b</math>. Тогда давайте вместо этого составим так называемую матрицу Крылова:

<math>K_{n} = \begin{bmatrix}b & Ab & A^{2}b & \cdots & A^{n-1}b \end{bmatrix}.</math>

Столбцы этой матрицы в общем случае не являются ортогональными, но мы можем получить из них ортогональный базис с помощью ортогонализации Грама-Шмидта. Полученное множество векторов будет являться ортогональным базисом подпространства Крылова <math>\mathcal{K}_{n}</math>. Можно ожидать, что вектора этого базиса будут хорошим приближением к векторам, соответствующим <math>n</math> наибольшим по модулю собственным значениям.

Итерация Арнольди

Итерация Арнольди использует стабилизированный процесс Грама-Шмидта для получения последовательности ортонормированных векторов <math>q_1, q_2, q_3, \dots</math>, называемых векторами Арнольди, таких, что для каждого <math>n</math> векторы <math>q_1, \dots, q_n</math> являются базисом подпространства Крылова <math>\mathcal{K}_{n}</math>. Алгоритм выглядит следующим образом:

  • Начать с произвольного вектора q1 с нормой 1.
  • Повторить для k = 2, 3, …
    • <math> q_k \leftarrow Aq_{k-1} \,</math>
    • for j = 1 ... k − 1
      • <math> h_{j,k-1} \leftarrow q_j^* q_k \, </math>
      • <math> q_k \leftarrow q_k - h_{j,k-1} q_j \, </math>
    • <math> h_{k,k-1} \leftarrow \|q_k\| \, </math>
    • <math> q_k \leftarrow \frac{q_k}{h_{k,k-1}} \, </math>

Цикл по <math>j</math> проецирует компоненту <math>q_k</math> на <math>q_1, \dots, q_{k - 1}.</math> Это обеспечивает ортогональность всех построенных векторов.

Алгоритм останавливается, когда <math>q_k</math> является нулевым вектором. Это происходит, когда минимальный многочлен матрицы <math>A</math> будет степени <math>k.</math>

Каждый шаг цикла по <math>k</math> производит одно умножение матрицы на вектор и около <math>4mk</math> операций с дробными числами.

На языке программирования python:

import numpy as np

def arnoldi_iteration(A, b, n: int):
    """Computes a basis of the (n + 1)-Krylov subspace of A: the space
    spanned by {b, Ab, ..., A^n b}.

    Arguments
      A: m × m array
      b: initial vector (length m)
      n: dimension of Krylov subspace, must be >= 1

    Returns
      Q: m x (n + 1) array, the columns are an orthonormal basis of the
        Krylov subspace.
      h: (n + 1) x n array, A on basis Q. It is upper Hessenberg.  
    """
    m = A.shape[0]
    h = np.zeros((n + 1, n))
    Q = np.zeros((m, n + 1))
    q = b / np.linalg.norm(b)  # Normalize the input vector
    Q[:, 0] = q  # Use it as the first Krylov vector

    for k in range(n):
        v = A.dot(q)  # Generate a new candidate vector
        for j in range(k + 1):  # Subtract the projections on previous vectors
            h[j, k] = np.dot(Q[:, j].conj(), v)
            v = v - h[j, k] * Q[:, j]

        h[k + 1, k] = np.linalg.norm(v)
        eps = 1e-12  # If v is shorter than this threshold it is the zero vector
        if h[k + 1, k] > eps:  # Add the produced vector to the list, unless
            q = v / h[k + 1, k]  # the zero vector is produced.
            Q[:, k + 1] = q
        else:  # If that happens, stop iterating.
            return Q, h
    return Q, h