| 1 | /* $Id: CoinFactorization2.cpp 1448 2011-06-19 15:34:41Z stefan $ */ |
| 2 | // Copyright (C) 2002, International Business Machines |
| 3 | // Corporation and others. All Rights Reserved. |
| 4 | // This code is licensed under the terms of the Eclipse Public License (EPL). |
| 5 | |
| 6 | #if defined(_MSC_VER) |
| 7 | // Turn off compiler warning about long names |
| 8 | # pragma warning(disable:4786) |
| 9 | #endif |
| 10 | |
| 11 | #include "CoinUtilsConfig.h" |
| 12 | |
| 13 | #include <cassert> |
| 14 | #include <cfloat> |
| 15 | #include <stdio.h> |
| 16 | #include "CoinFactorization.hpp" |
| 17 | #include "CoinIndexedVector.hpp" |
| 18 | #include "CoinHelperFunctions.hpp" |
| 19 | #include "CoinFinite.hpp" |
| 20 | #if DENSE_CODE==1 |
| 21 | // using simple lapack interface |
| 22 | extern "C" |
| 23 | { |
| 24 | /** LAPACK Fortran subroutine DGETRF. */ |
| 25 | void F77_FUNC(dgetrf,DGETRF)(ipfint * m, ipfint *n, |
| 26 | double *A, ipfint *ldA, |
| 27 | ipfint * ipiv, ipfint *info); |
| 28 | } |
| 29 | #endif |
| 30 | #ifndef NDEBUG |
| 31 | static int counter1=0; |
| 32 | #endif |
| 33 | // factorSparse. Does sparse phase of factorization |
| 34 | //return code is <0 error, 0= finished |
| 35 | int |
| 36 | CoinFactorization::factorSparse ( ) |
| 37 | { |
| 38 | int larger; |
| 39 | |
| 40 | if ( numberRows_ < numberColumns_ ) { |
| 41 | larger = numberColumns_; |
| 42 | } else { |
| 43 | larger = numberRows_; |
| 44 | } |
| 45 | int returnCode; |
| 46 | #define LARGELIMIT 65530 |
| 47 | #define SMALL_SET 65531 |
| 48 | #define SMALL_UNSET (SMALL_SET+1) |
| 49 | #define LARGE_SET COIN_INT_MAX-10 |
| 50 | #define LARGE_UNSET (LARGE_SET+1) |
| 51 | if ( larger < LARGELIMIT ) |
| 52 | returnCode = factorSparseSmall(); |
| 53 | else |
| 54 | returnCode = factorSparseLarge(); |
| 55 | return returnCode; |
| 56 | } |
| 57 | // factorSparse. Does sparse phase of factorization |
| 58 | //return code is <0 error, 0= finished |
| 59 | int |
| 60 | CoinFactorization::factorSparseSmall ( ) |
| 61 | { |
| 62 | int *indexRow = indexRowU_.array(); |
| 63 | int *indexColumn = indexColumnU_.array(); |
| 64 | CoinFactorizationDouble *element = elementU_.array(); |
| 65 | int count = 1; |
| 66 | workArea_.conditionalNew(numberRows_); |
| 67 | CoinFactorizationDouble * workArea = workArea_.array(); |
| 68 | #ifndef NDEBUG |
| 69 | counter1++; |
| 70 | #endif |
| 71 | // when to go dense |
| 72 | int denseThreshold=denseThreshold_; |
| 73 | |
| 74 | CoinZeroN ( workArea, numberRows_ ); |
| 75 | //get space for bit work area |
| 76 | CoinBigIndex workSize = 1000; |
| 77 | workArea2_.conditionalNew(workSize); |
| 78 | unsigned int * workArea2 = workArea2_.array(); |
| 79 | |
| 80 | //set markRow so no rows updated |
| 81 | unsigned short * markRow = reinterpret_cast<unsigned short *> (markRow_.array()); |
| 82 | CoinFillN ( markRow, numberRows_, static_cast<unsigned short> (SMALL_UNSET)); |
| 83 | int status = 0; |
| 84 | //do slacks first |
| 85 | int * numberInRow = numberInRow_.array(); |
| 86 | int * numberInColumn = numberInColumn_.array(); |
| 87 | int * numberInColumnPlus = numberInColumnPlus_.array(); |
| 88 | CoinBigIndex * startColumnU = startColumnU_.array(); |
| 89 | CoinBigIndex * startColumnL = startColumnL_.array(); |
| 90 | if (biasLU_<3&&numberColumns_==numberRows_) { |
| 91 | int iPivotColumn; |
| 92 | int * pivotColumn = pivotColumn_.array(); |
| 93 | int * nextRow = nextRow_.array(); |
| 94 | int * lastRow = lastRow_.array(); |
| 95 | for ( iPivotColumn = 0; iPivotColumn < numberColumns_; |
| 96 | iPivotColumn++ ) { |
| 97 | if ( numberInColumn[iPivotColumn] == 1 ) { |
| 98 | CoinBigIndex start = startColumnU[iPivotColumn]; |
| 99 | CoinFactorizationDouble value = element[start]; |
| 100 | if ( value == slackValue_ && numberInColumnPlus[iPivotColumn] == 0 ) { |
| 101 | // treat as slack |
| 102 | int iRow = indexRow[start]; |
| 103 | // but only if row not marked |
| 104 | if (numberInRow[iRow]>0) { |
| 105 | totalElements_ -= numberInRow[iRow]; |
| 106 | //take out this bit of indexColumnU |
| 107 | int next = nextRow[iRow]; |
| 108 | int last = lastRow[iRow]; |
| 109 | |
| 110 | nextRow[last] = next; |
| 111 | lastRow[next] = last; |
| 112 | nextRow[iRow] = numberGoodU_; //use for permute |
| 113 | lastRow[iRow] = -2; //mark |
| 114 | //modify linked list for pivots |
| 115 | deleteLink ( iRow ); |
| 116 | numberInRow[iRow]=-1; |
| 117 | numberInColumn[iPivotColumn]=0; |
| 118 | numberGoodL_++; |
| 119 | startColumnL[numberGoodL_] = 0; |
| 120 | pivotColumn[numberGoodU_] = iPivotColumn; |
| 121 | numberGoodU_++; |
| 122 | } |
| 123 | } |
| 124 | } |
| 125 | } |
| 126 | // redo |
| 127 | preProcess(4); |
| 128 | CoinFillN ( markRow, numberRows_, static_cast<unsigned short> (SMALL_UNSET)); |
| 129 | } |
| 130 | numberSlacks_ = numberGoodU_; |
| 131 | int *nextCount = nextCount_.array(); |
| 132 | int *firstCount = firstCount_.array(); |
| 133 | CoinBigIndex *startRow = startRowU_.array(); |
| 134 | CoinBigIndex *startColumn = startColumnU; |
| 135 | //#define UGLY_COIN_FACTOR_CODING |
| 136 | #ifdef UGLY_COIN_FACTOR_CODING |
| 137 | CoinFactorizationDouble *elementL = elementL_.array(); |
| 138 | int *indexRowL = indexRowL_.array(); |
| 139 | int *saveColumn = saveColumn_.array(); |
| 140 | int *nextRow = nextRow_.array(); |
| 141 | int *lastRow = lastRow_.array() ; |
| 142 | #endif |
| 143 | double pivotTolerance = pivotTolerance_; |
| 144 | int numberTrials = numberTrials_; |
| 145 | int numberRows = numberRows_; |
| 146 | // Put column singletons first - (if false) |
| 147 | separateLinks(1,(biasLU_>1)); |
| 148 | #ifndef NDEBUG |
| 149 | int counter2=0; |
| 150 | #endif |
| 151 | while ( count <= biggerDimension_ ) { |
| 152 | #ifndef NDEBUG |
| 153 | counter2++; |
| 154 | int badRow=-1; |
| 155 | if (counter1==-1&&counter2>=0) { |
| 156 | // check counts consistent |
| 157 | for (int iCount=1;iCount<numberRows_;iCount++) { |
| 158 | int look = firstCount[iCount]; |
| 159 | while ( look >= 0 ) { |
| 160 | if ( look < numberRows_ ) { |
| 161 | int iRow = look; |
| 162 | if (iRow==badRow) |
| 163 | printf("row count for row %d is %d\n" ,iCount,iRow); |
| 164 | if ( numberInRow[iRow] != iCount ) { |
| 165 | printf("failed debug on %d entry to factorSparse and %d try\n" , |
| 166 | counter1,counter2); |
| 167 | printf("row %d - count %d number %d\n" ,iRow,iCount,numberInRow[iRow]); |
| 168 | abort(); |
| 169 | } |
| 170 | look = nextCount[look]; |
| 171 | } else { |
| 172 | int iColumn = look - numberRows; |
| 173 | if ( numberInColumn[iColumn] != iCount ) { |
| 174 | printf("failed debug on %d entry to factorSparse and %d try\n" , |
| 175 | counter1,counter2); |
| 176 | printf("column %d - count %d number %d\n" ,iColumn,iCount,numberInColumn[iColumn]); |
| 177 | abort(); |
| 178 | } |
| 179 | look = nextCount[look]; |
| 180 | } |
| 181 | } |
| 182 | } |
| 183 | } |
| 184 | #endif |
| 185 | CoinBigIndex minimumCount = COIN_INT_MAX; |
| 186 | double minimumCost = COIN_DBL_MAX; |
| 187 | |
| 188 | int iPivotRow = -1; |
| 189 | int iPivotColumn = -1; |
| 190 | int pivotRowPosition = -1; |
| 191 | int pivotColumnPosition = -1; |
| 192 | int look = firstCount[count]; |
| 193 | int trials = 0; |
| 194 | int * pivotColumn = pivotColumn_.array(); |
| 195 | |
| 196 | if ( count == 1 && firstCount[1] >= 0 &&!biasLU_) { |
| 197 | //do column singletons first to put more in U |
| 198 | while ( look >= 0 ) { |
| 199 | if ( look < numberRows_ ) { |
| 200 | look = nextCount[look]; |
| 201 | } else { |
| 202 | int iColumn = look - numberRows_; |
| 203 | |
| 204 | assert ( numberInColumn[iColumn] == count ); |
| 205 | CoinBigIndex start = startColumnU[iColumn]; |
| 206 | int iRow = indexRow[start]; |
| 207 | |
| 208 | iPivotRow = iRow; |
| 209 | pivotRowPosition = start; |
| 210 | iPivotColumn = iColumn; |
| 211 | assert (iPivotRow>=0&&iPivotColumn>=0); |
| 212 | pivotColumnPosition = -1; |
| 213 | look = -1; |
| 214 | break; |
| 215 | } |
| 216 | } /* endwhile */ |
| 217 | if ( iPivotRow < 0 ) { |
| 218 | //back to singletons |
| 219 | look = firstCount[1]; |
| 220 | } |
| 221 | } |
| 222 | while ( look >= 0 ) { |
| 223 | if ( look < numberRows_ ) { |
| 224 | int iRow = look; |
| 225 | #ifndef NDEBUG |
| 226 | if ( numberInRow[iRow] != count ) { |
| 227 | printf("failed on %d entry to factorSparse and %d try\n" , |
| 228 | counter1,counter2); |
| 229 | printf("row %d - count %d number %d\n" ,iRow,count,numberInRow[iRow]); |
| 230 | abort(); |
| 231 | } |
| 232 | #endif |
| 233 | look = nextCount[look]; |
| 234 | bool rejected = false; |
| 235 | CoinBigIndex start = startRow[iRow]; |
| 236 | CoinBigIndex end = start + count; |
| 237 | |
| 238 | CoinBigIndex i; |
| 239 | for ( i = start; i < end; i++ ) { |
| 240 | int iColumn = indexColumn[i]; |
| 241 | assert (numberInColumn[iColumn]>0); |
| 242 | double cost = ( count - 1 ) * numberInColumn[iColumn]; |
| 243 | |
| 244 | if ( cost < minimumCost ) { |
| 245 | CoinBigIndex where = startColumn[iColumn]; |
| 246 | double minimumValue = element[where]; |
| 247 | |
| 248 | minimumValue = fabs ( minimumValue ) * pivotTolerance; |
| 249 | while ( indexRow[where] != iRow ) { |
| 250 | where++; |
| 251 | } /* endwhile */ |
| 252 | assert ( where < startColumn[iColumn] + |
| 253 | numberInColumn[iColumn]); |
| 254 | CoinFactorizationDouble value = element[where]; |
| 255 | |
| 256 | value = fabs ( value ); |
| 257 | if ( value >= minimumValue ) { |
| 258 | minimumCost = cost; |
| 259 | minimumCount = numberInColumn[iColumn]; |
| 260 | iPivotRow = iRow; |
| 261 | pivotRowPosition = -1; |
| 262 | iPivotColumn = iColumn; |
| 263 | assert (iPivotRow>=0&&iPivotColumn>=0); |
| 264 | pivotColumnPosition = i; |
| 265 | rejected=false; |
| 266 | if ( minimumCount < count ) { |
| 267 | look = -1; |
| 268 | break; |
| 269 | } |
| 270 | } else if ( iPivotRow == -1 ) { |
| 271 | rejected = true; |
| 272 | } |
| 273 | } |
| 274 | } |
| 275 | trials++; |
| 276 | if ( trials >= numberTrials && iPivotRow >= 0 ) { |
| 277 | look = -1; |
| 278 | break; |
| 279 | } |
| 280 | if ( rejected ) { |
| 281 | //take out for moment |
| 282 | //eligible when row changes |
| 283 | deleteLink ( iRow ); |
| 284 | addLink ( iRow, biggerDimension_ + 1 ); |
| 285 | } |
| 286 | } else { |
| 287 | int iColumn = look - numberRows; |
| 288 | |
| 289 | assert ( numberInColumn[iColumn] == count ); |
| 290 | look = nextCount[look]; |
| 291 | CoinBigIndex start = startColumn[iColumn]; |
| 292 | CoinBigIndex end = start + numberInColumn[iColumn]; |
| 293 | CoinFactorizationDouble minimumValue = element[start]; |
| 294 | |
| 295 | minimumValue = fabs ( minimumValue ) * pivotTolerance; |
| 296 | CoinBigIndex i; |
| 297 | for ( i = start; i < end; i++ ) { |
| 298 | CoinFactorizationDouble value = element[i]; |
| 299 | |
| 300 | value = fabs ( value ); |
| 301 | if ( value >= minimumValue ) { |
| 302 | int iRow = indexRow[i]; |
| 303 | int nInRow = numberInRow[iRow]; |
| 304 | assert (nInRow>0); |
| 305 | double cost = ( count - 1 ) * nInRow; |
| 306 | |
| 307 | if ( cost < minimumCost ) { |
| 308 | minimumCost = cost; |
| 309 | minimumCount = nInRow; |
| 310 | iPivotRow = iRow; |
| 311 | pivotRowPosition = i; |
| 312 | iPivotColumn = iColumn; |
| 313 | assert (iPivotRow>=0&&iPivotColumn>=0); |
| 314 | pivotColumnPosition = -1; |
| 315 | if ( minimumCount <= count + 1 ) { |
| 316 | look = -1; |
| 317 | break; |
| 318 | } |
| 319 | } |
| 320 | } |
| 321 | } |
| 322 | trials++; |
| 323 | if ( trials >= numberTrials && iPivotRow >= 0 ) { |
| 324 | look = -1; |
| 325 | break; |
| 326 | } |
| 327 | } |
| 328 | } /* endwhile */ |
| 329 | if (iPivotRow>=0) { |
| 330 | assert (iPivotRow<numberRows_); |
| 331 | int numberDoRow = numberInRow[iPivotRow] - 1; |
| 332 | int numberDoColumn = numberInColumn[iPivotColumn] - 1; |
| 333 | |
| 334 | totalElements_ -= ( numberDoRow + numberDoColumn + 1 ); |
| 335 | if ( numberDoColumn > 0 ) { |
| 336 | if ( numberDoRow > 0 ) { |
| 337 | if ( numberDoColumn > 1 ) { |
| 338 | // if (1) { |
| 339 | //need to adjust more for cache and SMP |
| 340 | //allow at least 4 extra |
| 341 | int increment = numberDoColumn + 1 + 4; |
| 342 | |
| 343 | if ( increment & 15 ) { |
| 344 | increment = increment & ( ~15 ); |
| 345 | increment += 16; |
| 346 | } |
| 347 | int increment2 = |
| 348 | |
| 349 | ( increment + COINFACTORIZATION_BITS_PER_INT - 1 ) >> COINFACTORIZATION_SHIFT_PER_INT; |
| 350 | CoinBigIndex size = increment2 * numberDoRow; |
| 351 | |
| 352 | if ( size > workSize ) { |
| 353 | workSize = size; |
| 354 | workArea2_.conditionalNew(workSize); |
| 355 | workArea2 = workArea2_.array(); |
| 356 | } |
| 357 | bool goodPivot; |
| 358 | #ifndef UGLY_COIN_FACTOR_CODING |
| 359 | //branch out to best pivot routine |
| 360 | goodPivot = pivot ( iPivotRow, iPivotColumn, |
| 361 | pivotRowPosition, pivotColumnPosition, |
| 362 | workArea, workArea2, |
| 363 | increment2, markRow , |
| 364 | SMALL_SET); |
| 365 | #else |
| 366 | #define FAC_SET SMALL_SET |
| 367 | #include "CoinFactorization.hpp" |
| 368 | #undef FAC_SET |
| 369 | #undef UGLY_COIN_FACTOR_CODING |
| 370 | #endif |
| 371 | if ( !goodPivot ) { |
| 372 | status = -99; |
| 373 | count=biggerDimension_+1; |
| 374 | break; |
| 375 | } |
| 376 | } else { |
| 377 | if ( !pivotOneOtherRow ( iPivotRow, iPivotColumn ) ) { |
| 378 | status = -99; |
| 379 | count=biggerDimension_+1; |
| 380 | break; |
| 381 | } |
| 382 | } |
| 383 | } else { |
| 384 | assert (!numberDoRow); |
| 385 | if ( !pivotRowSingleton ( iPivotRow, iPivotColumn ) ) { |
| 386 | status = -99; |
| 387 | count=biggerDimension_+1; |
| 388 | break; |
| 389 | } |
| 390 | } |
| 391 | } else { |
| 392 | assert (!numberDoColumn); |
| 393 | if ( !pivotColumnSingleton ( iPivotRow, iPivotColumn ) ) { |
| 394 | status = -99; |
| 395 | count=biggerDimension_+1; |
| 396 | break; |
| 397 | } |
| 398 | } |
| 399 | assert (nextRow_.array()[iPivotRow]==numberGoodU_); |
| 400 | pivotColumn[numberGoodU_] = iPivotColumn; |
| 401 | numberGoodU_++; |
| 402 | // This should not need to be trapped here - but be safe |
| 403 | if (numberGoodU_==numberRows_) |
| 404 | count=biggerDimension_+1; |
| 405 | #if COIN_DEBUG==2 |
| 406 | checkConsistency ( ); |
| 407 | #endif |
| 408 | #if 0 |
| 409 | // Even if no dense code may be better to use naive dense |
| 410 | if (!denseThreshold_&&totalElements_>1000) { |
| 411 | int leftRows=numberRows_-numberGoodU_; |
| 412 | double full = leftRows; |
| 413 | full *= full; |
| 414 | assert (full>=0.0); |
| 415 | double leftElements = totalElements_; |
| 416 | double ratio; |
| 417 | if (leftRows>2000) |
| 418 | ratio=4.0; |
| 419 | else |
| 420 | ratio=3.0; |
| 421 | if (ratio*leftElements>full) |
| 422 | denseThreshold=1; |
| 423 | } |
| 424 | #endif |
| 425 | if (denseThreshold) { |
| 426 | // see whether to go dense |
| 427 | int leftRows=numberRows_-numberGoodU_; |
| 428 | double full = leftRows; |
| 429 | full *= full; |
| 430 | assert (full>=0.0); |
| 431 | double leftElements = totalElements_; |
| 432 | //if (leftRows==100) |
| 433 | //printf("at 100 %d elements\n",totalElements_); |
| 434 | double ratio; |
| 435 | if (leftRows>2000) |
| 436 | ratio=4.0; |
| 437 | else if (leftRows>800) |
| 438 | ratio=3.0; |
| 439 | else if (leftRows>256) |
| 440 | ratio=2.0; |
| 441 | else |
| 442 | ratio=1.5; |
| 443 | if ((ratio*leftElements>full&&leftRows>denseThreshold_)) { |
| 444 | //return to do dense |
| 445 | if (status!=0) |
| 446 | break; |
| 447 | int check=0; |
| 448 | for (int iColumn=0;iColumn<numberColumns_;iColumn++) { |
| 449 | if (numberInColumn[iColumn]) |
| 450 | check++; |
| 451 | } |
| 452 | if (check!=leftRows&&denseThreshold_) { |
| 453 | //printf("** mismatch %d columns left, %d rows\n",check,leftRows); |
| 454 | denseThreshold=0; |
| 455 | } else { |
| 456 | status=2; |
| 457 | if ((messageLevel_&4)!=0) |
| 458 | std::cout<<" Went dense at " <<leftRows<<" rows " << |
| 459 | totalElements_<<" " <<full<<" " <<leftElements<<std::endl; |
| 460 | if (!denseThreshold_) |
| 461 | denseThreshold_=-check; // say how many |
| 462 | break; |
| 463 | } |
| 464 | } |
| 465 | } |
| 466 | // start at 1 again |
| 467 | count = 1; |
| 468 | } else { |
| 469 | //end of this - onto next |
| 470 | count++; |
| 471 | } |
| 472 | } /* endwhile */ |
| 473 | workArea_.conditionalDelete() ; |
| 474 | workArea2_.conditionalDelete() ; |
| 475 | return status; |
| 476 | } |
| 477 | |
| 478 | //:method factorDense. Does dense phase of factorization |
| 479 | //return code is <0 error, 0= finished |
| 480 | int CoinFactorization::factorDense() |
| 481 | { |
| 482 | int status=0; |
| 483 | numberDense_=numberRows_-numberGoodU_; |
| 484 | if (sizeof(CoinBigIndex)==4&&numberDense_>=2<<15) { |
| 485 | abort(); |
| 486 | } |
| 487 | CoinBigIndex full; |
| 488 | if (denseThreshold_>0) |
| 489 | full = numberDense_*numberDense_; |
| 490 | else |
| 491 | full = - denseThreshold_*numberDense_; |
| 492 | totalElements_=full; |
| 493 | denseArea_= new double [full]; |
| 494 | CoinZeroN(denseArea_,full); |
| 495 | densePermute_= new int [numberDense_]; |
| 496 | int * indexRowU = indexRowU_.array(); |
| 497 | //mark row lookup using lastRow |
| 498 | int i; |
| 499 | int * nextRow = nextRow_.array(); |
| 500 | int * lastRow = lastRow_.array(); |
| 501 | int * numberInColumn = numberInColumn_.array(); |
| 502 | int * numberInColumnPlus = numberInColumnPlus_.array(); |
| 503 | for (i=0;i<numberRows_;i++) { |
| 504 | if (lastRow[i]>=0) |
| 505 | lastRow[i]=0; |
| 506 | } |
| 507 | int * indexRow = indexRowU_.array(); |
| 508 | CoinFactorizationDouble * element = elementU_.array(); |
| 509 | int which=0; |
| 510 | for (i=0;i<numberRows_;i++) { |
| 511 | if (!lastRow[i]) { |
| 512 | lastRow[i]=which; |
| 513 | nextRow[i]=numberGoodU_+which; |
| 514 | densePermute_[which]=i; |
| 515 | which++; |
| 516 | } |
| 517 | } |
| 518 | //for L part |
| 519 | CoinBigIndex * startColumnL = startColumnL_.array(); |
| 520 | CoinFactorizationDouble * elementL = elementL_.array(); |
| 521 | int * indexRowL = indexRowL_.array(); |
| 522 | CoinBigIndex endL=startColumnL[numberGoodL_]; |
| 523 | //take out of U |
| 524 | double * column = denseArea_; |
| 525 | int rowsDone=0; |
| 526 | int iColumn=0; |
| 527 | int * pivotColumn = pivotColumn_.array(); |
| 528 | CoinFactorizationDouble * pivotRegion = pivotRegion_.array(); |
| 529 | CoinBigIndex * startColumnU = startColumnU_.array(); |
| 530 | for (iColumn=0;iColumn<numberColumns_;iColumn++) { |
| 531 | if (numberInColumn[iColumn]) { |
| 532 | //move |
| 533 | CoinBigIndex start = startColumnU[iColumn]; |
| 534 | int number = numberInColumn[iColumn]; |
| 535 | CoinBigIndex end = start+number; |
| 536 | for (CoinBigIndex i=start;i<end;i++) { |
| 537 | int iRow=indexRow[i]; |
| 538 | iRow=lastRow[iRow]; |
| 539 | assert (iRow>=0&&iRow<numberDense_); |
| 540 | column[iRow]=element[i]; |
| 541 | } /* endfor */ |
| 542 | column+=numberDense_; |
| 543 | while (lastRow[rowsDone]<0) { |
| 544 | rowsDone++; |
| 545 | } /* endwhile */ |
| 546 | nextRow[rowsDone]=numberGoodU_; |
| 547 | rowsDone++; |
| 548 | startColumnL[numberGoodU_+1]=endL; |
| 549 | numberInColumn[iColumn]=0; |
| 550 | pivotColumn[numberGoodU_]=iColumn; |
| 551 | pivotRegion[numberGoodU_]=1.0; |
| 552 | numberGoodU_++; |
| 553 | } |
| 554 | } |
| 555 | #ifdef DENSE_CODE |
| 556 | if (denseThreshold_>0) { |
| 557 | assert(numberGoodU_==numberRows_); |
| 558 | numberGoodL_=numberRows_; |
| 559 | //now factorize |
| 560 | //dgef(denseArea_,&numberDense_,&numberDense_,densePermute_); |
| 561 | int info; |
| 562 | F77_FUNC(dgetrf,DGETRF)(&numberDense_,&numberDense_,denseArea_,&numberDense_,densePermute_, |
| 563 | &info); |
| 564 | // need to check size of pivots |
| 565 | if(info) |
| 566 | status = -1; |
| 567 | return status; |
| 568 | } |
| 569 | #endif |
| 570 | numberGoodU_ = numberRows_-numberDense_; |
| 571 | int base = numberGoodU_; |
| 572 | int iDense; |
| 573 | int numberToDo=-denseThreshold_; |
| 574 | denseThreshold_=0; |
| 575 | double tolerance = zeroTolerance_; |
| 576 | tolerance = 1.0e-30; |
| 577 | int * nextColumn = nextColumn_.array(); |
| 578 | const int * pivotColumnConst = pivotColumn_.array(); |
| 579 | // make sure we have enough space in L and U |
| 580 | for (iDense=0;iDense<numberToDo;iDense++) { |
| 581 | //how much space have we got |
| 582 | iColumn = pivotColumnConst[base+iDense]; |
| 583 | int next = nextColumn[iColumn]; |
| 584 | int numberInPivotColumn = iDense; |
| 585 | CoinBigIndex space = startColumnU[next] |
| 586 | - startColumnU[iColumn] |
| 587 | - numberInColumnPlus[next]; |
| 588 | //assume no zero elements |
| 589 | if ( numberInPivotColumn > space ) { |
| 590 | //getColumnSpace also moves fixed part |
| 591 | if ( !getColumnSpace ( iColumn, numberInPivotColumn ) ) { |
| 592 | return -99; |
| 593 | } |
| 594 | } |
| 595 | // set so further moves will work |
| 596 | numberInColumn[iColumn]=numberInPivotColumn; |
| 597 | } |
| 598 | // Fill in ? |
| 599 | for (iColumn=numberGoodU_+numberToDo;iColumn<numberRows_;iColumn++) { |
| 600 | nextRow[iColumn]=iColumn; |
| 601 | startColumnL[iColumn+1]=endL; |
| 602 | pivotRegion[iColumn]=1.0; |
| 603 | } |
| 604 | if ( lengthL_ + full*0.5 > lengthAreaL_ ) { |
| 605 | //need more memory |
| 606 | if ((messageLevel_&4)!=0) |
| 607 | std::cout << "more memory needed in middle of invert" << std::endl; |
| 608 | return -99; |
| 609 | } |
| 610 | CoinFactorizationDouble *elementU = elementU_.array(); |
| 611 | for (iDense=0;iDense<numberToDo;iDense++) { |
| 612 | int iRow; |
| 613 | int jDense; |
| 614 | int pivotRow=-1; |
| 615 | double * element = denseArea_+iDense*numberDense_; |
| 616 | CoinFactorizationDouble largest = 1.0e-12; |
| 617 | for (iRow=iDense;iRow<numberDense_;iRow++) { |
| 618 | if (fabs(element[iRow])>largest) { |
| 619 | largest = fabs(element[iRow]); |
| 620 | pivotRow = iRow; |
| 621 | } |
| 622 | } |
| 623 | if ( pivotRow >= 0 ) { |
| 624 | iColumn = pivotColumnConst[base+iDense]; |
| 625 | CoinFactorizationDouble pivotElement=element[pivotRow]; |
| 626 | // get original row |
| 627 | int originalRow = densePermute_[pivotRow]; |
| 628 | // do nextRow |
| 629 | nextRow[originalRow] = numberGoodU_; |
| 630 | lastRow[originalRow] = -2; //mark |
| 631 | // swap |
| 632 | densePermute_[pivotRow]=densePermute_[iDense]; |
| 633 | densePermute_[iDense] = originalRow; |
| 634 | for (jDense=iDense;jDense<numberDense_;jDense++) { |
| 635 | CoinFactorizationDouble value = element[iDense]; |
| 636 | element[iDense] = element[pivotRow]; |
| 637 | element[pivotRow] = value; |
| 638 | element += numberDense_; |
| 639 | } |
| 640 | CoinFactorizationDouble pivotMultiplier = 1.0 / pivotElement; |
| 641 | //printf("pivotMultiplier %g\n",pivotMultiplier); |
| 642 | pivotRegion[numberGoodU_] = pivotMultiplier; |
| 643 | // Do L |
| 644 | element = denseArea_+iDense*numberDense_; |
| 645 | CoinBigIndex l = lengthL_; |
| 646 | startColumnL[numberGoodL_] = l; //for luck and first time |
| 647 | for (iRow=iDense+1;iRow<numberDense_;iRow++) { |
| 648 | CoinFactorizationDouble value = element[iRow]*pivotMultiplier; |
| 649 | element[iRow] = value; |
| 650 | if (fabs(value)>tolerance) { |
| 651 | indexRowL[l] = densePermute_[iRow]; |
| 652 | elementL[l++] = value; |
| 653 | } |
| 654 | } |
| 655 | numberGoodL_++; |
| 656 | lengthL_ = l; |
| 657 | startColumnL[numberGoodL_] = l; |
| 658 | // update U column |
| 659 | CoinBigIndex start = startColumnU[iColumn]; |
| 660 | for (iRow=0;iRow<iDense;iRow++) { |
| 661 | if (fabs(element[iRow])>tolerance) { |
| 662 | indexRowU[start] = densePermute_[iRow]; |
| 663 | elementU[start++] = element[iRow]; |
| 664 | } |
| 665 | } |
| 666 | numberInColumn[iColumn]=0; |
| 667 | numberInColumnPlus[iColumn] += start-startColumnU[iColumn]; |
| 668 | startColumnU[iColumn]=start; |
| 669 | // update other columns |
| 670 | double * element2 = element+numberDense_; |
| 671 | for (jDense=iDense+1;jDense<numberToDo;jDense++) { |
| 672 | CoinFactorizationDouble value = element2[iDense]; |
| 673 | for (iRow=iDense+1;iRow<numberDense_;iRow++) { |
| 674 | //double oldValue=element2[iRow]; |
| 675 | element2[iRow] -= value*element[iRow]; |
| 676 | //if (oldValue&&!element2[iRow]) { |
| 677 | //printf("Updated element for column %d, row %d old %g", |
| 678 | // pivotColumnConst[base+jDense],densePermute_[iRow],oldValue); |
| 679 | //printf(" new %g\n",element2[iRow]); |
| 680 | //} |
| 681 | } |
| 682 | element2 += numberDense_; |
| 683 | } |
| 684 | numberGoodU_++; |
| 685 | } else { |
| 686 | return -1; |
| 687 | } |
| 688 | } |
| 689 | // free area (could use L?) |
| 690 | delete [] denseArea_; |
| 691 | denseArea_ = NULL; |
| 692 | // check if can use another array for densePermute_ |
| 693 | delete [] densePermute_; |
| 694 | densePermute_ = NULL; |
| 695 | numberDense_=0; |
| 696 | return status; |
| 697 | } |
| 698 | // Separate out links with same row/column count |
| 699 | void |
| 700 | CoinFactorization::separateLinks(int count,bool rowsFirst) |
| 701 | { |
| 702 | int *nextCount = nextCount_.array(); |
| 703 | int *firstCount = firstCount_.array(); |
| 704 | int *lastCount = lastCount_.array(); |
| 705 | int next = firstCount[count]; |
| 706 | int firstRow=-1; |
| 707 | int firstColumn=-1; |
| 708 | int lastRow=-1; |
| 709 | int lastColumn=-1; |
| 710 | while(next>=0) { |
| 711 | int next2=nextCount[next]; |
| 712 | if (next>=numberRows_) { |
| 713 | nextCount[next]=-1; |
| 714 | // Column |
| 715 | if (firstColumn>=0) { |
| 716 | lastCount[next]=lastColumn; |
| 717 | nextCount[lastColumn]=next; |
| 718 | } else { |
| 719 | lastCount[next]= -2 - count; |
| 720 | firstColumn=next; |
| 721 | } |
| 722 | lastColumn=next; |
| 723 | } else { |
| 724 | // Row |
| 725 | if (firstRow>=0) { |
| 726 | lastCount[next]=lastRow; |
| 727 | nextCount[lastRow]=next; |
| 728 | } else { |
| 729 | lastCount[next]= -2 - count; |
| 730 | firstRow=next; |
| 731 | } |
| 732 | lastRow=next; |
| 733 | } |
| 734 | next=next2; |
| 735 | } |
| 736 | if (rowsFirst&&firstRow>=0) { |
| 737 | firstCount[count]=firstRow; |
| 738 | nextCount[lastRow]=firstColumn; |
| 739 | if (firstColumn>=0) |
| 740 | lastCount[firstColumn]=lastRow; |
| 741 | } else if (firstRow<0) { |
| 742 | firstCount[count]=firstColumn; |
| 743 | } else if (firstColumn>=0) { |
| 744 | firstCount[count]=firstColumn; |
| 745 | nextCount[lastColumn]=firstRow; |
| 746 | if (firstRow>=0) |
| 747 | lastCount[firstRow]=lastColumn; |
| 748 | } |
| 749 | } |
| 750 | // Debug - save on file |
| 751 | int |
| 752 | CoinFactorization::saveFactorization (const char * file ) const |
| 753 | { |
| 754 | FILE * fp = fopen(file,"wb" ); |
| 755 | if (fp) { |
| 756 | // Save so we can pick up scalars |
| 757 | const char * first = reinterpret_cast<const char *> ( &pivotTolerance_); |
| 758 | const char * last = reinterpret_cast<const char *> ( &biasLU_); |
| 759 | // increment |
| 760 | last += sizeof(int); |
| 761 | if (fwrite(first,last-first,1,fp)!=1) |
| 762 | return 1; |
| 763 | // Now arrays |
| 764 | if (CoinToFile(elementU_.array(),lengthAreaU_ , fp )) |
| 765 | return 1; |
| 766 | if (CoinToFile(indexRowU_.array(),lengthAreaU_ , fp )) |
| 767 | return 1; |
| 768 | if (CoinToFile(indexColumnU_.array(),lengthAreaU_ , fp )) |
| 769 | return 1; |
| 770 | if (CoinToFile(convertRowToColumnU_.array(),lengthAreaU_ , fp )) |
| 771 | return 1; |
| 772 | if (CoinToFile(elementByRowL_.array(),lengthAreaL_ , fp )) |
| 773 | return 1; |
| 774 | if (CoinToFile(indexColumnL_.array(),lengthAreaL_ , fp )) |
| 775 | return 1; |
| 776 | if (CoinToFile(startRowL_.array() , numberRows_+1, fp )) |
| 777 | return 1; |
| 778 | if (CoinToFile(elementL_.array(),lengthAreaL_ , fp )) |
| 779 | return 1; |
| 780 | if (CoinToFile(indexRowL_.array(),lengthAreaL_ , fp )) |
| 781 | return 1; |
| 782 | if (CoinToFile(startColumnL_.array(),numberRows_ + 1 , fp )) |
| 783 | return 1; |
| 784 | if (CoinToFile(markRow_.array(),numberRows_ , fp)) |
| 785 | return 1; |
| 786 | if (CoinToFile(saveColumn_.array(),numberColumns_ , fp)) |
| 787 | return 1; |
| 788 | if (CoinToFile(startColumnR_.array() , maximumPivots_ + 1 , fp )) |
| 789 | return 1; |
| 790 | if (CoinToFile(startRowU_.array(),maximumRowsExtra_ + 1 , fp )) |
| 791 | return 1; |
| 792 | if (CoinToFile(numberInRow_.array(),maximumRowsExtra_ + 1 , fp )) |
| 793 | return 1; |
| 794 | if (CoinToFile(nextRow_.array(),maximumRowsExtra_ + 1 , fp )) |
| 795 | return 1; |
| 796 | if (CoinToFile(lastRow_.array(),maximumRowsExtra_ + 1 , fp )) |
| 797 | return 1; |
| 798 | if (CoinToFile(pivotRegion_.array(),maximumRowsExtra_ + 1 , fp )) |
| 799 | return 1; |
| 800 | if (CoinToFile(permuteBack_.array(),maximumRowsExtra_ + 1 , fp )) |
| 801 | return 1; |
| 802 | if (CoinToFile(permute_.array(),maximumRowsExtra_ + 1 , fp )) |
| 803 | return 1; |
| 804 | if (CoinToFile(pivotColumnBack_.array(),maximumRowsExtra_ + 1 , fp )) |
| 805 | return 1; |
| 806 | if (CoinToFile(startColumnU_.array(),maximumColumnsExtra_ + 1 , fp )) |
| 807 | return 1; |
| 808 | if (CoinToFile(numberInColumn_.array(),maximumColumnsExtra_ + 1 , fp )) |
| 809 | return 1; |
| 810 | if (CoinToFile(numberInColumnPlus_.array(),maximumColumnsExtra_ + 1 , fp )) |
| 811 | return 1; |
| 812 | if (CoinToFile(firstCount_.array(),biggerDimension_ + 2 , fp )) |
| 813 | return 1; |
| 814 | if (CoinToFile(nextCount_.array(),numberRows_ + numberColumns_ , fp )) |
| 815 | return 1; |
| 816 | if (CoinToFile(lastCount_.array(),numberRows_ + numberColumns_ , fp )) |
| 817 | return 1; |
| 818 | if (CoinToFile(pivotRowL_.array(),numberRows_ + 1 , fp )) |
| 819 | return 1; |
| 820 | if (CoinToFile(pivotColumn_.array(),maximumColumnsExtra_ + 1 , fp )) |
| 821 | return 1; |
| 822 | if (CoinToFile(nextColumn_.array(),maximumColumnsExtra_ + 1 , fp )) |
| 823 | return 1; |
| 824 | if (CoinToFile(lastColumn_.array(),maximumColumnsExtra_ + 1 , fp )) |
| 825 | return 1; |
| 826 | if (CoinToFile(denseArea_ , numberDense_*numberDense_, fp )) |
| 827 | return 1; |
| 828 | if (CoinToFile(densePermute_ , numberDense_, fp )) |
| 829 | return 1; |
| 830 | fclose(fp); |
| 831 | } |
| 832 | return 0; |
| 833 | } |
| 834 | // Debug - restore from file |
| 835 | int |
| 836 | CoinFactorization::restoreFactorization (const char * file , bool factorIt ) |
| 837 | { |
| 838 | FILE * fp = fopen(file,"rb" ); |
| 839 | if (fp) { |
| 840 | // Get rid of current |
| 841 | gutsOfDestructor(); |
| 842 | CoinBigIndex newSize=0; // for checking - should be same |
| 843 | // Restore so we can pick up scalars |
| 844 | char * first = reinterpret_cast<char *> ( &pivotTolerance_); |
| 845 | char * last = reinterpret_cast<char *> ( &biasLU_); |
| 846 | // increment |
| 847 | last += sizeof(int); |
| 848 | if (fread(first,last-first,1,fp)!=1) |
| 849 | return 1; |
| 850 | CoinBigIndex space = lengthAreaL_ - lengthL_; |
| 851 | // Now arrays |
| 852 | CoinFactorizationDouble *elementU = elementU_.array(); |
| 853 | if (CoinFromFile(elementU,lengthAreaU_ , fp, newSize )==1) |
| 854 | return 1; |
| 855 | assert (newSize==lengthAreaU_); |
| 856 | int * indexRowU = indexRowU_.array(); |
| 857 | if (CoinFromFile(indexRowU,lengthAreaU_ , fp, newSize )==1) |
| 858 | return 1; |
| 859 | assert (newSize==lengthAreaU_); |
| 860 | int * indexColumnU = indexColumnU_.array(); |
| 861 | if (CoinFromFile(indexColumnU,lengthAreaU_ , fp, newSize )==1) |
| 862 | return 1; |
| 863 | assert (newSize==lengthAreaU_); |
| 864 | CoinBigIndex *convertRowToColumnU = convertRowToColumnU_.array(); |
| 865 | if (CoinFromFile(convertRowToColumnU,lengthAreaU_ , fp, newSize )==1) |
| 866 | return 1; |
| 867 | assert (newSize==lengthAreaU_||(newSize==0&&!convertRowToColumnU_.array())); |
| 868 | CoinFactorizationDouble * elementByRowL = elementByRowL_.array(); |
| 869 | if (CoinFromFile(elementByRowL,lengthAreaL_ , fp, newSize )==1) |
| 870 | return 1; |
| 871 | assert (newSize==lengthAreaL_||(newSize==0&&!elementByRowL_.array())); |
| 872 | int * indexColumnL = indexColumnL_.array(); |
| 873 | if (CoinFromFile(indexColumnL,lengthAreaL_ , fp, newSize )==1) |
| 874 | return 1; |
| 875 | assert (newSize==lengthAreaL_||(newSize==0&&!indexColumnL_.array())); |
| 876 | CoinBigIndex * startRowL = startRowL_.array(); |
| 877 | if (CoinFromFile(startRowL , numberRows_+1, fp, newSize )==1) |
| 878 | return 1; |
| 879 | assert (newSize==numberRows_+1||(newSize==0&&!startRowL_.array())); |
| 880 | CoinFactorizationDouble * elementL = elementL_.array(); |
| 881 | if (CoinFromFile(elementL,lengthAreaL_ , fp, newSize )==1) |
| 882 | return 1; |
| 883 | assert (newSize==lengthAreaL_); |
| 884 | int * indexRowL = indexRowL_.array(); |
| 885 | if (CoinFromFile(indexRowL,lengthAreaL_ , fp, newSize )==1) |
| 886 | return 1; |
| 887 | assert (newSize==lengthAreaL_); |
| 888 | CoinBigIndex * startColumnL = startColumnL_.array(); |
| 889 | if (CoinFromFile(startColumnL,numberRows_ + 1 , fp, newSize )==1) |
| 890 | return 1; |
| 891 | assert (newSize==numberRows_+1); |
| 892 | int * markRow = markRow_.array(); |
| 893 | if (CoinFromFile(markRow,numberRows_ , fp, newSize )==1) |
| 894 | return 1; |
| 895 | assert (newSize==numberRows_); |
| 896 | int * saveColumn = saveColumn_.array(); |
| 897 | if (CoinFromFile(saveColumn,numberColumns_ , fp, newSize )==1) |
| 898 | return 1; |
| 899 | assert (newSize==numberColumns_); |
| 900 | CoinBigIndex * startColumnR = startColumnR_.array(); |
| 901 | if (CoinFromFile(startColumnR , maximumPivots_ + 1 , fp, newSize )==1) |
| 902 | return 1; |
| 903 | assert (newSize==maximumPivots_+1||(newSize==0&&!startColumnR_.array())); |
| 904 | CoinBigIndex * startRowU = startRowU_.array(); |
| 905 | if (CoinFromFile(startRowU,maximumRowsExtra_ + 1 , fp, newSize )==1) |
| 906 | return 1; |
| 907 | assert (newSize==maximumRowsExtra_+1||(newSize==0&&!startRowU_.array())); |
| 908 | int * numberInRow = numberInRow_.array(); |
| 909 | if (CoinFromFile(numberInRow,maximumRowsExtra_ + 1 , fp, newSize )==1) |
| 910 | return 1; |
| 911 | assert (newSize==maximumRowsExtra_+1); |
| 912 | int * nextRow = nextRow_.array(); |
| 913 | if (CoinFromFile(nextRow,maximumRowsExtra_ + 1 , fp, newSize )==1) |
| 914 | return 1; |
| 915 | assert (newSize==maximumRowsExtra_+1); |
| 916 | int * lastRow = lastRow_.array(); |
| 917 | if (CoinFromFile(lastRow,maximumRowsExtra_ + 1 , fp, newSize )==1) |
| 918 | return 1; |
| 919 | assert (newSize==maximumRowsExtra_+1); |
| 920 | CoinFactorizationDouble * pivotRegion = pivotRegion_.array(); |
| 921 | if (CoinFromFile(pivotRegion,maximumRowsExtra_ + 1 , fp, newSize )==1) |
| 922 | return 1; |
| 923 | assert (newSize==maximumRowsExtra_+1); |
| 924 | int * permuteBack = permuteBack_.array(); |
| 925 | if (CoinFromFile(permuteBack,maximumRowsExtra_ + 1 , fp, newSize )==1) |
| 926 | return 1; |
| 927 | assert (newSize==maximumRowsExtra_+1||(newSize==0&&!permuteBack_.array())); |
| 928 | int * permute = permute_.array(); |
| 929 | if (CoinFromFile(permute,maximumRowsExtra_ + 1 , fp, newSize )==1) |
| 930 | return 1; |
| 931 | assert (newSize==maximumRowsExtra_+1||(newSize==0&&!permute_.array())); |
| 932 | int * pivotColumnBack = pivotColumnBack_.array(); |
| 933 | if (CoinFromFile(pivotColumnBack,maximumRowsExtra_ + 1 , fp, newSize )==1) |
| 934 | return 1; |
| 935 | assert (newSize==maximumRowsExtra_+1||(newSize==0&&!pivotColumnBack_.array())); |
| 936 | CoinBigIndex * startColumnU = startColumnU_.array(); |
| 937 | if (CoinFromFile(startColumnU,maximumColumnsExtra_ + 1 , fp, newSize )==1) |
| 938 | return 1; |
| 939 | assert (newSize==maximumColumnsExtra_+1); |
| 940 | int * numberInColumn = numberInColumn_.array(); |
| 941 | if (CoinFromFile(numberInColumn,maximumColumnsExtra_ + 1 , fp, newSize )==1) |
| 942 | return 1; |
| 943 | assert (newSize==maximumColumnsExtra_+1); |
| 944 | int * numberInColumnPlus = numberInColumnPlus_.array(); |
| 945 | if (CoinFromFile(numberInColumnPlus,maximumColumnsExtra_ + 1 , fp, newSize )==1) |
| 946 | return 1; |
| 947 | assert (newSize==maximumColumnsExtra_+1); |
| 948 | int *firstCount = firstCount_.array(); |
| 949 | if (CoinFromFile(firstCount,biggerDimension_ + 2 , fp, newSize )==1) |
| 950 | return 1; |
| 951 | assert (newSize==biggerDimension_+2); |
| 952 | int *nextCount = nextCount_.array(); |
| 953 | if (CoinFromFile(nextCount,numberRows_ + numberColumns_ , fp, newSize )==1) |
| 954 | return 1; |
| 955 | assert (newSize==numberRows_+numberColumns_); |
| 956 | int *lastCount = lastCount_.array(); |
| 957 | if (CoinFromFile(lastCount,numberRows_ + numberColumns_ , fp, newSize )==1) |
| 958 | return 1; |
| 959 | assert (newSize==numberRows_+numberColumns_); |
| 960 | int * pivotRowL = pivotRowL_.array(); |
| 961 | if (CoinFromFile(pivotRowL,numberRows_ + 1 , fp, newSize )==1) |
| 962 | return 1; |
| 963 | assert (newSize==numberRows_+1); |
| 964 | int * pivotColumn = pivotColumn_.array(); |
| 965 | if (CoinFromFile(pivotColumn,maximumColumnsExtra_ + 1 , fp, newSize )==1) |
| 966 | return 1; |
| 967 | assert (newSize==maximumColumnsExtra_+1); |
| 968 | int * nextColumn = nextColumn_.array(); |
| 969 | if (CoinFromFile(nextColumn,maximumColumnsExtra_ + 1 , fp, newSize )==1) |
| 970 | return 1; |
| 971 | assert (newSize==maximumColumnsExtra_+1); |
| 972 | int * lastColumn = lastColumn_.array(); |
| 973 | if (CoinFromFile(lastColumn,maximumColumnsExtra_ + 1 , fp, newSize )==1) |
| 974 | return 1; |
| 975 | assert (newSize==maximumColumnsExtra_+1); |
| 976 | if (CoinFromFile(denseArea_ , numberDense_*numberDense_, fp, newSize )==1) |
| 977 | return 1; |
| 978 | assert (newSize==numberDense_*numberDense_); |
| 979 | if (CoinFromFile(densePermute_ , numberDense_, fp, newSize )==1) |
| 980 | return 1; |
| 981 | assert (newSize==numberDense_); |
| 982 | lengthAreaR_ = space; |
| 983 | elementR_ = elementL_.array() + lengthL_; |
| 984 | indexRowR_ = indexRowL_.array() + lengthL_; |
| 985 | fclose(fp); |
| 986 | if (factorIt) { |
| 987 | if (biasLU_>=3||numberRows_!=numberColumns_) |
| 988 | preProcess ( 2 ); |
| 989 | else |
| 990 | preProcess ( 3 ); // no row copy |
| 991 | factor ( ); |
| 992 | } |
| 993 | } |
| 994 | return 0; |
| 995 | } |
| 996 | // factorSparse. Does sparse phase of factorization |
| 997 | //return code is <0 error, 0= finished |
| 998 | int |
| 999 | CoinFactorization::factorSparseLarge ( ) |
| 1000 | { |
| 1001 | int *indexRow = indexRowU_.array(); |
| 1002 | int *indexColumn = indexColumnU_.array(); |
| 1003 | CoinFactorizationDouble *element = elementU_.array(); |
| 1004 | int count = 1; |
| 1005 | workArea_.conditionalNew(numberRows_); |
| 1006 | CoinFactorizationDouble * workArea = workArea_.array(); |
| 1007 | #ifndef NDEBUG |
| 1008 | counter1++; |
| 1009 | #endif |
| 1010 | // when to go dense |
| 1011 | int denseThreshold=denseThreshold_; |
| 1012 | |
| 1013 | CoinZeroN ( workArea, numberRows_ ); |
| 1014 | //get space for bit work area |
| 1015 | CoinBigIndex workSize = 1000; |
| 1016 | workArea2_.conditionalNew(workSize); |
| 1017 | unsigned int * workArea2 = workArea2_.array(); |
| 1018 | |
| 1019 | //set markRow so no rows updated |
| 1020 | int * markRow = markRow_.array(); |
| 1021 | CoinFillN ( markRow, numberRows_, COIN_INT_MAX-10+1); |
| 1022 | int status = 0; |
| 1023 | //do slacks first |
| 1024 | int * numberInRow = numberInRow_.array(); |
| 1025 | int * numberInColumn = numberInColumn_.array(); |
| 1026 | int * numberInColumnPlus = numberInColumnPlus_.array(); |
| 1027 | CoinBigIndex * startColumnU = startColumnU_.array(); |
| 1028 | CoinBigIndex * startColumnL = startColumnL_.array(); |
| 1029 | if (biasLU_<3&&numberColumns_==numberRows_) { |
| 1030 | int iPivotColumn; |
| 1031 | int * pivotColumn = pivotColumn_.array(); |
| 1032 | int * nextRow = nextRow_.array(); |
| 1033 | int * lastRow = lastRow_.array(); |
| 1034 | for ( iPivotColumn = 0; iPivotColumn < numberColumns_; |
| 1035 | iPivotColumn++ ) { |
| 1036 | if ( numberInColumn[iPivotColumn] == 1 ) { |
| 1037 | CoinBigIndex start = startColumnU[iPivotColumn]; |
| 1038 | CoinFactorizationDouble value = element[start]; |
| 1039 | if ( value == slackValue_ && numberInColumnPlus[iPivotColumn] == 0 ) { |
| 1040 | // treat as slack |
| 1041 | int iRow = indexRow[start]; |
| 1042 | // but only if row not marked |
| 1043 | if (numberInRow[iRow]>0) { |
| 1044 | totalElements_ -= numberInRow[iRow]; |
| 1045 | //take out this bit of indexColumnU |
| 1046 | int next = nextRow[iRow]; |
| 1047 | int last = lastRow[iRow]; |
| 1048 | |
| 1049 | nextRow[last] = next; |
| 1050 | lastRow[next] = last; |
| 1051 | nextRow[iRow] = numberGoodU_; //use for permute |
| 1052 | lastRow[iRow] = -2; //mark |
| 1053 | //modify linked list for pivots |
| 1054 | deleteLink ( iRow ); |
| 1055 | numberInRow[iRow]=-1; |
| 1056 | numberInColumn[iPivotColumn]=0; |
| 1057 | numberGoodL_++; |
| 1058 | startColumnL[numberGoodL_] = 0; |
| 1059 | pivotColumn[numberGoodU_] = iPivotColumn; |
| 1060 | numberGoodU_++; |
| 1061 | } |
| 1062 | } |
| 1063 | } |
| 1064 | } |
| 1065 | // redo |
| 1066 | preProcess(4); |
| 1067 | CoinFillN ( markRow, numberRows_, COIN_INT_MAX-10+1); |
| 1068 | } |
| 1069 | numberSlacks_ = numberGoodU_; |
| 1070 | int *nextCount = nextCount_.array(); |
| 1071 | int *firstCount = firstCount_.array(); |
| 1072 | CoinBigIndex *startRow = startRowU_.array(); |
| 1073 | CoinBigIndex *startColumn = startColumnU; |
| 1074 | //double *elementL = elementL_.array(); |
| 1075 | //int *indexRowL = indexRowL_.array(); |
| 1076 | //int *saveColumn = saveColumn_.array(); |
| 1077 | //int *nextRow = nextRow_.array(); |
| 1078 | //int *lastRow = lastRow_.array() ; |
| 1079 | double pivotTolerance = pivotTolerance_; |
| 1080 | int numberTrials = numberTrials_; |
| 1081 | int numberRows = numberRows_; |
| 1082 | // Put column singletons first - (if false) |
| 1083 | separateLinks(1,(biasLU_>1)); |
| 1084 | #ifndef NDEBUG |
| 1085 | int counter2=0; |
| 1086 | #endif |
| 1087 | while ( count <= biggerDimension_ ) { |
| 1088 | #ifndef NDEBUG |
| 1089 | counter2++; |
| 1090 | int badRow=-1; |
| 1091 | if (counter1==-1&&counter2>=0) { |
| 1092 | // check counts consistent |
| 1093 | for (int iCount=1;iCount<numberRows_;iCount++) { |
| 1094 | int look = firstCount[iCount]; |
| 1095 | while ( look >= 0 ) { |
| 1096 | if ( look < numberRows_ ) { |
| 1097 | int iRow = look; |
| 1098 | if (iRow==badRow) |
| 1099 | printf("row count for row %d is %d\n" ,iCount,iRow); |
| 1100 | if ( numberInRow[iRow] != iCount ) { |
| 1101 | printf("failed debug on %d entry to factorSparse and %d try\n" , |
| 1102 | counter1,counter2); |
| 1103 | printf("row %d - count %d number %d\n" ,iRow,iCount,numberInRow[iRow]); |
| 1104 | abort(); |
| 1105 | } |
| 1106 | look = nextCount[look]; |
| 1107 | } else { |
| 1108 | int iColumn = look - numberRows; |
| 1109 | if ( numberInColumn[iColumn] != iCount ) { |
| 1110 | printf("failed debug on %d entry to factorSparse and %d try\n" , |
| 1111 | counter1,counter2); |
| 1112 | printf("column %d - count %d number %d\n" ,iColumn,iCount,numberInColumn[iColumn]); |
| 1113 | abort(); |
| 1114 | } |
| 1115 | look = nextCount[look]; |
| 1116 | } |
| 1117 | } |
| 1118 | } |
| 1119 | } |
| 1120 | #endif |
| 1121 | CoinBigIndex minimumCount = COIN_INT_MAX; |
| 1122 | double minimumCost = COIN_DBL_MAX; |
| 1123 | |
| 1124 | int iPivotRow = -1; |
| 1125 | int iPivotColumn = -1; |
| 1126 | int pivotRowPosition = -1; |
| 1127 | int pivotColumnPosition = -1; |
| 1128 | int look = firstCount[count]; |
| 1129 | int trials = 0; |
| 1130 | int * pivotColumn = pivotColumn_.array(); |
| 1131 | |
| 1132 | if ( count == 1 && firstCount[1] >= 0 &&!biasLU_) { |
| 1133 | //do column singletons first to put more in U |
| 1134 | while ( look >= 0 ) { |
| 1135 | if ( look < numberRows_ ) { |
| 1136 | look = nextCount[look]; |
| 1137 | } else { |
| 1138 | int iColumn = look - numberRows_; |
| 1139 | |
| 1140 | assert ( numberInColumn[iColumn] == count ); |
| 1141 | CoinBigIndex start = startColumnU[iColumn]; |
| 1142 | int iRow = indexRow[start]; |
| 1143 | |
| 1144 | iPivotRow = iRow; |
| 1145 | pivotRowPosition = start; |
| 1146 | iPivotColumn = iColumn; |
| 1147 | assert (iPivotRow>=0&&iPivotColumn>=0); |
| 1148 | pivotColumnPosition = -1; |
| 1149 | look = -1; |
| 1150 | break; |
| 1151 | } |
| 1152 | } /* endwhile */ |
| 1153 | if ( iPivotRow < 0 ) { |
| 1154 | //back to singletons |
| 1155 | look = firstCount[1]; |
| 1156 | } |
| 1157 | } |
| 1158 | while ( look >= 0 ) { |
| 1159 | if ( look < numberRows_ ) { |
| 1160 | int iRow = look; |
| 1161 | #ifndef NDEBUG |
| 1162 | if ( numberInRow[iRow] != count ) { |
| 1163 | printf("failed on %d entry to factorSparse and %d try\n" , |
| 1164 | counter1,counter2); |
| 1165 | printf("row %d - count %d number %d\n" ,iRow,count,numberInRow[iRow]); |
| 1166 | abort(); |
| 1167 | } |
| 1168 | #endif |
| 1169 | look = nextCount[look]; |
| 1170 | bool rejected = false; |
| 1171 | CoinBigIndex start = startRow[iRow]; |
| 1172 | CoinBigIndex end = start + count; |
| 1173 | |
| 1174 | CoinBigIndex i; |
| 1175 | for ( i = start; i < end; i++ ) { |
| 1176 | int iColumn = indexColumn[i]; |
| 1177 | assert (numberInColumn[iColumn]>0); |
| 1178 | double cost = ( count - 1 ) * numberInColumn[iColumn]; |
| 1179 | |
| 1180 | if ( cost < minimumCost ) { |
| 1181 | CoinBigIndex where = startColumn[iColumn]; |
| 1182 | CoinFactorizationDouble minimumValue = element[where]; |
| 1183 | |
| 1184 | minimumValue = fabs ( minimumValue ) * pivotTolerance; |
| 1185 | while ( indexRow[where] != iRow ) { |
| 1186 | where++; |
| 1187 | } /* endwhile */ |
| 1188 | assert ( where < startColumn[iColumn] + |
| 1189 | numberInColumn[iColumn]); |
| 1190 | CoinFactorizationDouble value = element[where]; |
| 1191 | |
| 1192 | value = fabs ( value ); |
| 1193 | if ( value >= minimumValue ) { |
| 1194 | minimumCost = cost; |
| 1195 | minimumCount = numberInColumn[iColumn]; |
| 1196 | iPivotRow = iRow; |
| 1197 | pivotRowPosition = -1; |
| 1198 | iPivotColumn = iColumn; |
| 1199 | assert (iPivotRow>=0&&iPivotColumn>=0); |
| 1200 | pivotColumnPosition = i; |
| 1201 | rejected=false; |
| 1202 | if ( minimumCount < count ) { |
| 1203 | look = -1; |
| 1204 | break; |
| 1205 | } |
| 1206 | } else if ( iPivotRow == -1 ) { |
| 1207 | rejected = true; |
| 1208 | } |
| 1209 | } |
| 1210 | } |
| 1211 | trials++; |
| 1212 | if ( trials >= numberTrials && iPivotRow >= 0 ) { |
| 1213 | look = -1; |
| 1214 | break; |
| 1215 | } |
| 1216 | if ( rejected ) { |
| 1217 | //take out for moment |
| 1218 | //eligible when row changes |
| 1219 | deleteLink ( iRow ); |
| 1220 | addLink ( iRow, biggerDimension_ + 1 ); |
| 1221 | } |
| 1222 | } else { |
| 1223 | int iColumn = look - numberRows; |
| 1224 | |
| 1225 | assert ( numberInColumn[iColumn] == count ); |
| 1226 | look = nextCount[look]; |
| 1227 | CoinBigIndex start = startColumn[iColumn]; |
| 1228 | CoinBigIndex end = start + numberInColumn[iColumn]; |
| 1229 | CoinFactorizationDouble minimumValue = element[start]; |
| 1230 | |
| 1231 | minimumValue = fabs ( minimumValue ) * pivotTolerance; |
| 1232 | CoinBigIndex i; |
| 1233 | for ( i = start; i < end; i++ ) { |
| 1234 | CoinFactorizationDouble value = element[i]; |
| 1235 | |
| 1236 | value = fabs ( value ); |
| 1237 | if ( value >= minimumValue ) { |
| 1238 | int iRow = indexRow[i]; |
| 1239 | int nInRow = numberInRow[iRow]; |
| 1240 | assert (nInRow>0); |
| 1241 | double cost = ( count - 1 ) * nInRow; |
| 1242 | |
| 1243 | if ( cost < minimumCost ) { |
| 1244 | minimumCost = cost; |
| 1245 | minimumCount = nInRow; |
| 1246 | iPivotRow = iRow; |
| 1247 | pivotRowPosition = i; |
| 1248 | iPivotColumn = iColumn; |
| 1249 | assert (iPivotRow>=0&&iPivotColumn>=0); |
| 1250 | pivotColumnPosition = -1; |
| 1251 | if ( minimumCount <= count + 1 ) { |
| 1252 | look = -1; |
| 1253 | break; |
| 1254 | } |
| 1255 | } |
| 1256 | } |
| 1257 | } |
| 1258 | trials++; |
| 1259 | if ( trials >= numberTrials && iPivotRow >= 0 ) { |
| 1260 | look = -1; |
| 1261 | break; |
| 1262 | } |
| 1263 | } |
| 1264 | } /* endwhile */ |
| 1265 | if (iPivotRow>=0) { |
| 1266 | if ( iPivotRow >= 0 ) { |
| 1267 | int numberDoRow = numberInRow[iPivotRow] - 1; |
| 1268 | int numberDoColumn = numberInColumn[iPivotColumn] - 1; |
| 1269 | |
| 1270 | totalElements_ -= ( numberDoRow + numberDoColumn + 1 ); |
| 1271 | if ( numberDoColumn > 0 ) { |
| 1272 | if ( numberDoRow > 0 ) { |
| 1273 | if ( numberDoColumn > 1 ) { |
| 1274 | // if (1) { |
| 1275 | //need to adjust more for cache and SMP |
| 1276 | //allow at least 4 extra |
| 1277 | int increment = numberDoColumn + 1 + 4; |
| 1278 | |
| 1279 | if ( increment & 15 ) { |
| 1280 | increment = increment & ( ~15 ); |
| 1281 | increment += 16; |
| 1282 | } |
| 1283 | int increment2 = |
| 1284 | |
| 1285 | ( increment + COINFACTORIZATION_BITS_PER_INT - 1 ) >> COINFACTORIZATION_SHIFT_PER_INT; |
| 1286 | CoinBigIndex size = increment2 * numberDoRow; |
| 1287 | |
| 1288 | if ( size > workSize ) { |
| 1289 | workSize = size; |
| 1290 | workArea2_.conditionalNew(workSize); |
| 1291 | workArea2 = workArea2_.array(); |
| 1292 | } |
| 1293 | bool goodPivot; |
| 1294 | |
| 1295 | //might be able to do better by permuting |
| 1296 | #ifndef UGLY_COIN_FACTOR_CODING |
| 1297 | //branch out to best pivot routine |
| 1298 | goodPivot = pivot ( iPivotRow, iPivotColumn, |
| 1299 | pivotRowPosition, pivotColumnPosition, |
| 1300 | workArea, workArea2, |
| 1301 | increment2, markRow , |
| 1302 | LARGE_SET); |
| 1303 | #else |
| 1304 | #define FAC_SET LARGE_SET |
| 1305 | #include "CoinFactorization.hpp" |
| 1306 | #undef FAC_SET |
| 1307 | #endif |
| 1308 | if ( !goodPivot ) { |
| 1309 | status = -99; |
| 1310 | count=biggerDimension_+1; |
| 1311 | break; |
| 1312 | } |
| 1313 | } else { |
| 1314 | if ( !pivotOneOtherRow ( iPivotRow, iPivotColumn ) ) { |
| 1315 | status = -99; |
| 1316 | count=biggerDimension_+1; |
| 1317 | break; |
| 1318 | } |
| 1319 | } |
| 1320 | } else { |
| 1321 | assert (!numberDoRow); |
| 1322 | if ( !pivotRowSingleton ( iPivotRow, iPivotColumn ) ) { |
| 1323 | status = -99; |
| 1324 | count=biggerDimension_+1; |
| 1325 | break; |
| 1326 | } |
| 1327 | } |
| 1328 | } else { |
| 1329 | assert (!numberDoColumn); |
| 1330 | if ( !pivotColumnSingleton ( iPivotRow, iPivotColumn ) ) { |
| 1331 | status = -99; |
| 1332 | count=biggerDimension_+1; |
| 1333 | break; |
| 1334 | } |
| 1335 | } |
| 1336 | assert (nextRow_.array()[iPivotRow]==numberGoodU_); |
| 1337 | pivotColumn[numberGoodU_] = iPivotColumn; |
| 1338 | numberGoodU_++; |
| 1339 | // This should not need to be trapped here - but be safe |
| 1340 | if (numberGoodU_==numberRows_) |
| 1341 | count=biggerDimension_+1; |
| 1342 | } |
| 1343 | #if COIN_DEBUG==2 |
| 1344 | checkConsistency ( ); |
| 1345 | #endif |
| 1346 | #if 0 |
| 1347 | // Even if no dense code may be better to use naive dense |
| 1348 | if (!denseThreshold_&&totalElements_>1000) { |
| 1349 | int leftRows=numberRows_-numberGoodU_; |
| 1350 | double full = leftRows; |
| 1351 | full *= full; |
| 1352 | assert (full>=0.0); |
| 1353 | double leftElements = totalElements_; |
| 1354 | double ratio; |
| 1355 | if (leftRows>2000) |
| 1356 | ratio=4.0; |
| 1357 | else |
| 1358 | ratio=3.0; |
| 1359 | if (ratio*leftElements>full) |
| 1360 | denseThreshold=1; |
| 1361 | } |
| 1362 | #endif |
| 1363 | if (denseThreshold) { |
| 1364 | // see whether to go dense |
| 1365 | int leftRows=numberRows_-numberGoodU_; |
| 1366 | double full = leftRows; |
| 1367 | full *= full; |
| 1368 | assert (full>=0.0); |
| 1369 | double leftElements = totalElements_; |
| 1370 | //if (leftRows==100) |
| 1371 | //printf("at 100 %d elements\n",totalElements_); |
| 1372 | double ratio; |
| 1373 | if (leftRows>2000) |
| 1374 | ratio=4.0; |
| 1375 | else if (leftRows>800) |
| 1376 | ratio=3.0; |
| 1377 | else if (leftRows>256) |
| 1378 | ratio=2.0; |
| 1379 | else |
| 1380 | ratio=1.5; |
| 1381 | if ((ratio*leftElements>full&&leftRows>denseThreshold_)) { |
| 1382 | //return to do dense |
| 1383 | if (status!=0) |
| 1384 | break; |
| 1385 | int check=0; |
| 1386 | for (int iColumn=0;iColumn<numberColumns_;iColumn++) { |
| 1387 | if (numberInColumn[iColumn]) |
| 1388 | check++; |
| 1389 | } |
| 1390 | if (check!=leftRows&&denseThreshold_) { |
| 1391 | //printf("** mismatch %d columns left, %d rows\n",check,leftRows); |
| 1392 | denseThreshold=0; |
| 1393 | } else { |
| 1394 | status=2; |
| 1395 | if ((messageLevel_&4)!=0) |
| 1396 | std::cout<<" Went dense at " <<leftRows<<" rows " << |
| 1397 | totalElements_<<" " <<full<<" " <<leftElements<<std::endl; |
| 1398 | if (!denseThreshold_) |
| 1399 | denseThreshold_=-check; // say how many |
| 1400 | break; |
| 1401 | } |
| 1402 | } |
| 1403 | } |
| 1404 | // start at 1 again |
| 1405 | count = 1; |
| 1406 | } else { |
| 1407 | //end of this - onto next |
| 1408 | count++; |
| 1409 | } |
| 1410 | } /* endwhile */ |
| 1411 | workArea_.conditionalDelete() ; |
| 1412 | workArea2_.conditionalDelete() ; |
| 1413 | return status; |
| 1414 | } |
| 1415 | |