00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <QVCholmodSolver>
00026
00027 QVCholmodSolver::QVCholmodSolver(const QVSparseBlockMatrix &sparseA)
00028 {
00029 chA = NULL;
00030 nnz = 0;
00031 asize = sparseA.getMajorRows();
00032 bsize = sparseA.getMinorRows();
00033 csize = asize*bsize;
00034
00035 diagonal = QVector<QVMatrix>( asize, QVMatrix(bsize, bsize, 0.0) );
00036 offdiagonal = QVector< QMap<int, QVMatrix> >(asize);
00037
00038 foreach(int ib, sparseA.keys())
00039 {
00040 const QMap<int, QVMatrix> &majorRow = sparseA[ib];
00041 foreach(int jb, majorRow.keys())
00042 {
00043 const QVMatrix &qvblockMatrix = majorRow[jb];
00044
00045 if (ib == jb)
00046 diagonal[ib] = diagonal[ib] + qvblockMatrix;
00047 else {
00048 offdiagonal[jb][ib] = qvblockMatrix;
00049 offdiagonal[ib][jb] = qvblockMatrix.transpose();
00050 }
00051 }
00052 }
00053
00054 cholmod_start(&Common);
00055 }
00056
00057 QVCholmodSolver::~QVCholmodSolver()
00058 {
00059 cholmod_free_sparse(&chA, &Common);
00060 cholmod_finish (&Common);
00061 }
00062
00063
00064
00065
00066 void QVCholmodSolver::init()
00067 {
00068
00069
00070 nnz = asize * bsize * (bsize+1) / 2;
00071 for (int i=0; i< asize; i++)
00072 nnz += bsize * bsize * offdiagonal[i].count();
00073
00074 chA = cholmod_allocate_sparse(csize, csize, nnz, true, true, 1, CHOLMOD_REAL, &Common);
00075
00076
00077 int colp = 0,
00078 *Ap = (int *)chA->p,
00079 *Ai = (int *)chA->i;
00080
00081 for (int ib=0; ib < asize; ib++)
00082 {
00083 const QMap<int, QVMatrix> &column = offdiagonal[ib];
00084
00085 const int numCols = column.count();
00086
00087
00088 for (int k=0; k<bsize; k++)
00089 {
00090 *Ap++ = colp;
00091
00092
00093 if (numCols > 0)
00094
00095 foreach(int jb, column.keys())
00096 for (int j=0, row = bsize*jb; j<bsize; j++)
00097 Ai[colp++] = row++;
00098
00099
00100 for (int kk=0, row = bsize*ib; kk<k+1; kk++)
00101 Ai[colp++] = row++;
00102 }
00103 }
00104
00105 *Ap = nnz;
00106
00107
00108 colp = 0;
00109 double *Ax = (double *)chA->x;
00110
00111 for (int ib=0; ib < asize; ib++)
00112 {
00113 const QMap<int, QVMatrix> &column = offdiagonal[ib];
00114
00115 const int numCols = column.count();
00116
00117
00118 for (int k=0; k<bsize; k++)
00119 {
00120
00121 if (numCols > 0)
00122
00123 foreach(int jb, column.keys())
00124 {
00125 const QVMatrix &m = column[jb];
00126 for (int j=0; j<bsize; j++)
00127 Ax[colp++] = m(j,k);
00128 }
00129
00130 const QVMatrix &m = diagonal[ib];
00131 for (int kk=0; kk<k+1; kk++)
00132 Ax[colp++] = m(kk,k);
00133 }
00134 }
00135 }
00136
00137
00138 bool QVCholmodSolver::solve(QVVector &qvX, QVVector &qvB)
00139 {
00140
00141
00142
00143 cholmod_dense b;
00144 b.nrow = csize;
00145 b.ncol = 1;
00146 b.d = csize;
00147 b.xtype = CHOLMOD_REAL;
00148 b.dtype = CHOLMOD_DOUBLE;
00149 b.x = qvB.data();
00150
00151
00152 cholmod_factor *L = cholmod_analyze (chA, &Common) ;
00153
00154
00155 cholmod_factorize (chA, L, &Common) ;
00156
00157
00158 cholmod_dense *x = cholmod_solve (CHOLMOD_A, L, &b, &Common) ;
00159 qvX = QVVector(csize, (double *)x->x);
00160
00161
00162
00163 cholmod_dense *R = cholmod_copy_dense (&b, &Common);
00164 double one [2] = { 1.0, 0.0 }, minusone [2] = { -1.0, 0.0 };
00165 cholmod_sdmult(chA, 0, minusone, one, x, R, &Common);
00166 cholmod_dense *R2 = cholmod_solve(CHOLMOD_A, L, R, &Common);
00167
00168 for (int i=0 ; i<csize ; i++)
00169 qvX[i] += ((double *)R2->x)[i];
00170
00171
00172 cholmod_free_dense (&R2, &Common);
00173 cholmod_free_dense (&R, &Common);
00174 cholmod_free_factor (&L, &Common);
00175 cholmod_free_dense (&x, &Common);
00176
00177 return true;
00178 }
00179
00180