Текст подпрограммы и версий
aes0r_c.zip
Тексты тестовых примеров
taes0r_c.zip

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

Назначение

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

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

Метод Ланцоша для заданной симметричной матрицы А порядка N и начального вектора v  ЕN ,  v ≠ 0 ,  строит последовательность векторов Ланцоша  v1, v2, ..., vj и последовательность трехдиагональных матриц  Т1, Т2, ..., Тj по следующим формулам процесса (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-1v1 }  ,   j = 1, ..., N  , 

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

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

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

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

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

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

Выход из подпрограммы происходит, когда все требуемые собственные пары будут вычислены с точностью ЕРS по невязке, где ЕРS задаваемая величина, или по заданному максимально допустимому числу NI крупных шагов.

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

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

    int aes0r_c (integer *n, integer *kl, integer *kr, integer *f, real *
                 eps, integer *l, real *r, real *ev, real *y, real *er, integer *ip)

Параметры

n - порядок исходной матрицы (тип: целый);
kl, kr - задаваемые соответственно число наименьших и число наибольших вычисляемых собственных значений и соответствующих собственных векторов (тип: целый);
            kl0 -             kr0   целочисленные переменные, содержащие на входе в подпрограмму соответственно число наименьших и число наибольших уже вычисленных (c точностью по невязке) собственных значений и соответствующих собственных векторов; при первом обращении к aes0r_c нужно положить kl0 = 0, kr0 = 0, на выходе из подпрограммы значения kl0 и kr0 имеют тот же смысл, но с учетом собственных значений и векторов, полученных в результате работы подпрограммы;
m - задаваемое максимальное число шагов алгоритма в одном крупном шаге (тип: целый);
ni - целочисленная переменная, содержащая на входе в подпрограмму максимальное число крупных шагов алгоритма, а на выходе из подпрограммы - число выполненных крупных шагов;
vj - вещественный вектор длины n, содержащий на входе в подпрограмму задаваемый начальный вектор; если вектор vj задан нулевым, то в качестве начального вектора будет использован вектор (1, 1, ..., 1)T ;
f - имя подпрограммы вычисления w:  = (A - s*I) v - w ; первый оператор подпрограммы должен иметь вид:
 
int f (float *v, float *w, int *n, float *s)
Здесь:
v - заданный вещественный вектор длины n;
w - вещественный вектор длины n, содержащий на входе в подпрограмму заданный вектор, а на выходе из подпрограммы - вычисленный вектор (A - s*I) v - w ;
n - порядок матрицы A (тип: целый);
s - простая переменная (тип: вещественный);
eps - задаваемая относительная точность вычисляемых собственных значений и соответствующих собственных векторов, оцениваемая по отношению нормы невязки к спектральной норме матрицы A (тип: вещественный);
l - длина вектора r, указанная в операторе описания этого вектора в вызывающей подпрограмме (тип: целый);
l ≥ n*(m + kl + kr + 4) + m*(kl + kr + 14) +
      + 9*(kl + kr) + 37;
r - вещественный вектор длины l, используемый как рабочий;
ev - вещественный вектор длины kl + kr, содержащий на входе в подпрограмму при kl0 + kr0 > 0 в своих первых (kl0 + kr0) компонентах уже вычисленные собственные значения; на выходе из подпрограммы в первых компонентах вектора ev содержатся в порядке неубывания вычисленные наименьшие собственные значения, a в последних kr компонентах в порядке невозрастания - вычисленные наибольшие собственные значения;
y - двумерный вещественный массив размерности n на (kl + kr), содержащий на входе в подпрограмму при kl0 + kr0 ≠ 0 в своем i - ом столбце, 1 ≤ i ≤ kl0 + kr0 , нормированный собственный вектор, соответствующий входному значению ev(i), а на выходе из подпрограммы в i - ом столбце, 1 ≤ i ≤ kl + kr , содержится вычисленный нормированный собственный вектор, соответствующий выходному значению ev (i);
er - вещественный вектор длины kl + kr, в i - ой компоненте которого содержится невязка || Ayi - ev (i) * yi || , соответствующая вектору yi , расположенному в i - ом столбце массива y ; при этом входные значения er (i) должны соответствовать входным значениям yi и ev (i) , а выходные значения er (i) соответствуют выходным значениям  yi и ev (i) ;
ip - целочисленная переменная, содержащая на входе в подпрограмму признак тестового повтора, причем
ip = 0 ,  если повтор не нужен;
ip = 1 ,  если нужен;
  на выходе из подпрограммы ip содержит признак выхода из подпрограммы, причем
