他のものと同様に、私はコレスキーをお勧めします。私は、加算、減算、およびメモリアクセスの数が増えると、LDLtがコレスキーよりも遅いことが分かりました。
実際には、コレスキーにはいくつかのバリエーションがあります。どちらが最速になるかは、使用するマトリックスの表現によって異なります。私は一般的に行列MであるM(i、j)がm [i + dim * j]であるdouble * Mです。これについては、上部の三角形のコレスキーが最も速いと考えています。つまり、U '* U = Mの上三角形のUを探します。
固定小規模な次元については、ループを使用しません。これを行うための比較的簡単な方法は、それを行うプログラムを書くことです。私が思い出しているように、一般的なケースをテンプレートとして扱うルーチンを使用すると、特定の固定ディメンションバージョンを書き込むプログラムを書くのは朝のみでした。節約はかなりの可能性があります。たとえば、私の一般的なバージョンでは9倍の9倍分解を行うのに0.47秒かかりますが、無能なバージョンでは0.17秒かかります。これらのタイミングは2.6GHzのPCでシングルスレッドで実行されます。
これは重要な作業ではないことを示すために、私は以下のようなプログラムのソースを含めました。これには、因子分解の一般バージョンがコメントとして含まれています。私は行列が特異に近くない状況でこのコードを使用しました。しかし、それはあまりにも繊細な作業のためにあまりにも粗すぎるかもしれません。
/* ----------------------------------------------------------------
** to write fixed dimension ut cholesky routines
** ----------------------------------------------------------------
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <strings.h>
/* ----------------------------------------------------------------
*/
#if 0
static inline double vec_dot_1_1(int dim, const double* x, const double* y)
{
double d = 0.0;
while(--dim >= 0)
{ d += *x++ * *y++;
}
return d;
}
/* ----------------------------------------------------------------
** ut cholesky: solve U'*U = P for ut U in P (only ut of P accessed)
** ----------------------------------------------------------------
*/
int mat_ut_cholesky(int dim, double* P)
{
int i, j;
double d;
double* Ucoli;
for(Ucoli=P, i=0; i<dim; ++i, Ucoli+=dim)
{ /* U[i,i] = P[i,i] - Sum{ k<i | U[k,i]*U[k,i]} */
d = Ucoli[i] - vec_dot_1_1(i, Ucoli, Ucoli);
if (d < 0.0)
{ return 0;
}
Ucoli[i] = sqrt(d);
d = 1.0/Ucoli[i];
for(j=i+1; j<dim; ++j)
{ /* U[i,j] = (P[i,j] - Sum{ k<i | U[k,i]*U[k,j]})/U[i,i] */
P[i+j*dim] = d*(P[i+j*dim] - vec_dot_1_1(i, Ucoli, P+j*dim));
}
}
return 1;
}
/* ----------------------------------------------------------------
*/
#endif
/* ----------------------------------------------------------------
**
** ----------------------------------------------------------------
*/
static void write_ut_inner_step(int dim, int i, int off)
{
int j, k, l;
printf("\td = 1.0/P[%d];\n", i+off);
for(j=i+1; j<dim; ++j)
{ k = i+j*dim;
printf("\tP[%d] = d * ", k);
if (i)
{ printf("(P[%d]", k);
printf(" - (P[%d]*P[%d]", off, j*dim);
for(l=1; l<i; ++l)
{ printf(" + P[%d]*P[%d]", l+off, l+j*dim);
}
printf("));");
}
else
{ printf("P[%d];", k);
}
printf("\n");
}
}
static void write_dot(int n, int off)
{
int i;
printf("P[%d]*P[%d]", off, off);
for(i=1; i<n; ++i)
{ printf("+P[%d]*P[%d]", off+i, off+i);
}
}
static void write_ut_outer_step(int dim, int i, int off)
{
printf("\td = P[%d]", off+i);
if (i)
{ printf(" - (");
write_dot(i, off);
printf(")");
}
printf(";\n");
printf("\tif (d <= 0.0)\n");
printf("\t{\treturn 0;\n");
printf("\t}\n");
printf("\tP[%d] = sqrt(d);\n", i+off);
if (i < dim-1)
{ write_ut_inner_step(dim, i, off);
}
}
static void write_ut_chol(int dim)
{
int i;
int off=0;
printf("int\tut_chol_%.2d(double* P)\n", dim);
printf("{\n");
printf("double\td;\n");
for(i=0; i<dim; ++i)
{ write_ut_outer_step(dim, i, off);
printf("\n");
off += dim;
}
printf("\treturn 1;\n");
printf("}\n");
}
/* ----------------------------------------------------------------
*/
/* ----------------------------------------------------------------
**
** ----------------------------------------------------------------
*/
static int read_args(int* dim, int argc, char** argv)
{
while(argc)
{ if (strcmp(*argv, "-h") == 0)
{ return 0;
}
else if (strcmp(*argv, "-d") == 0)
{ --argc; ++argv;
*dim = atoi((--argc, *argv++));
}
else
{ break;
}
}
return 1;
}
int main(int argc, char** argv)
{
int dim = 9;
if(read_args(&dim, --argc, ++argv))
{ write_ut_chol(dim);
}
else
{ fprintf(stderr, "usage: wchol (-d dim)? -- writes to stdout\n");
}
return EXIT_SUCCESS;
}
/* ----------------------------------------------------------------
*/
あなたの質問は、http://scicomp.stackexchange.com/によく合います。 – biziclop
注釈ありがとうございました – qble
scicompに関する質問を再投稿することをお勧めします。ただし、いくつかの追加情報を指定する必要があります。 1)「何百万回も解決した」とはどういう意味ですか?何百万もの異なる右辺用語を持つ同じ係数行列、または何百万もの異なる行列? 2)正の_semi_definiteは、行列が特異で(機械精度に)なる可能性があることを意味します。どのようにこのケースに対処したいですか?ちょうどエラーを起こすか、または賢明な答えを返そうとしますか? –