Текст подпрограммы и версий
aes4r_c.zip , aes4d_c.zip
Тексты тестовых примеров
taes4r_c.zip , taes4d_c.zip

Подпрограмма:  aes4r_c

Назначение

Вычисление нескольких крайних собственных значений и соответствующих собственных векторов вещественной симметричной разреженной или имеющей регулярную структуру матрицы методом Ланцоша с выборочной ортогонализацией.

Математическое описание

Метод Ланцоша для заданной симметричной матрицы А порядка N и начального вектора  v  EN,  v ≠ 0, строит последовательность векторов  v1, v2,..., vj и последовательность трехдиагональных матриц T1, T2,..., Tj по следующим формулам

(1)       v1 = v / (vTv)1/2  ,     β1 = 0  , 
            ui = Avi - βivi -1  ,     αi = uiTvi  , 

  T1 =  α1 ,                            i = 1 ,

           |               |   0  |
           |               |   .   |
  Ti =   |    Ti-1     |  0   |  ,          i > 1 ,
           | ______ |  βi  |
           | 0 ... 0  βi  αi  |

   wi +1 = ui - αivi ,    βi +1 = (wTi +1wi +1)1/2 ,

   vi +1 = wi +1 / βi +1  ,    i = 1,..., j 

Метод Ланцоша может быть рассмотрен как реализация для спектральной задачи Az = λz метода проекций Ритца - Галеркина на последовательность подпространств Крылова

     K( j )  =  span { v1,  Av1,... , Aj -1 v1 }   ,     j = 1,... , N   , 

при этом числа Ритца (собственные значения сужения оператора PjA на K ( j ), где Pj - ортогональный проект на K ( j ) ) совпадают с собственными значениями θi ( j ), i = 1,..., j, матрицы Tj, получаемой на  j - ом шаге метода Ланцоша, а векторы Ритца равны Vjsi ( j ), где  si ( j ) - соответствующие θi ( j ) собственные векторы Tj, а Vj - матрица, столбцами которой являются векторы Ланцоша  v1, v2,..., vj.

Полезной особенностью метода Ланцоша является то, что часто уже при  j ~ 2√N крайние пары Ритца ( θi ( j ), Vj sj ( j ) ) оказываются хорошими приближениями к искомым крайним собственным парам матрицы А.

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

В подпрограмме aes4r_c используется метод Ланцоша с выборочной ортогонализацией - устойчивая к влиянию ошибок округления модификация простого метода Ланцоша, отличающаяся от него тем, что на некоторых шагах процесса (1) проводится ортогонализация  wj + 1 относительно некоторых векторов Ритца.

В подпрограмме aes4r_c предполагается, что || A || 2 ~ 1, где || A || 2 - спектральная норма матрицы. Гарантированной точностью по невязке для вычисляемых собственных векторов является величина  k || A ||2√ε, где  ε - относительная машинная точность,  k ~ 1, но часто возможно получение лучшей точности.

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

Б.Парлетт. Симметричная проблема собственных значений. Численные методы. М.: Мир, 1983.

Использование

    int aes4r_c (integer *n, integer *kl, integer *kr, real *ff,
                 real *eps, integer *m, real *vj, integer *k, integer *l, real *r, 
                 real *r1, real *r2, real *ev, real *er, real *v, real *y, integer *ip)

Параметры

n - порядок исходной матрицы, (тип: целый);
kl, kr - задаваемые соответственно число наименьших и число наибольших собственных значений и соответствующих собственных векторов, которые требуется вычислить (тип: целый);
ff - имя подпрограммы вычисления   w : = ( A - sI ) v - w; первый оператор подпрограммы должен иметь вид:
 
