| 1 | /* $Id: ClpCholeskyTaucs.cpp 1665 2011-01-04 17:55:54Z lou $ */ |
| 2 | #ifdef TAUCS_BARRIER |
| 3 | // Copyright (C) 2004, International Business Machines |
| 4 | // Corporation and others. All Rights Reserved. |
| 5 | // This code is licensed under the terms of the Eclipse Public License (EPL). |
| 6 | |
| 7 | |
| 8 | #include "CoinPragma.hpp" |
| 9 | #include "CoinHelperFunctions.hpp" |
| 10 | #include "ClpHelperFunctions.hpp" |
| 11 | |
| 12 | #include "ClpInterior.hpp" |
| 13 | #include "ClpCholeskyTaucs.hpp" |
| 14 | #include "ClpMessage.hpp" |
| 15 | |
| 16 | //############################################################################# |
| 17 | // Constructors / Destructor / Assignment |
| 18 | //############################################################################# |
| 19 | |
| 20 | //------------------------------------------------------------------- |
| 21 | // Default Constructor |
| 22 | //------------------------------------------------------------------- |
| 23 | ClpCholeskyTaucs::ClpCholeskyTaucs () |
| 24 | : ClpCholeskyBase(), |
| 25 | matrix_(NULL), |
| 26 | factorization_(NULL), |
| 27 | sparseFactorT_(NULL), |
| 28 | choleskyStartT_(NULL), |
| 29 | choleskyRowT_(NULL), |
| 30 | sizeFactorT_(0), |
| 31 | rowCopyT_(NULL) |
| 32 | { |
| 33 | type_ = 13; |
| 34 | } |
| 35 | |
| 36 | //------------------------------------------------------------------- |
| 37 | // Copy constructor |
| 38 | //------------------------------------------------------------------- |
| 39 | ClpCholeskyTaucs::ClpCholeskyTaucs (const ClpCholeskyTaucs & rhs) |
| 40 | : ClpCholeskyBase(rhs) |
| 41 | { |
| 42 | type_ = rhs.type_; |
| 43 | // For Taucs stuff is done by malloc |
| 44 | matrix_ = rhs.matrix_; |
| 45 | sizeFactorT_ = rhs.sizeFactorT_; |
| 46 | if (matrix_) { |
| 47 | choleskyStartT_ = (int *) malloc((numberRows_ + 1) * sizeof(int)); |
| 48 | CoinMemcpyN(rhs.choleskyStartT_, (numberRows_ + 1), choleskyStartT_); |
| 49 | choleskyRowT_ = (int *) malloc(sizeFactorT_ * sizeof(int)); |
| 50 | CoinMemcpyN(rhs.choleskyRowT_, sizeFactorT_, choleskyRowT_); |
| 51 | sparseFactorT_ = (double *) malloc(sizeFactorT_ * sizeof(double)); |
| 52 | CoinMemcpyN(rhs.sparseFactorT_, sizeFactorT_, sparseFactorT_); |
| 53 | matrix_->colptr = choleskyStartT_; |
| 54 | matrix_->rowind = choleskyRowT_; |
| 55 | matrix_->values.d = sparseFactorT_; |
| 56 | } else { |
| 57 | sparseFactorT_ = NULL; |
| 58 | choleskyStartT_ = NULL; |
| 59 | choleskyRowT_ = NULL; |
| 60 | } |
| 61 | factorization_ = NULL, |
| 62 | rowCopyT_ = rhs.rowCopyT_->clone(); |
| 63 | } |
| 64 | |
| 65 | |
| 66 | //------------------------------------------------------------------- |
| 67 | // Destructor |
| 68 | //------------------------------------------------------------------- |
| 69 | ClpCholeskyTaucs::~ClpCholeskyTaucs () |
| 70 | { |
| 71 | taucs_ccs_free(matrix_); |
| 72 | if (factorization_) |
| 73 | taucs_supernodal_factor_free(factorization_); |
| 74 | delete rowCopyT_; |
| 75 | } |
| 76 | |
| 77 | //---------------------------------------------------------------- |
| 78 | // Assignment operator |
| 79 | //------------------------------------------------------------------- |
| 80 | ClpCholeskyTaucs & |
| 81 | ClpCholeskyTaucs::operator=(const ClpCholeskyTaucs& rhs) |
| 82 | { |
| 83 | if (this != &rhs) { |
| 84 | ClpCholeskyBase::operator=(rhs); |
| 85 | taucs_ccs_free(matrix_); |
| 86 | if (factorization_) |
| 87 | taucs_supernodal_factor_free(factorization_); |
| 88 | factorization_ = NULL; |
| 89 | sizeFactorT_ = rhs.sizeFactorT_; |
| 90 | matrix_ = rhs.matrix_; |
| 91 | if (matrix_) { |
| 92 | choleskyStartT_ = (int *) malloc((numberRows_ + 1) * sizeof(int)); |
| 93 | CoinMemcpyN(rhs.choleskyStartT_, (numberRows_ + 1), choleskyStartT_); |
| 94 | choleskyRowT_ = (int *) malloc(sizeFactorT_ * sizeof(int)); |
| 95 | CoinMemcpyN(rhs.choleskyRowT_, sizeFactorT_, choleskyRowT_); |
| 96 | sparseFactorT_ = (double *) malloc(sizeFactorT_ * sizeof(double)); |
| 97 | CoinMemcpyN(rhs.sparseFactorT_, sizeFactorT_, sparseFactorT_); |
| 98 | matrix_->colptr = choleskyStartT_; |
| 99 | matrix_->rowind = choleskyRowT_; |
| 100 | matrix_->values.d = sparseFactorT_; |
| 101 | } else { |
| 102 | sparseFactorT_ = NULL; |
| 103 | choleskyStartT_ = NULL; |
| 104 | choleskyRowT_ = NULL; |
| 105 | } |
| 106 | delete rowCopyT_; |
| 107 | rowCopyT_ = rhs.rowCopyT_->clone(); |
| 108 | } |
| 109 | return *this; |
| 110 | } |
| 111 | //------------------------------------------------------------------- |
| 112 | // Clone |
| 113 | //------------------------------------------------------------------- |
| 114 | ClpCholeskyBase * ClpCholeskyTaucs::clone() const |
| 115 | { |
| 116 | return new ClpCholeskyTaucs(*this); |
| 117 | } |
| 118 | /* Orders rows and saves pointer to matrix.and model */ |
| 119 | int |
| 120 | ClpCholeskyTaucs::order(ClpInterior * model) |
| 121 | { |
| 122 | numberRows_ = model->numberRows(); |
| 123 | rowsDropped_ = new char [numberRows_]; |
| 124 | memset(rowsDropped_, 0, numberRows_); |
| 125 | numberRowsDropped_ = 0; |
| 126 | model_ = model; |
| 127 | rowCopyT_ = model->clpMatrix()->reverseOrderedCopy(); |
| 128 | const CoinBigIndex * columnStart = model_->clpMatrix()->getVectorStarts(); |
| 129 | const int * columnLength = model_->clpMatrix()->getVectorLengths(); |
| 130 | const int * row = model_->clpMatrix()->getIndices(); |
| 131 | const CoinBigIndex * rowStart = rowCopyT_->getVectorStarts(); |
| 132 | const int * rowLength = rowCopyT_->getVectorLengths(); |
| 133 | const int * column = rowCopyT_->getIndices(); |
| 134 | // We need two arrays for counts |
| 135 | int * which = new int [numberRows_]; |
| 136 | int * used = new int[numberRows_]; |
| 137 | CoinZeroN(used, numberRows_); |
| 138 | int iRow; |
| 139 | sizeFactorT_ = 0; |
| 140 | for (iRow = 0; iRow < numberRows_; iRow++) { |
| 141 | int number = 1; |
| 142 | // make sure diagonal exists |
| 143 | which[0] = iRow; |
| 144 | used[iRow] = 1; |
| 145 | if (!rowsDropped_[iRow]) { |
| 146 | CoinBigIndex startRow = rowStart[iRow]; |
| 147 | CoinBigIndex endRow = rowStart[iRow] + rowLength[iRow]; |
| 148 | for (CoinBigIndex k = startRow; k < endRow; k++) { |
| 149 | int iColumn = column[k]; |
| 150 | CoinBigIndex start = columnStart[iColumn]; |
| 151 | CoinBigIndex end = columnStart[iColumn] + columnLength[iColumn]; |
| 152 | for (CoinBigIndex j = start; j < end; j++) { |
| 153 | int jRow = row[j]; |
| 154 | if (jRow >= iRow && !rowsDropped_[jRow]) { |
| 155 | if (!used[jRow]) { |
| 156 | used[jRow] = 1; |
| 157 | which[number++] = jRow; |
| 158 | } |
| 159 | } |
| 160 | } |
| 161 | } |
| 162 | sizeFactorT_ += number; |
| 163 | int j; |
| 164 | for (j = 0; j < number; j++) |
| 165 | used[which[j]] = 0; |
| 166 | } |
| 167 | } |
| 168 | delete [] which; |
| 169 | // Now we have size - create arrays and fill in |
| 170 | matrix_ = taucs_ccs_create(numberRows_, numberRows_, sizeFactorT_, |
| 171 | TAUCS_DOUBLE | TAUCS_SYMMETRIC | TAUCS_LOWER); |
| 172 | if (!matrix_) |
| 173 | return 1; |
| 174 | // Space for starts |
| 175 | choleskyStartT_ = matrix_->colptr; |
| 176 | choleskyRowT_ = matrix_->rowind; |
| 177 | sparseFactorT_ = matrix_->values.d; |
| 178 | sizeFactorT_ = 0; |
| 179 | which = choleskyRowT_; |
| 180 | for (iRow = 0; iRow < numberRows_; iRow++) { |
| 181 | int number = 1; |
| 182 | // make sure diagonal exists |
| 183 | which[0] = iRow; |
| 184 | used[iRow] = 1; |
| 185 | choleskyStartT_[iRow] = sizeFactorT_; |
| 186 | if (!rowsDropped_[iRow]) { |
| 187 | CoinBigIndex startRow = rowStart[iRow]; |
| 188 | CoinBigIndex endRow = rowStart[iRow] + rowLength[iRow]; |
| 189 | for (CoinBigIndex k = startRow; k < endRow; k++) { |
| 190 | int iColumn = column[k]; |
| 191 | CoinBigIndex start = columnStart[iColumn]; |
| 192 | CoinBigIndex end = columnStart[iColumn] + columnLength[iColumn]; |
| 193 | for (CoinBigIndex j = start; j < end; j++) { |
| 194 | int jRow = row[j]; |
| 195 | if (jRow >= iRow && !rowsDropped_[jRow]) { |
| 196 | if (!used[jRow]) { |
| 197 | used[jRow] = 1; |
| 198 | which[number++] = jRow; |
| 199 | } |
| 200 | } |
| 201 | } |
| 202 | } |
| 203 | sizeFactorT_ += number; |
| 204 | int j; |
| 205 | for (j = 0; j < number; j++) |
| 206 | used[which[j]] = 0; |
| 207 | // Sort |
| 208 | std::sort(which, which + number); |
| 209 | // move which on |
| 210 | which += number; |
| 211 | } |
| 212 | } |
| 213 | choleskyStartT_[numberRows_] = sizeFactorT_; |
| 214 | delete [] used; |
| 215 | permuteInverse_ = new int [numberRows_]; |
| 216 | permute_ = new int[numberRows_]; |
| 217 | int * perm, *invp; |
| 218 | // There seem to be bugs in ordering if model too small |
| 219 | if (numberRows_ > 10) |
| 220 | taucs_ccs_order(matrix_, &perm, &invp, (const char *) "genmmd" ); |
| 221 | else |
| 222 | taucs_ccs_order(matrix_, &perm, &invp, (const char *) "identity" ); |
| 223 | CoinMemcpyN(perm, numberRows_, permuteInverse_); |
| 224 | free(perm); |
| 225 | CoinMemcpyN(invp, numberRows_, permute_); |
| 226 | free(invp); |
| 227 | // need to permute |
| 228 | taucs_ccs_matrix * permuted = taucs_ccs_permute_symmetrically(matrix_, permuteInverse_, permute_); |
| 229 | // symbolic |
| 230 | factorization_ = taucs_ccs_factor_llt_symbolic(permuted); |
| 231 | taucs_ccs_free(permuted); |
| 232 | return factorization_ ? 0 : 1; |
| 233 | } |
| 234 | /* Does Symbolic factorization given permutation. |
| 235 | This is called immediately after order. If user provides this then |
| 236 | user must provide factorize and solve. Otherwise the default factorization is used |
| 237 | returns non-zero if not enough memory */ |
| 238 | int |
| 239 | ClpCholeskyTaucs::symbolic() |
| 240 | { |
| 241 | return 0; |
| 242 | } |
| 243 | /* Factorize - filling in rowsDropped and returning number dropped */ |
| 244 | int |
| 245 | ClpCholeskyTaucs::factorize(const double * diagonal, int * rowsDropped) |
| 246 | { |
| 247 | const CoinBigIndex * columnStart = model_->clpMatrix()->getVectorStarts(); |
| 248 | const int * columnLength = model_->clpMatrix()->getVectorLengths(); |
| 249 | const int * row = model_->clpMatrix()->getIndices(); |
| 250 | const double * element = model_->clpMatrix()->getElements(); |
| 251 | const CoinBigIndex * rowStart = rowCopyT_->getVectorStarts(); |
| 252 | const int * rowLength = rowCopyT_->getVectorLengths(); |
| 253 | const int * column = rowCopyT_->getIndices(); |
| 254 | const double * elementByRow = rowCopyT_->getElements(); |
| 255 | int numberColumns = model_->clpMatrix()->getNumCols(); |
| 256 | int iRow; |
| 257 | double * work = new double[numberRows_]; |
| 258 | CoinZeroN(work, numberRows_); |
| 259 | const double * diagonalSlack = diagonal + numberColumns; |
| 260 | int newDropped = 0; |
| 261 | double largest; |
| 262 | //perturbation |
| 263 | double perturbation = model_->diagonalPerturbation() * model_->diagonalNorm(); |
| 264 | perturbation = perturbation * perturbation; |
| 265 | if (perturbation > 1.0) { |
| 266 | //if (model_->model()->logLevel()&4) |
| 267 | std::cout << "large perturbation " << perturbation << std::endl; |
| 268 | perturbation = sqrt(perturbation); |
| 269 | perturbation = 1.0; |
| 270 | } |
| 271 | for (iRow = 0; iRow < numberRows_; iRow++) { |
| 272 | double * put = sparseFactorT_ + choleskyStartT_[iRow]; |
| 273 | int * which = choleskyRowT_ + choleskyStartT_[iRow]; |
| 274 | int number = choleskyStartT_[iRow+1] - choleskyStartT_[iRow]; |
| 275 | if (!rowLength[iRow]) |
| 276 | rowsDropped_[iRow] = 1; |
| 277 | if (!rowsDropped_[iRow]) { |
| 278 | CoinBigIndex startRow = rowStart[iRow]; |
| 279 | CoinBigIndex endRow = rowStart[iRow] + rowLength[iRow]; |
| 280 | work[iRow] = diagonalSlack[iRow]; |
| 281 | for (CoinBigIndex k = startRow; k < endRow; k++) { |
| 282 | int iColumn = column[k]; |
| 283 | CoinBigIndex start = columnStart[iColumn]; |
| 284 | CoinBigIndex end = columnStart[iColumn] + columnLength[iColumn]; |
| 285 | double multiplier = diagonal[iColumn] * elementByRow[k]; |
| 286 | for (CoinBigIndex j = start; j < end; j++) { |
| 287 | int jRow = row[j]; |
| 288 | if (jRow >= iRow && !rowsDropped_[jRow]) { |
| 289 | double value = element[j] * multiplier; |
| 290 | work[jRow] += value; |
| 291 | } |
| 292 | } |
| 293 | } |
| 294 | int j; |
| 295 | for (j = 0; j < number; j++) { |
| 296 | int jRow = which[j]; |
| 297 | put[j] = work[jRow]; |
| 298 | work[jRow] = 0.0; |
| 299 | } |
| 300 | } else { |
| 301 | // dropped |
| 302 | int j; |
| 303 | for (j = 1; j < number; j++) { |
| 304 | put[j] = 0.0; |
| 305 | } |
| 306 | put[0] = 1.0; |
| 307 | } |
| 308 | } |
| 309 | //check sizes |
| 310 | double largest2 = maximumAbsElement(sparseFactorT_, sizeFactorT_); |
| 311 | largest2 *= 1.0e-19; |
| 312 | largest = CoinMin(largest2, 1.0e-11); |
| 313 | int numberDroppedBefore = 0; |
| 314 | for (iRow = 0; iRow < numberRows_; iRow++) { |
| 315 | int dropped = rowsDropped_[iRow]; |
| 316 | // Move to int array |
| 317 | rowsDropped[iRow] = dropped; |
| 318 | if (!dropped) { |
| 319 | CoinBigIndex start = choleskyStartT_[iRow]; |
| 320 | double diagonal = sparseFactorT_[start]; |
| 321 | if (diagonal > largest2) { |
| 322 | sparseFactorT_[start] = diagonal + perturbation; |
| 323 | } else { |
| 324 | sparseFactorT_[start] = diagonal + perturbation; |
| 325 | rowsDropped[iRow] = 2; |
| 326 | numberDroppedBefore++; |
| 327 | } |
| 328 | } |
| 329 | } |
| 330 | taucs_supernodal_factor_free_numeric(factorization_); |
| 331 | // need to permute |
| 332 | taucs_ccs_matrix * permuted = taucs_ccs_permute_symmetrically(matrix_, permuteInverse_, permute_); |
| 333 | int rCode = taucs_ccs_factor_llt_numeric(permuted, factorization_); |
| 334 | taucs_ccs_free(permuted); |
| 335 | if (rCode) |
| 336 | printf("return code of %d from factor\n" , rCode); |
| 337 | delete [] work; |
| 338 | choleskyCondition_ = 1.0; |
| 339 | bool cleanCholesky; |
| 340 | if (model_->numberIterations() < 200) |
| 341 | cleanCholesky = true; |
| 342 | else |
| 343 | cleanCholesky = false; |
| 344 | /* |
| 345 | How do I find out where 1.0e100's are in cholesky? |
| 346 | */ |
| 347 | if (cleanCholesky) { |
| 348 | //drop fresh makes some formADAT easier |
| 349 | int oldDropped = numberRowsDropped_; |
| 350 | if (newDropped || numberRowsDropped_) { |
| 351 | std::cout << "Rank " << numberRows_ - newDropped << " ( " << |
| 352 | newDropped << " dropped)" ; |
| 353 | if (newDropped > oldDropped) |
| 354 | std::cout << " ( " << newDropped - oldDropped << " dropped this time)" ; |
| 355 | std::cout << std::endl; |
| 356 | newDropped = 0; |
| 357 | for (int i = 0; i < numberRows_; i++) { |
| 358 | char dropped = rowsDropped[i]; |
| 359 | rowsDropped_[i] = dropped; |
| 360 | if (dropped == 2) { |
| 361 | //dropped this time |
| 362 | rowsDropped[newDropped++] = i; |
| 363 | rowsDropped_[i] = 0; |
| 364 | } |
| 365 | } |
| 366 | numberRowsDropped_ = newDropped; |
| 367 | newDropped = -(1 + newDropped); |
| 368 | } |
| 369 | } else { |
| 370 | if (newDropped) { |
| 371 | newDropped = 0; |
| 372 | for (int i = 0; i < numberRows_; i++) { |
| 373 | char dropped = rowsDropped[i]; |
| 374 | int oldDropped = rowsDropped_[i]; |
| 375 | rowsDropped_[i] = dropped; |
| 376 | if (dropped == 2) { |
| 377 | assert (!oldDropped); |
| 378 | //dropped this time |
| 379 | rowsDropped[newDropped++] = i; |
| 380 | rowsDropped_[i] = 1; |
| 381 | } |
| 382 | } |
| 383 | } |
| 384 | numberRowsDropped_ += newDropped; |
| 385 | if (numberRowsDropped_) { |
| 386 | std::cout << "Rank " << numberRows_ - numberRowsDropped_ << " ( " << |
| 387 | numberRowsDropped_ << " dropped)" ; |
| 388 | if (newDropped) { |
| 389 | std::cout << " ( " << newDropped << " dropped this time)" ; |
| 390 | } |
| 391 | std::cout << std::endl; |
| 392 | } |
| 393 | } |
| 394 | status_ = 0; |
| 395 | return newDropped; |
| 396 | } |
| 397 | /* Uses factorization to solve. */ |
| 398 | void |
| 399 | ClpCholeskyTaucs::solve (double * region) |
| 400 | { |
| 401 | double * in = new double[numberRows_]; |
| 402 | double * out = new double[numberRows_]; |
| 403 | taucs_vec_permute(numberRows_, TAUCS_DOUBLE, region, in, permuteInverse_); |
| 404 | int rCode = taucs_supernodal_solve_llt(factorization_, out, in); |
| 405 | if (rCode) |
| 406 | printf("return code of %d from solve\n" , rCode); |
| 407 | taucs_vec_permute(numberRows_, TAUCS_DOUBLE, out, region, permute_); |
| 408 | delete [] out; |
| 409 | delete [] in; |
| 410 | } |
| 411 | #endif |
| 412 | |