Lapack + C, seltsames Verhalten
-
22-09-2019 - |
Frage
Ich versuche, ein einfaches System für lineare Gleichungen mit Lapack zu lösen. Ich verwende die DBSVG -Methode, die für bänderte Matrizen optimiert ist. Ich habe ein wirklich seltsames Verhalten beobachtet. Wenn ich die AT -Matrix auf diese Weise fülle:
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];
}
Und Ruf an:
dgbsv_(&N, &KL, &KU, &NRHS, AT, &LDAB, myIpiv, x, &LDB, &INFO);
Es funktioniert perfekt. Wenn ich es jedoch so mache:
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;
Es ergibt sich mit einem mit Nan gefüllten Vektor. Hier sind die Erklärungen:
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;
Irgendwelche Ideen?
Lösung
Sie legen die Einträge im Bandspeicher nicht richtig aus. Es arbeitete zuvor durch einen glücklichen Unfall. Das Lapack -Dokumente sagen:
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.
Wenn Sie also eine triagonale Matrix mit 2 auf der Diagonal und -1 oben und unten wünschen, sollte das Layout sein:
* * * * * * * ... * * * *
* -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 sollte in diesem Fall 4 sein. Denken Sie daran, dass Lapack ein Säulen-Major-Layout verwendet, sodass das tatsächliche Array im Speicher so aussehen sollte:
{ *, *, 2.0, -1.0, *, -1.0, 2.0, -1.0, *, -1.0, 2.0, -1.0, ... }
dgbsv
gab unterschiedliche Ergebnisse für die beiden identischen Arrays, da es die Enden der Arrays, die Sie angelegt hatten, abgelesen wurden.
Andere Tipps
Ist dies der genaue Code, den Sie verwendet haben, oder nur ein Beispiel? Ich habe diesen Code hier geleitet (einfach von Ihren Beiträgen geschnitten und eingefügt, mit einer Änderung von AT to AT2 in der zweiten Schleife:
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");
und bekam diese Ausgabe
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
Diff: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
Anscheinend sind bei und AT2 gleich. Was ich erwarten würde.