int ff (float *v, float *w, int *n, float *s)
Здесь:
v - заданный вещественный вектор длины n;
w - вещественный вектор длины n, содержащий на входе в подпрограмму заданный вектор, а на выходе из программы - вычисленный вектор ( A - sI ) v - w;
n - порядок матрицы a (тип: целый);
s - простая переменная (тип: вещественный);
eps - заданная требуемая точность по невязке для вычисляемых собственных значений и соответствующих собственных векторов (тип: вещественный);
m - целая переменная, содержащая на входе в подпрограмму задаваемое максимальное число шагов алгоритма, а на выходе из подпрограммы - число выполненных шагов;
vj - вещественный вектор длины n, содержащий на входе в подпрограмму заданный начальный вектор; если vj = 0, то в качестве начального будет взят вектор  v1 = (1., 1., ... , 1.) t;
k - заданное максимальное число вычисляемых собственых значений и соответствующих собственных векторов матриц tj,  k ≥ kl + kr + 2 (тип: целый);
l - длина рабочего вектора r (тип: целый), l ≥ m (k + 9) + 8k;
r - вещественный рабочий вектор длины l, использемый как рабочий;
r1, r2 - вещественные рабочие вектора длины n, используемые как рабочие;
ev - вещественный вектор длины (kl + kr), в первых kl компонентах которого на выходе из подпрограммы содержатся в порядке неубывания вычисленные kl наименьших собственных значений, а в последних kr компонентах в порядке невозрастания - kr наибольших собственных значений;
er - вещественный вектор длины (kl + kr), содержащий невязки er ( i ) = || Ayi - er ( i ) yi ||, где  yi = yi - вычисленный нормированный собственный вектор матрицы A соответствующий собственному значению er ( i ),  1 ≤ i ≤ kl + kr;
v - вещественный двумерный массив размерности n * mmax, в столбцах которого в ходе работы подпрограммы располагаются вычисленные векторы Ланцоша  v1, v2, ..., vmmax;
y - вещественный двумерный массив размерности n * k, в  i - ом, 1 ≤ i ≤ kl + kr, столбце которого на выходе из подпрограммы содержится вычисленный нормированный собственный вектор, соответствующий выходному значению ev ( i );
ip - простая целочисленная переменная, содержащая на входе в подпрограмму признак рещаемой задачи, при этом:
ip = 1 - если требуется выполнить ровно m шагов алгоритма;
ip = 0 - если допустим выход из программы при  j < m,  j - число выполненных шагов; в этом случае вычисления будут прекращены после того, как на некотором шаге  j  будет получено заданное число приближений к собственным парам матрицы A с заданной точностью;
  на выходе из подпрограммы ip содержит признак выхода, причем:
ip = -1 - если заданное значение параметра l не удовлетворяет неравенству l ≥ m * (9 + k) + 8k;
ip = -2 - если заданное значение параметра k не удовлетворяет неравенству k ≥ kl + kr + 2;
ip = -3 - если обе описанные выше ошибки имели место;
ip =  0 - если требуемые собственные значения и соответствующие собственные векторы вычислены с заданной точностью;
ip =  1 - если выполнено заданное число m шагов алгоритма, а заданная точность еще не достигнута;
ip =  2 - если на некотором шаге  j,  j < m, алгоритма потребовалось вычислить более k собственных пар матрицы Tj; в этом случае для продолжения процесса не хватает памяти;
ip =  3 - если заданная точность не может быть достигнута;
ip =  4 - если получено слишком малое значение  βj + 1;
ip =  5 - если резко возрастает объем работ по проведению выборочной ортогонализации.

Версии

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

Вызываемые подпрограммы

avz6r_c - упорядочивание вектора по возрастанию его компонент с запоминанием произведенных перестановок;
avz2r_c - нахождение максимальной по модулю компоненты и ее индекса из всего вектора или из заданного подмножества компонент этого вектора;
av02r_c - вычисление евклидовой нормы вектора;
av04a_c - вычисление скалярного произведения в режиме накопления;
am05r_c - вычисление произведения матрицы на вектор.

