LAPACK + C, странное поведение - PullRequest
2 голосов
/ 23 января 2010

Я пытаюсь решить простую систему линейных уравнений, используя LAPACK. Я использую метод dbsvg, который оптимизирован для полосчатых матриц. Я наблюдал за действительно странным поведением. Когда я заполняю матрицу AT таким образом:

for(i=0; i<DIM;i++) AB[0][i] = -1;
for(i=0; i<DIM;i++) AB[1][i] = 2;
for(i=0; i<DIM;i++) AB[2][i] = -1;
for(i=0; i<3; i++)
    for(j=0;j<DIM;j++) {
        AT[i*DIM+j]=AB[i][j];
    }

И звоните:

dgbsv_(&N, &KL, &KU, &NRHS, AT, &LDAB, myIpiv, x, &LDB, &INFO);

Работает отлично. Однако, когда я делаю это так:

for(i=0; i<DIM;i++) AT[i] = -1;
for(i=0; i<DIM;i++) AT[DIM+i] = 2;
for(i=0; i<DIM;i++) AT[2*DIM+i] = -1;

В результате получается вектор, заполненный NaN. Вот декларации:

double AB[3][DIM], AT[3*DIM];
double x[DIM];
int myIpiv[DIM];
int N=DIM, KL=1, KU=1, NRHS=1, LDAB=DIM, LDB=DIM, INFO;

Есть идеи?

Ответы [ 2 ]

3 голосов
/ 23 января 2010

Вы неправильно размещаете записи в хранилище группы; раньше это работало по счастливой случайности. Документы LAPACK говорят:

    On entry, the matrix A in band storage, in rows KL+1 to
    2*KL+KU+1; rows 1 to KL of the array need not be set.
    The j-th column of A is stored in the j-th column of the
    array AB as follows:
    AB(KL+KU+1+i-j,j) = A(i,j) for max(1,j-KU)<=i<=min(N,j+KL)
    On exit, details of the factorization: U is stored as an
    upper triangular band matrix with KL+KU superdiagonals in
    rows 1 to KL+KU+1, and the multipliers used during the
    factorization are stored in rows KL+KU+2 to 2*KL+KU+1.
    See below for further details.

Так что, если вы хотите трехугольную матрицу с 2 по диагонали и -1 сверху и снизу, расположение должно быть:

 *  *  *  *  *  *  *  ...  *  *  *  *
 * -1 -1 -1 -1 -1 -1  ... -1 -1 -1 -1
 2  2  2  2  2  2  2  ...  2  2  2  2
-1 -1 -1 -1 -1 -1 -1  ... -1 -1 -1  *

В этом случае LDAB должен быть равен 4. Имейте в виду, что LAPACK использует макет для столбца, поэтому фактический массив должен выглядеть в памяти следующим образом:

{ *, *, 2.0, -1.0, *, -1.0, 2.0, -1.0, *, -1.0, 2.0, -1.0, ... }

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

0 голосов
/ 23 января 2010

Это точный код, который вы использовали, или просто пример? Я запустил этот код здесь (просто вырезал и вставил из ваших сообщений, с заменой AT на AT2 во втором цикле:

const int DIM=10;
double AB[DIM][DIM], AT[3*DIM], AT2[3*DIM];
int i,j;

for(i=0; i<DIM;i++) AB[0][i] = -1;
for(i=0; i<DIM;i++) AB[1][i] = 2;
for(i=0; i<DIM;i++) AB[2][i] = -1;
for(i=0; i<3; i++)
        for(j=0;j<DIM;j++) {
                AT[i*DIM+j]=AB[i][j];
        }
printf("AT:");
for (i=0;i<3*DIM;++i) printf("%lf ",AT[i]);
printf("\n\n");
for(i=0; i<DIM;i++) AT2[i] = -1;
for(i=0; i<DIM;i++) AT2[DIM+i] = 2;
for(i=0; i<DIM;i++) AT2[2*DIM+i] = -1;
printf("AT2:");
for (i=0;i<3*DIM;++i) printf("%lf ",AT2[i]);
printf("\n\n");
printf("Diff:");
for (i=0;i<3*DIM;++i) printf("%lf ",AT[i]-AT2[i]);
printf("\n\n");

и получил этот вывод

AT: -1,000000 -1,000000 -1,000000 -1,000000 -1,000000 -1,000000 -1,000000 -1,0000 00 -1.000000 -1.000000 2.000000 2.000000 2.000000 2.000000 2.000000 2.000000 2.0 00000 2,000000 2,000000 2,000000 -1,000000 -1,000000 -1,000000 -1,000000 -1,0000 00 -1,000000 -1,000000 -1,000000 -1,000000 -1,000000

AT2: -1,000000 -1,000000 -1,000000 -1,000000 -1,000000 -1,000000 -1,000000 -1,000 000 -1,000000 -1,000000 2,000000 2.000000 2.000000 2.000000 2.000000 2.000000 2. 000000 2.000000 2.000000 2.000000 -1.000000 -1.000000 -1.000000 -1.000000 -1.000 000 -1,000000 -1,000000 -1,000000 -1,000000 -1,000000

Разница: 0,000000 0,000000 0,000000 0,000000 0,000000 0,000000 0,000000 0,000000 0,0 00000 0,000000 0,000000 0,000000 0,000000 0,000000 0,000000 0,000000 0,000000 0. 000000 0,000000 0,000000 0,000000 0,000000 0,000000 0,000000 0,000000 0,000000 0 .000000 0,000000 0,000000 0,000000

Очевидно, AT и AT2 одинаковы. Что я и ожидал.

...