$search
00001 /* 00002 * OpenNL: Numerical Library 00003 * Copyright (C) 2004 Bruno Levy 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License as published by 00007 * the Free Software Foundation; either version 2 of the License, or 00008 * (at your option) any later version. 00009 * 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 * GNU General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU General Public License 00016 * along with this program; if not, write to the Free Software 00017 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00018 * 00019 * If you modify this software, you should include a notice giving the 00020 * name of the person performing the modification, the date of modification, 00021 * and the reason for such modification. 00022 * 00023 * Contact: Bruno Levy 00024 * 00025 * levy@loria.fr 00026 * 00027 * ISA Project 00028 * LORIA, INRIA Lorraine, 00029 * Campus Scientifique, BP 239 00030 * 54506 VANDOEUVRE LES NANCY CEDEX 00031 * FRANCE 00032 * 00033 * Note that the GNU General Public License does not permit incorporating 00034 * the Software into proprietary programs. 00035 */ 00036 00037 #include <NL/nl_matrix.h> 00038 00039 void nlRowColumnConstruct(NLRowColumn* c) { 00040 c->size = 0 ; 00041 c->capacity = 0 ; 00042 c->coeff = NULL ; 00043 } 00044 00045 void nlRowColumnDestroy(NLRowColumn* c) { 00046 NL_DELETE_ARRAY(c->coeff) ; 00047 #ifdef NL_PARANOID 00048 NL_CLEAR(NLRowColumn, c) ; 00049 #endif 00050 } 00051 00052 void nlRowColumnGrow(NLRowColumn* c) { 00053 if(c->capacity != 0) { 00054 c->capacity = 2 * c->capacity ; 00055 c->coeff = NL_RENEW_ARRAY(NLCoeff, c->coeff, c->capacity) ; 00056 } else { 00057 c->capacity = 4 ; 00058 c->coeff = NL_NEW_ARRAY(NLCoeff, c->capacity) ; 00059 } 00060 } 00061 00062 void nlRowColumnAdd(NLRowColumn* c, NLint index, NLdouble value) { 00063 NLuint i ; 00064 for(i=0; i<c->size; i++) { 00065 if(c->coeff[i].index == index) { 00066 c->coeff[i].value += value ; 00067 return ; 00068 } 00069 } 00070 if(c->size == c->capacity) { 00071 nlRowColumnGrow(c) ; 00072 } 00073 c->coeff[c->size].index = index ; 00074 c->coeff[c->size].value = value ; 00075 c->size++ ; 00076 } 00077 00078 /* Does not check whether the index already exists */ 00079 void nlRowColumnAppend(NLRowColumn* c, NLint index, NLdouble value) { 00080 if(c->size == c->capacity) { 00081 nlRowColumnGrow(c) ; 00082 } 00083 c->coeff[c->size].index = index ; 00084 c->coeff[c->size].value = value ; 00085 c->size++ ; 00086 } 00087 00088 void nlRowColumnZero(NLRowColumn* c) { 00089 c->size = 0 ; 00090 } 00091 00092 void nlRowColumnClear(NLRowColumn* c) { 00093 c->size = 0 ; 00094 c->capacity = 0 ; 00095 NL_DELETE_ARRAY(c->coeff) ; 00096 } 00097 00098 static int nlCoeffCompare(void* p1, void* p2) { 00099 return (((NLCoeff*)(p2))->index > ((NLCoeff*)(p1))->index) ; 00100 } 00101 00102 void nlRowColumnSort(NLRowColumn* c) { 00103 qsort(c->coeff, c->size, sizeof(NLCoeff), nlCoeffCompare) ; 00104 } 00105 00106 /************************************************************************************/ 00107 /* SparseMatrix data structure */ 00108 00109 void nlSparseMatrixConstruct( 00110 NLSparseMatrix* M, NLuint m, NLuint n, NLenum storage 00111 ) { 00112 NLuint i ; 00113 M->m = m ; 00114 M->n = n ; 00115 M->storage = storage ; 00116 if(storage & NL_MATRIX_STORE_ROWS) { 00117 M->row = NL_NEW_ARRAY(NLRowColumn, m) ; 00118 for(i=0; i<n; i++) { 00119 nlRowColumnConstruct(&(M->row[i])) ; 00120 } 00121 } else { 00122 M->row = NULL ; 00123 } 00124 00125 if(storage & NL_MATRIX_STORE_COLUMNS) { 00126 M->column = NL_NEW_ARRAY(NLRowColumn, n) ; 00127 for(i=0; i<n; i++) { 00128 nlRowColumnConstruct(&(M->column[i])) ; 00129 } 00130 } else { 00131 M->column = NULL ; 00132 } 00133 00134 M->diag_size = MIN(m,n) ; 00135 M->diag = NL_NEW_ARRAY(NLdouble, M->diag_size) ; 00136 } 00137 00138 void nlSparseMatrixDestroy(NLSparseMatrix* M) { 00139 NLuint i ; 00140 NL_DELETE_ARRAY(M->diag) ; 00141 if(M->storage & NL_MATRIX_STORE_ROWS) { 00142 for(i=0; i<M->m; i++) { 00143 nlRowColumnDestroy(&(M->row[i])) ; 00144 } 00145 NL_DELETE_ARRAY(M->row) ; 00146 } 00147 if(M->storage & NL_MATRIX_STORE_COLUMNS) { 00148 for(i=0; i<M->n; i++) { 00149 nlRowColumnDestroy(&(M->column[i])) ; 00150 } 00151 NL_DELETE_ARRAY(M->column) ; 00152 } 00153 #ifdef NL_PARANOID 00154 NL_CLEAR(NLSparseMatrix,M) ; 00155 #endif 00156 } 00157 00158 void nlSparseMatrixAdd( 00159 NLSparseMatrix* M, NLuint i, NLuint j, NLdouble value 00160 ) { 00161 nl_parano_range_assert(i, 0, M->m - 1) ; 00162 nl_parano_range_assert(j, 0, M->n - 1) ; 00163 if((M->storage & NL_MATRIX_STORE_SYMMETRIC) && (j > i)) { 00164 return ; 00165 } 00166 if(i == j) { 00167 M->diag[i] += value ; 00168 } 00169 if(M->storage & NL_MATRIX_STORE_ROWS) { 00170 nlRowColumnAdd(&(M->row[i]), j, value) ; 00171 } 00172 if(M->storage & NL_MATRIX_STORE_COLUMNS) { 00173 nlRowColumnAdd(&(M->column[j]), i, value) ; 00174 } 00175 } 00176 00177 void nlSparseMatrixZero( NLSparseMatrix* M) { 00178 NLuint i ; 00179 if(M->storage & NL_MATRIX_STORE_ROWS) { 00180 for(i=0; i<M->m; i++) { 00181 nlRowColumnZero(&(M->row[i])) ; 00182 } 00183 } 00184 if(M->storage & NL_MATRIX_STORE_COLUMNS) { 00185 for(i=0; i<M->n; i++) { 00186 nlRowColumnZero(&(M->column[i])) ; 00187 } 00188 } 00189 NL_CLEAR_ARRAY(NLdouble, M->diag, M->diag_size) ; 00190 } 00191 00192 void nlSparseMatrixClear( NLSparseMatrix* M) { 00193 NLuint i ; 00194 if(M->storage & NL_MATRIX_STORE_ROWS) { 00195 for(i=0; i<M->m; i++) { 00196 nlRowColumnClear(&(M->row[i])) ; 00197 } 00198 } 00199 if(M->storage & NL_MATRIX_STORE_COLUMNS) { 00200 for(i=0; i<M->n; i++) { 00201 nlRowColumnClear(&(M->column[i])) ; 00202 } 00203 } 00204 NL_CLEAR_ARRAY(NLdouble, M->diag, M->diag_size) ; 00205 } 00206 00207 /* Returns the number of non-zero coefficients */ 00208 NLuint nlSparseMatrixNNZ( NLSparseMatrix* M) { 00209 NLuint nnz = 0 ; 00210 NLuint i ; 00211 if(M->storage & NL_MATRIX_STORE_ROWS) { 00212 for(i = 0; i<M->m; i++) { 00213 nnz += M->row[i].size ; 00214 } 00215 } else if (M->storage & NL_MATRIX_STORE_COLUMNS) { 00216 for(i = 0; i<M->n; i++) { 00217 nnz += M->column[i].size ; 00218 } 00219 } else { 00220 nl_assert_not_reached ; 00221 } 00222 return nnz ; 00223 } 00224 00225 void nlSparseMatrixSort( NLSparseMatrix* M) { 00226 NLuint i ; 00227 if(M->storage & NL_MATRIX_STORE_ROWS) { 00228 for(i = 0; i<M->m; i++) { 00229 nlRowColumnSort(&(M->row[i])) ; 00230 } 00231 } 00232 if (M->storage & NL_MATRIX_STORE_COLUMNS) { 00233 for(i = 0; i<M->n; i++) { 00234 nlRowColumnSort(&(M->row[i])) ; 00235 } 00236 } 00237 } 00238 00239 /************************************************************************************/ 00240 /* SparseMatrix x Vector routines, internal helper routines */ 00241 00242 static void nlSparseMatrix_mult_rows_symmetric( 00243 NLSparseMatrix* A, NLdouble* x, NLdouble* y 00244 ) { 00245 NLuint m = A->m ; 00246 NLuint i,ij ; 00247 NLRowColumn* Ri = NULL ; 00248 NLCoeff* c = NULL ; 00249 for(i=0; i<m; i++) { 00250 y[i] = 0 ; 00251 Ri = &(A->row[i]) ; 00252 for(ij=0; ij<Ri->size; ij++) { 00253 c = &(Ri->coeff[ij]) ; 00254 y[i] += c->value * x[c->index] ; 00255 if(i != c->index) { 00256 y[c->index] += c->value * x[i] ; 00257 } 00258 } 00259 } 00260 } 00261 00262 static void nlSparseMatrix_mult_rows( 00263 NLSparseMatrix* A, NLdouble* x, NLdouble* y 00264 ) { 00265 NLuint m = A->m ; 00266 NLuint i,ij ; 00267 NLRowColumn* Ri = NULL ; 00268 NLCoeff* c = NULL ; 00269 for(i=0; i<m; i++) { 00270 y[i] = 0 ; 00271 Ri = &(A->row[i]) ; 00272 for(ij=0; ij<Ri->size; ij++) { 00273 c = &(Ri->coeff[ij]) ; 00274 y[i] += c->value * x[c->index] ; 00275 } 00276 } 00277 } 00278 00279 static void nlSparseMatrix_mult_cols_symmetric( 00280 NLSparseMatrix* A, NLdouble* x, NLdouble* y 00281 ) { 00282 NLuint n = A->n ; 00283 NLuint j,ii ; 00284 NLRowColumn* Cj = NULL ; 00285 NLCoeff* c = NULL ; 00286 for(j=0; j<n; j++) { 00287 y[j] = 0 ; 00288 Cj = &(A->column[j]) ; 00289 for(ii=0; ii<Cj->size; ii++) { 00290 c = &(Cj->coeff[ii]) ; 00291 y[c->index] += c->value * x[j] ; 00292 if(j != c->index) { 00293 y[j] += c->value * x[c->index] ; 00294 } 00295 } 00296 } 00297 } 00298 00299 static void nlSparseMatrix_mult_cols( 00300 NLSparseMatrix* A, NLdouble* x, NLdouble* y 00301 ) { 00302 NLuint n = A->n ; 00303 NLuint j,ii ; 00304 NLRowColumn* Cj = NULL ; 00305 NLCoeff* c = NULL ; 00306 NL_CLEAR_ARRAY(NLdouble, y, A->m) ; 00307 for(j=0; j<n; j++) { 00308 Cj = &(A->column[j]) ; 00309 for(ii=0; ii<Cj->size; ii++) { 00310 c = &(Cj->coeff[ii]) ; 00311 y[c->index] += c->value * x[j] ; 00312 } 00313 } 00314 } 00315 00316 /************************************************************************************/ 00317 /* SparseMatrix x Vector routines, main driver routine */ 00318 00319 void nlSparseMatrixMult(NLSparseMatrix* A, NLdouble* x, NLdouble* y) { 00320 if(A->storage & NL_MATRIX_STORE_ROWS) { 00321 if(A->storage & NL_MATRIX_STORE_SYMMETRIC) { 00322 nlSparseMatrix_mult_rows_symmetric(A, x, y) ; 00323 } else { 00324 nlSparseMatrix_mult_rows(A, x, y) ; 00325 } 00326 } else { 00327 if(A->storage & NL_MATRIX_STORE_SYMMETRIC) { 00328 nlSparseMatrix_mult_cols_symmetric(A, x, y) ; 00329 } else { 00330 nlSparseMatrix_mult_cols(A, x, y) ; 00331 } 00332 } 00333 } 00334