Замечания по использованию

  1.  Наименование подпрограммы, соответствующей формальному параметру ff, должно быть указано в операторе extern в программе пользователя, вызывающей aes4r_c;
 
  2.  Подпpогpамма ff должна сохранять вектор v;
 
  3.  Если начальный вектор был выбран неудачно (имел нулевые составляющие вдоль направлений некоторых из искомых собственных векторов), то возможно, что вычисленные векторы не обязательно будут приближениями именно к тем собственным векторам, которые соответствуют первым kl и последним kr собственным значениям. Поэтому, вообще говоря, для проверки необходимо обратиться к aes4r_c с начальными векторами. Особенно это необходимо, если на выходе из программы ip = 4 или мало выходное значение параметра m;
 
  4.  Неудачный выбор начального вектора может привести к выходу из подпрограммы на шаге с номером  j < kl + kr по признаку ip = 4. В этом случае будут вычислены все  j  собственных пар, причем все  j  вычисленных собственных значений будут расположены в массиве ev в порядке неубывания. Понятно, что в этом случае повторное обращение к подпрограмме совершенно необходимо;
 
  5.  Если на выходе из подпрограммы ip < 0, то никакой информации об искомых собственных парах получено не будет; если же ip > 0, то на выходе из подпрограммы будут получены kl первых и kr последних пар Ритца, вычисленных на шаге прерывания (номер этого шага - выходное значение m), т.е. будут получены приближения к искомым собственным парам, хотя их точность и не является удовлетворительной. Эти приближения могут быть использованы для построения нового начального вектора и повторного обращения к aes4r_c;
 
  6.  Если на выходе из подпрограммы ip = 2, то необходимо увеличить значение параметра k и соответственно l. Рекомендации для выбора значения k, которые были бы удовлетворительными для любых матриц, не могут быть даны, т.к. требуемое значение k зависит от спектра исходной матрицы и равно числу пар Ритца, невязки которых станут величинами ~ || A || √ε к тому моменту, когда невязки для заданного числа крайних пар Ритца станут меньше eps;
 
  7.  В подпpогpамме aes4d_c паpаметpы eps, vj, r, r1, r2, ev, er, v, y имеют тип double;
 
  8.  Подпpогpаммы aes4r1_c (aes4d1_c), aes0r0_c (aes0d0_c), av04r1_c (av04d1_c) используются в качестве рабочих;
 
  9.  В подпpогpамме ff паpаметpы v, w, s должны иметь тип double.

Пример использования

int main(void)
{
    /* Initialized data */
    static float vj[6] = { 1.f,1.f,1.f,1.f,1.f,1.f };

    /* Local variables */
    extern int aes4r_c(int *, int *, int *, U_fp, float *, int *, float *,
                       int *, int *, float *, float *, float *, float *,
                       float *, float *, float *, int *);
    static int i__, m;
    static float r__[97], v[30] /* was [6][5] */, y[12] /* was [6][2] */;
    extern int f0_c();
    static float r1[6], r2[6], er[2];
    static int ip;
    static float ev[2];

#define y_ref(a_1,a_2) y[(a_2)*6 + a_1 - 7]

    m = 5;
    ip = 0;
    aes4r_c(&c__6, &c__0, &c__2, (U_fp)f0_c, &c_b4, &m, vj, &c__4, &c__97, r__,
            r1, r2, ev, er, v, y, &ip);

    printf("\n %5i %5i \n", ip, m);
    if (ip < 0) {
        goto l55;
    }
    printf("\n %17.7e %17.7e \n", ev[0], ev[1]);
    for (i__ = 1; i__ <= 6; ++i__) {
        printf("\n %17.7e %17.7e \n", y_ref(i__,1), y_ref(i__,2));
    }
    printf("\n %17.7e %17.7e \n", er[0], er[1]);
l55:
    return 0;
} /* main */


int f0_c(float *x, float *z__, int *n, float *s)
{
    /* Initialized data */
    static float rab[6] = { 0.f,1e-5f,2e-5f,3e-5f,.1f,1.f };

    /* System generated locals */
    int i__1;

    /* Local variables */
    static int i__;

    /* Parameter adjustments */
    --z__;
    --x;

    /* Function Body */
    i__1 = *n;
    for (i__ = 1; i__ <= i__1; ++i__) {
        z__[i__] = (rab[i__ - 1] - *s) * x[i__] - z__[i__];
/* l10: */
    }
    return 0;
} /* f0_c */


Результаты:

         ip  =  0   ,     m  =  3
        
         coбcтвeнныe значения:

         ev(1)  =  1.   ,     ev(2)  =  0.1
         
         coбcтвeнныe векторы:  

                   |   5.e - 7           2.e - 4  |
                   | - 6.e - 7           5.e - 5  |
                   | - 2.e - 6         - 6.e - 5  |
      y_ref  =   | - 3.e - 6         - 2.e - 4  |
                   |   1.e - 6         - 1.          |
                   |   1.                   3.e - 6  |
                     
         нeвязkи:     er(1)  =  4.e - 6   ,     er(2)  =  2.e - 5