ip = 0 ,  если все требуемые собственные значения и соответствующие собственные векторы вычислены с заданной точностью и, если требовалось, то проведен тестовый повтор;
ip = 1 ,  если выполнено заданное число крупных шагов, а требуемая точность еще не достигнута;
ip = 2 ,  если заданное число собственных значений и соответствующих векторов вычислено с заданной точностью, но тестовый повтор не проведен;
ip = 3 ,  если требуемая точность не может быть достигнута;
ip =-1 ,  если заданное значение параметра l не удовлетворяет неравенству
l ≥ n*(m + kl + kr + 4) + m*(kl + kr + 14) +
      + 9*(kl + kr) + 37 .

Версии : нет

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

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

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

  1. 

Наименование подпрограммы, соответствующей формальному параметру ff, должно быть указано в операторе extern в подпрограмме пользователя, вызывающей aes0r_c.

  2. 

Подпрограмма ff должна сохранять вектор v.

  3. 

Если при первом обращении к aes0r_c не все требуемые собственные значения были вычислены с заданной точностью, то к aes0r_c можно обратиться повторно. При этом нужно задать kl0 (kr0) - число уже вычисленных с заданной точностью наименьших (наибольших) собственных значений, расположить в первых (kl0 + kr0) столбцах массива y уже вычисленные с заданной точностью нормированные собственные векторы, в первых (kl0 + kr0) компонентах ev - соответствующие собственные значения, в первых компонентах r - соответствующие значения невязок. Тогда aes0r_c будет искать оставшиеся собственные векторы, не вычисляя повторно уже вычисленные.

  4.  Подпрограммы av04r1_c, aes0r0_c, aes0r1_c используются в качестве рабочих.

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

f0_c - подпрограмма пользователя, вычисляющая w:  = (A - s*I)v - w
       для a = diag (0., 1.e-5, 2.e-5, 3.e-5, 0.1, 1.)

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 aes0r_c(int *, int *, int *, int *, int *, int *, int *,
                       float *, U_fp, float *, int *, float *, float *,
                       float *, float *, int *);
    static int i__;
    static float y[12] /* was [6][2] */;
    extern int f0_c();
    static float er[2];
    static int ni, ip;
    static float ev[2];
    static int kl0, kr0;
    static float rab[211];

    kl0 = 0;
    kr0 = 0;
    ip = 0;
    ni = 1;
    aes0r_c(&c__6, &c__0, &c__2, &kl0, &kr0, &c__5, &ni, vj, (U_fp)f0_c, &c_b5,
            &c__211, rab, ev, y, er, &ip);

    printf("\n %16.7e %16.7e \n", ev[0], ev[1]);
    printf("\n %13.2e %13.2e \n", er[0], er[1]);
    printf("\n %5i %5i \n", ip, ni);
    for (i__ = 0; i__ <= 9; i__+=3) {
        printf("\n %10.2e %10.2e %10.2e \n", y[i__], y[i__+1], y[i__+2]);
    }
    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 */


Результаты:

       ev = (1., 0.1) ,   er = (2.2e-11, 2.2e-9) ,   ip = 0 ,   ni = 1 ,
  
       y1  =  (-1.1e-11,  1.1e-11,  1.1e-11,  -1.2e-11,  -2.0e-13,  1.)t
       y2  =  (-1.1e-8,  1.1e-8,  1.1e-8,  -1.1e-8,  -1.,  1.2e-10) .