| 1 | /* $Id: CoinPresolveFixed.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 | #include <stdio.h> | 
|---|
| 7 | #include <math.h> | 
|---|
| 8 |  | 
|---|
| 9 | #include "CoinPresolveMatrix.hpp" | 
|---|
| 10 | #include "CoinPresolveFixed.hpp" | 
|---|
| 11 | #include "CoinHelperFunctions.hpp" | 
|---|
| 12 | #include "CoinFinite.hpp" | 
|---|
| 13 |  | 
|---|
| 14 | #if PRESOLVE_DEBUG || PRESOLVE_CONSISTENCY | 
|---|
| 15 | #include "CoinPresolvePsdebug.hpp" | 
|---|
| 16 | #endif | 
|---|
| 17 |  | 
|---|
| 18 | /* Begin routines associated with remove_fixed_action */ | 
|---|
| 19 |  | 
|---|
| 20 | const char *remove_fixed_action::name() const | 
|---|
| 21 | { | 
|---|
| 22 | return ( "remove_fixed_action"); | 
|---|
| 23 | } | 
|---|
| 24 |  | 
|---|
| 25 | /* | 
|---|
| 26 | * Original comment: | 
|---|
| 27 | * | 
|---|
| 28 | * invariant:  both reps are loosely packed. | 
|---|
| 29 | * coefficients of both reps remain consistent. | 
|---|
| 30 | * | 
|---|
| 31 | * Note that this concerns variables whose column bounds determine that | 
|---|
| 32 | * they are slack; this does NOT concern singleton row constraints that | 
|---|
| 33 | * determine that the relevant variable is slack. | 
|---|
| 34 | * | 
|---|
| 35 | * Invariant:  col and row rep are consistent | 
|---|
| 36 | */ | 
|---|
| 37 |  | 
|---|
| 38 | /* | 
|---|
| 39 | This routine empties the columns for the list of fixed variables passed in | 
|---|
| 40 | (fcols, nfcols). As each coefficient a<ij> is set to 0, rlo<i> and rup<i> | 
|---|
| 41 | are adjusted accordingly. Note, however, that c<j> is not considered to be | 
|---|
| 42 | removed from the objective until column j is physically removed from the | 
|---|
| 43 | matrix (drop_empty_cols_action), so the correction to the objective is | 
|---|
| 44 | adjusted there. | 
|---|
| 45 |  | 
|---|
| 46 | If a column solution is available, row activity (acts_) is adjusted. | 
|---|
| 47 | remove_fixed_action implicitly assumes that the value of the variable has | 
|---|
| 48 | already been forced within bounds. If this isn't true, the correction to | 
|---|
| 49 | acts_ will be wrong. See make_fixed_action if you need to force the value | 
|---|
| 50 | within bounds first. | 
|---|
| 51 | */ | 
|---|
| 52 | const remove_fixed_action* | 
|---|
| 53 | remove_fixed_action::presolve (CoinPresolveMatrix *prob, | 
|---|
| 54 | int *fcols, | 
|---|
| 55 | int nfcols, | 
|---|
| 56 | const CoinPresolveAction *next) | 
|---|
| 57 | { | 
|---|
| 58 | double *colels	= prob->colels_; | 
|---|
| 59 | int *hrow		= prob->hrow_; | 
|---|
| 60 | CoinBigIndex *mcstrt	= prob->mcstrt_; | 
|---|
| 61 | int *hincol		= prob->hincol_; | 
|---|
| 62 |  | 
|---|
| 63 | double *rowels	= prob->rowels_; | 
|---|
| 64 | int *hcol		= prob->hcol_; | 
|---|
| 65 | CoinBigIndex *mrstrt	= prob->mrstrt_; | 
|---|
| 66 | int *hinrow		= prob->hinrow_; | 
|---|
| 67 |  | 
|---|
| 68 | double *clo	= prob->clo_; | 
|---|
| 69 | double *rlo	= prob->rlo_; | 
|---|
| 70 | double *rup	= prob->rup_; | 
|---|
| 71 | double *sol	= prob->sol_; | 
|---|
| 72 | double *acts	= prob->acts_; | 
|---|
| 73 |  | 
|---|
| 74 | presolvehlink *clink = prob->clink_; | 
|---|
| 75 | presolvehlink *rlink = prob->rlink_; | 
|---|
| 76 |  | 
|---|
| 77 | action *actions 	= new  action[nfcols+1]; | 
|---|
| 78 |  | 
|---|
| 79 | # if PRESOLVE_DEBUG | 
|---|
| 80 | std::cout << "Entering remove_fixed_action::presolve."<< std::endl ; | 
|---|
| 81 | presolve_check_sol(prob) ; | 
|---|
| 82 | presolve_check_nbasic(prob) ; | 
|---|
| 83 | # endif | 
|---|
| 84 |  | 
|---|
| 85 | /* | 
|---|
| 86 | Scan columns to be removed and total up the number of coefficients. | 
|---|
| 87 | */ | 
|---|
| 88 | int estsize=0; | 
|---|
| 89 | int ckc; | 
|---|
| 90 | for (ckc = 0 ; ckc < nfcols ; ckc++) { | 
|---|
| 91 | int j = fcols[ckc]; | 
|---|
| 92 | estsize += hincol[j]; | 
|---|
| 93 | } | 
|---|
| 94 | // Allocate arrays to hold coefficients and associated row indices | 
|---|
| 95 | double * els_action = new double[estsize]; | 
|---|
| 96 | int * rows_action = new int[estsize]; | 
|---|
| 97 | int actsize=0; | 
|---|
| 98 | // faster to do all deletes in row copy at once | 
|---|
| 99 | int nrows		= prob->nrows_; | 
|---|
| 100 | CoinBigIndex * rstrt = new int[nrows+1]; | 
|---|
| 101 | CoinZeroN(rstrt,nrows); | 
|---|
| 102 | /* | 
|---|
| 103 | Open a loop to excise each column a<j>. The first thing to do is load the | 
|---|
| 104 | action entry with the index j, the value of x<j>, and the number of | 
|---|
| 105 | entries in a<j>. After we walk the column and tweak the row-major | 
|---|
| 106 | representation, we'll simply claim this column is empty by setting | 
|---|
| 107 | hincol[j] = 0. | 
|---|
| 108 | */ | 
|---|
| 109 | for (ckc = 0 ; ckc < nfcols ; ckc++) { | 
|---|
| 110 | int j = fcols[ckc]; | 
|---|
| 111 | double solj = clo[j]; | 
|---|
| 112 | CoinBigIndex kcs = mcstrt[j]; | 
|---|
| 113 | CoinBigIndex kce = kcs + hincol[j]; | 
|---|
| 114 | CoinBigIndex k; | 
|---|
| 115 |  | 
|---|
| 116 | { action &f = actions[ckc]; | 
|---|
| 117 | f.col = j; | 
|---|
| 118 | f.sol = solj; | 
|---|
| 119 | f.start = actsize; | 
|---|
| 120 | } | 
|---|
| 121 | /* | 
|---|
| 122 | Now walk a<j>. For each row i with a coefficient a<ij> != 0: | 
|---|
| 123 | * save the coefficient and row index, | 
|---|
| 124 | * substitute the value of x<j>, adjusting the row bounds and lhs value | 
|---|
| 125 | accordingly, then | 
|---|
| 126 | * delete a<ij> from the row-major representation. | 
|---|
| 127 | * Finally: mark the row as changed and add it to the list of rows to be | 
|---|
| 128 | processed next. Then, for each remaining column in the row, do the same. | 
|---|
| 129 | (It makes sense to put the columns on the `to be processed' list, but | 
|---|
| 130 | I'm wondering about the wisdom of marking them as changed. | 
|---|
| 131 | -- lh, 040824 -- ) | 
|---|
| 132 | */ | 
|---|
| 133 | for (k = kcs ; k < kce ; k++) { | 
|---|
| 134 | int row = hrow[k]; | 
|---|
| 135 | double coeff = colels[k]; | 
|---|
| 136 |  | 
|---|
| 137 | els_action[actsize]=coeff; | 
|---|
| 138 | rstrt[row]++; // increase counts | 
|---|
| 139 | rows_action[actsize++]=row; | 
|---|
| 140 |  | 
|---|
| 141 | // Avoid reducing finite infinity. | 
|---|
| 142 | if (-PRESOLVE_INF < rlo[row]) | 
|---|
| 143 | rlo[row] -= solj*coeff; | 
|---|
| 144 | if (rup[row] < PRESOLVE_INF) | 
|---|
| 145 | rup[row] -= solj*coeff; | 
|---|
| 146 | if (sol) { | 
|---|
| 147 | acts[row] -= solj*coeff; | 
|---|
| 148 | } | 
|---|
| 149 | #define TRY2 | 
|---|
| 150 | #ifndef TRY2 | 
|---|
| 151 | presolve_delete_from_row(row,j,mrstrt,hinrow,hcol,rowels); | 
|---|
| 152 | if (hinrow[row] == 0) | 
|---|
| 153 | { PRESOLVE_REMOVE_LINK(rlink,row) ; } | 
|---|
| 154 |  | 
|---|
| 155 | // mark unless already marked | 
|---|
| 156 | if (!prob->rowChanged(row)) { | 
|---|
| 157 | prob->addRow(row); | 
|---|
| 158 | CoinBigIndex krs = mrstrt[row]; | 
|---|
| 159 | CoinBigIndex kre = krs + hinrow[row]; | 
|---|
| 160 | for (CoinBigIndex k=krs; k<kre; k++) { | 
|---|
| 161 | int jcol = hcol[k]; | 
|---|
| 162 | prob->addCol(jcol); | 
|---|
| 163 | } | 
|---|
| 164 | } | 
|---|
| 165 | #endif | 
|---|
| 166 | } | 
|---|
| 167 | /* | 
|---|
| 168 | Remove the column's link from the linked list of columns, and declare | 
|---|
| 169 | it empty in the column-major representation. Link removal must execute | 
|---|
| 170 | even if the column is already of length 0 when it arrives. | 
|---|
| 171 | */ | 
|---|
| 172 | PRESOLVE_REMOVE_LINK(clink, j); | 
|---|
| 173 | hincol[j] = 0; | 
|---|
| 174 | } | 
|---|
| 175 | /* | 
|---|
| 176 | Set the actual end of the coefficient and row index arrays. | 
|---|
| 177 | */ | 
|---|
| 178 | actions[nfcols].start=actsize; | 
|---|
| 179 | # if PRESOLVE_SUMMARY | 
|---|
| 180 | printf( "NFIXED:  %d", nfcols); | 
|---|
| 181 | if (estsize-actsize > 0) | 
|---|
| 182 | { printf( ", overalloc %d",estsize-actsize) ; } | 
|---|
| 183 | printf( "\n") ; | 
|---|
| 184 | # endif | 
|---|
| 185 | // Now get columns by row | 
|---|
| 186 | int * column = new int[actsize]; | 
|---|
| 187 | int nel=0; | 
|---|
| 188 | int iRow; | 
|---|
| 189 | for (iRow=0;iRow<nrows;iRow++) { | 
|---|
| 190 | int n=rstrt[iRow]; | 
|---|
| 191 | rstrt[iRow]=nel; | 
|---|
| 192 | nel += n; | 
|---|
| 193 | } | 
|---|
| 194 | rstrt[nrows]=nel; | 
|---|
| 195 | for (ckc = 0 ; ckc < nfcols ; ckc++) { | 
|---|
| 196 | int kcs = actions[ckc].start; | 
|---|
| 197 | int j=actions[ckc].col; | 
|---|
| 198 | int kce; | 
|---|
| 199 | if (ckc<nfcols-1) | 
|---|
| 200 | kce = actions[ckc+1].start; | 
|---|
| 201 | else | 
|---|
| 202 | kce = actsize; | 
|---|
| 203 | for (int k=kcs;k<kce;k++) { | 
|---|
| 204 | int iRow = rows_action[k]; | 
|---|
| 205 | CoinBigIndex put = rstrt[iRow]; | 
|---|
| 206 | rstrt[iRow]++; | 
|---|
| 207 | column[put]=j; | 
|---|
| 208 | } | 
|---|
| 209 | } | 
|---|
| 210 | // Now do rows | 
|---|
| 211 | int ncols		= prob->ncols_; | 
|---|
| 212 | char * mark = new char[ncols]; | 
|---|
| 213 | memset(mark,0,ncols); | 
|---|
| 214 | // rstrts are now one out i.e. rstrt[0] is end of row 0 | 
|---|
| 215 | nel=0; | 
|---|
| 216 | #ifdef TRY2 | 
|---|
| 217 | for (iRow=0;iRow<nrows;iRow++) { | 
|---|
| 218 | int k; | 
|---|
| 219 | for (k=nel;k<rstrt[iRow];k++) { | 
|---|
| 220 | mark[column[k]]=1; | 
|---|
| 221 | } | 
|---|
| 222 | presolve_delete_many_from_major(iRow,mark,mrstrt,hinrow,hcol,rowels); | 
|---|
| 223 | #ifndef NDEBUG | 
|---|
| 224 | for (k=nel;k<rstrt[iRow];k++) { | 
|---|
| 225 | assert(mark[column[k]]==0); | 
|---|
| 226 | } | 
|---|
| 227 | #endif | 
|---|
| 228 | if (hinrow[iRow] == 0) | 
|---|
| 229 | { | 
|---|
| 230 | PRESOLVE_REMOVE_LINK(rlink,iRow) ; | 
|---|
| 231 | } | 
|---|
| 232 | // mark unless already marked | 
|---|
| 233 | if (!prob->rowChanged(iRow)) { | 
|---|
| 234 | prob->addRow(iRow); | 
|---|
| 235 | CoinBigIndex krs = mrstrt[iRow]; | 
|---|
| 236 | CoinBigIndex kre = krs + hinrow[iRow]; | 
|---|
| 237 | for (CoinBigIndex k=krs; k<kre; k++) { | 
|---|
| 238 | int jcol = hcol[k]; | 
|---|
| 239 | prob->addCol(jcol); | 
|---|
| 240 | } | 
|---|
| 241 | } | 
|---|
| 242 | nel=rstrt[iRow]; | 
|---|
| 243 | } | 
|---|
| 244 | #endif | 
|---|
| 245 | delete [] mark; | 
|---|
| 246 | delete [] column; | 
|---|
| 247 | delete [] rstrt; | 
|---|
| 248 |  | 
|---|
| 249 | # if PRESOLVE_DEBUG | 
|---|
| 250 | presolve_check_sol(prob) ; | 
|---|
| 251 | std::cout << "Leaving remove_fixed_action::presolve."<< std::endl ; | 
|---|
| 252 | # endif | 
|---|
| 253 |  | 
|---|
| 254 | /* | 
|---|
| 255 | Create the postsolve object, link it at the head of the list of postsolve | 
|---|
| 256 | objects, and return a pointer. | 
|---|
| 257 | */ | 
|---|
| 258 | return (new remove_fixed_action(nfcols, | 
|---|
| 259 | actions,els_action,rows_action,next)); | 
|---|
| 260 | } | 
|---|
| 261 |  | 
|---|
| 262 |  | 
|---|
| 263 | remove_fixed_action::remove_fixed_action(int nactions, | 
|---|
| 264 | action *actions, | 
|---|
| 265 | double * els_action, | 
|---|
| 266 | int * rows_action, | 
|---|
| 267 | const CoinPresolveAction *next) : | 
|---|
| 268 | CoinPresolveAction(next), | 
|---|
| 269 | colrows_(rows_action), | 
|---|
| 270 | colels_(els_action), | 
|---|
| 271 | nactions_(nactions), | 
|---|
| 272 | actions_(actions) | 
|---|
| 273 | { | 
|---|
| 274 | } | 
|---|
| 275 |  | 
|---|
| 276 | remove_fixed_action::~remove_fixed_action() | 
|---|
| 277 | { | 
|---|
| 278 | deleteAction(actions_,action*); | 
|---|
| 279 | delete [] colels_; | 
|---|
| 280 | delete [] colrows_; | 
|---|
| 281 | } | 
|---|
| 282 |  | 
|---|
| 283 | /* | 
|---|
| 284 | * Say we determined that cup - clo <= ztolzb, so we fixed sol at clo. | 
|---|
| 285 | * This involved subtracting clo*coeff from ub/lb for each row the | 
|---|
| 286 | * variable occurred in. | 
|---|
| 287 | * Now when we put the variable back in, by construction the variable | 
|---|
| 288 | * is within tolerance, the non-slacks are unchanged, and the | 
|---|
| 289 | * distances of the affected slacks from their bounds should remain | 
|---|
| 290 | * unchanged (ignoring roundoff errors). | 
|---|
| 291 | * It may be that by adding the term back in, the affected constraints | 
|---|
| 292 | * now aren't as accurate due to round-off errors; this could happen | 
|---|
| 293 | * if only one summand and the slack in the original formulation were large | 
|---|
| 294 | * (and naturally had opposite signs), and the new term in the constraint | 
|---|
| 295 | * is about the size of the old slack, so the new slack becomes about 0. | 
|---|
| 296 | * It may be that there is catastrophic cancellation in the summation, | 
|---|
| 297 | * so it might not compute to 0. | 
|---|
| 298 | */ | 
|---|
| 299 | void remove_fixed_action::postsolve(CoinPostsolveMatrix *prob) const | 
|---|
| 300 | { | 
|---|
| 301 | action * actions	= actions_; | 
|---|
| 302 | const int nactions	= nactions_; | 
|---|
| 303 |  | 
|---|
| 304 | double *colels	= prob->colels_; | 
|---|
| 305 | int *hrow		= prob->hrow_; | 
|---|
| 306 | CoinBigIndex *mcstrt	= prob->mcstrt_; | 
|---|
| 307 | int *hincol		= prob->hincol_; | 
|---|
| 308 | int *link		= prob->link_; | 
|---|
| 309 | CoinBigIndex &free_list = prob->free_list_; | 
|---|
| 310 |  | 
|---|
| 311 | double *clo	= prob->clo_; | 
|---|
| 312 | double *cup	= prob->cup_; | 
|---|
| 313 | double *rlo	= prob->rlo_; | 
|---|
| 314 | double *rup	= prob->rup_; | 
|---|
| 315 |  | 
|---|
| 316 | double *sol	= prob->sol_; | 
|---|
| 317 | double *dcost	= prob->cost_; | 
|---|
| 318 | double *rcosts	= prob->rcosts_; | 
|---|
| 319 |  | 
|---|
| 320 | double *acts	= prob->acts_; | 
|---|
| 321 | double *rowduals = prob->rowduals_; | 
|---|
| 322 |  | 
|---|
| 323 | unsigned char *colstat	= prob->colstat_; | 
|---|
| 324 |  | 
|---|
| 325 | const double maxmin	= prob->maxmin_; | 
|---|
| 326 |  | 
|---|
| 327 | # if PRESOLVE_DEBUG || PRESOLVE_CONSISTENCY | 
|---|
| 328 | char *cdone	= prob->cdone_; | 
|---|
| 329 |  | 
|---|
| 330 | std::cout << "Entering remove_fixed_action::postsolve."<< std::endl ; | 
|---|
| 331 | presolve_check_threads(prob) ; | 
|---|
| 332 | presolve_check_free_list(prob) ; | 
|---|
| 333 | presolve_check_sol(prob) ; | 
|---|
| 334 | presolve_check_nbasic(prob) ; | 
|---|
| 335 | # endif | 
|---|
| 336 |  | 
|---|
| 337 | double * els_action = colels_; | 
|---|
| 338 | int * rows_action = colrows_; | 
|---|
| 339 | int end = actions[nactions].start; | 
|---|
| 340 |  | 
|---|
| 341 | /* | 
|---|
| 342 | At one point, it turned out that forcing_constraint_action was putting | 
|---|
| 343 | duplicates in the column list it passed to remove_fixed_action. This is now | 
|---|
| 344 | fixed, but ... it looks to me like we could be in trouble here if we | 
|---|
| 345 | reinstate a column multiple times. Hence the assert. | 
|---|
| 346 | */ | 
|---|
| 347 | for (const action *f = &actions[nactions-1]; actions<=f; f--) { | 
|---|
| 348 | int icol = f->col; | 
|---|
| 349 | const double thesol = f->sol; | 
|---|
| 350 |  | 
|---|
| 351 | # if PRESOLVE_DEBUG || PRESOLVE_CONSISTENCY | 
|---|
| 352 | assert(cdone[icol] != FIXED_VARIABLE) ; | 
|---|
| 353 | cdone[icol] = FIXED_VARIABLE ; | 
|---|
| 354 | # endif | 
|---|
| 355 |  | 
|---|
| 356 | sol[icol] = thesol; | 
|---|
| 357 | clo[icol] = thesol; | 
|---|
| 358 | cup[icol] = thesol; | 
|---|
| 359 |  | 
|---|
| 360 | int cs = NO_LINK ; | 
|---|
| 361 | int start = f->start; | 
|---|
| 362 | double dj = maxmin * dcost[icol]; | 
|---|
| 363 |  | 
|---|
| 364 | for (int i=start; i<end; ++i) { | 
|---|
| 365 | int row = rows_action[i]; | 
|---|
| 366 | double coeff =els_action[i]; | 
|---|
| 367 |  | 
|---|
| 368 | // pop free_list | 
|---|
| 369 | CoinBigIndex k = free_list; | 
|---|
| 370 | assert(k >= 0 && k < prob->bulk0_) ; | 
|---|
| 371 | free_list = link[free_list]; | 
|---|
| 372 | // restore | 
|---|
| 373 | hrow[k] = row; | 
|---|
| 374 | colels[k] = coeff; | 
|---|
| 375 | link[k] = cs; | 
|---|
| 376 | cs = k; | 
|---|
| 377 |  | 
|---|
| 378 | if (-PRESOLVE_INF < rlo[row]) | 
|---|
| 379 | rlo[row] += coeff * thesol; | 
|---|
| 380 | if (rup[row] < PRESOLVE_INF) | 
|---|
| 381 | rup[row] += coeff * thesol; | 
|---|
| 382 | acts[row] += coeff * thesol; | 
|---|
| 383 |  | 
|---|
| 384 | dj -= rowduals[row] * coeff; | 
|---|
| 385 | } | 
|---|
| 386 |  | 
|---|
| 387 | #   if PRESOLVE_CONSISTENCY | 
|---|
| 388 | presolve_check_free_list(prob) ; | 
|---|
| 389 | #   endif | 
|---|
| 390 |  | 
|---|
| 391 | mcstrt[icol] = cs; | 
|---|
| 392 |  | 
|---|
| 393 | rcosts[icol] = dj; | 
|---|
| 394 | hincol[icol] = end-start; | 
|---|
| 395 | end=start; | 
|---|
| 396 |  | 
|---|
| 397 | /* Original comment: | 
|---|
| 398 | * the bounds in the reduced problem were tightened. | 
|---|
| 399 | * that means that this variable may not have been basic | 
|---|
| 400 | * because it didn't have to be, | 
|---|
| 401 | * but now it may have to. | 
|---|
| 402 | * no - the bounds aren't changed by this operation | 
|---|
| 403 | */ | 
|---|
| 404 | /* | 
|---|
| 405 | We've reintroduced the variable, but it's still fixed (equal bounds). | 
|---|
| 406 | Pick the nonbasic status that agrees with the reduced cost. Later, if | 
|---|
| 407 | postsolve unfixes the variable, we'll need to confirm that this status is | 
|---|
| 408 | still viable. We live in a minimisation world here. | 
|---|
| 409 | */ | 
|---|
| 410 | if (colstat) | 
|---|
| 411 | { if (dj < 0) | 
|---|
| 412 | prob->setColumnStatus(icol,CoinPrePostsolveMatrix::atUpperBound); | 
|---|
| 413 | else | 
|---|
| 414 | prob->setColumnStatus(icol,CoinPrePostsolveMatrix::atLowerBound); } | 
|---|
| 415 |  | 
|---|
| 416 | } | 
|---|
| 417 |  | 
|---|
| 418 |  | 
|---|
| 419 | # if PRESOLVE_CONSISTENCY || PRESOLVE_DEBUG | 
|---|
| 420 | presolve_check_threads(prob) ; | 
|---|
| 421 | presolve_check_sol(prob) ; | 
|---|
| 422 | presolve_check_nbasic(prob) ; | 
|---|
| 423 | std::cout << "Leaving remove_fixed_action::postsolve."<< std::endl ; | 
|---|
| 424 | # endif | 
|---|
| 425 |  | 
|---|
| 426 | return ; | 
|---|
| 427 | } | 
|---|
| 428 |  | 
|---|
| 429 | /* | 
|---|
| 430 | Scan the problem for variables that are already fixed, and remove them. | 
|---|
| 431 | There's an implicit assumption that the value of the variable is already | 
|---|
| 432 | within bounds. If you want to protect against this possibility, you want to | 
|---|
| 433 | use make_fixed. | 
|---|
| 434 | */ | 
|---|
| 435 | const CoinPresolveAction *remove_fixed (CoinPresolveMatrix *prob, | 
|---|
| 436 | const CoinPresolveAction *next) | 
|---|
| 437 | { | 
|---|
| 438 | int ncols	= prob->ncols_; | 
|---|
| 439 | int *fcols	= new int[ncols]; | 
|---|
| 440 | int nfcols	= 0; | 
|---|
| 441 |  | 
|---|
| 442 | int *hincol		= prob->hincol_; | 
|---|
| 443 |  | 
|---|
| 444 | double *clo	= prob->clo_; | 
|---|
| 445 | double *cup	= prob->cup_; | 
|---|
| 446 |  | 
|---|
| 447 | for (int i = 0 ; i < ncols ; i++) | 
|---|
| 448 | if (hincol[i] > 0 && clo[i] == cup[i]&&!prob->colProhibited2(i)) | 
|---|
| 449 | fcols[nfcols++] = i; | 
|---|
| 450 |  | 
|---|
| 451 | if (nfcols > 0) | 
|---|
| 452 | { next = remove_fixed_action::presolve(prob, fcols, nfcols, next) ; } | 
|---|
| 453 | delete[]fcols; | 
|---|
| 454 | return (next); | 
|---|
| 455 | } | 
|---|
| 456 |  | 
|---|
| 457 | /* End routines associated with remove_fixed_action */ | 
|---|
| 458 |  | 
|---|
| 459 | /* Begin routines associated with make_fixed_action */ | 
|---|
| 460 |  | 
|---|
| 461 | const char *make_fixed_action::name() const | 
|---|
| 462 | { | 
|---|
| 463 | return ( "make_fixed_action"); | 
|---|
| 464 | } | 
|---|
| 465 |  | 
|---|
| 466 |  | 
|---|
| 467 | /* | 
|---|
| 468 | This routine does the actual job of fixing one or more variables. The set | 
|---|
| 469 | of indices to be fixed is specified by nfcols and fcols. fix_to_lower | 
|---|
| 470 | specifies the bound where the variable(s) should be fixed. The other bound | 
|---|
| 471 | is preserved as part of the action and the bounds are set equal. Note that | 
|---|
| 472 | you don't get to specify the bound on a per-variable basis. | 
|---|
| 473 |  | 
|---|
| 474 | If a primal solution is available, make_fixed_action will adjust the the | 
|---|
| 475 | row activity to compensate for forcing the variable within bounds. If the | 
|---|
| 476 | bounds are already equal, and the variable is within bounds, you should | 
|---|
| 477 | consider remove_fixed_action. | 
|---|
| 478 | */ | 
|---|
| 479 | const CoinPresolveAction* | 
|---|
| 480 | make_fixed_action::presolve (CoinPresolveMatrix *prob, | 
|---|
| 481 | int *fcols, int nfcols, | 
|---|
| 482 | bool fix_to_lower, | 
|---|
| 483 | const CoinPresolveAction *next) | 
|---|
| 484 |  | 
|---|
| 485 | { double *clo	= prob->clo_; | 
|---|
| 486 | double *cup	= prob->cup_; | 
|---|
| 487 | double *csol	= prob->sol_; | 
|---|
| 488 |  | 
|---|
| 489 | double *colels = prob->colels_; | 
|---|
| 490 | int *hrow	= prob->hrow_; | 
|---|
| 491 | CoinBigIndex *mcstrt	= prob->mcstrt_; | 
|---|
| 492 | int *hincol	= prob->hincol_; | 
|---|
| 493 |  | 
|---|
| 494 | double *acts	= prob->acts_; | 
|---|
| 495 |  | 
|---|
| 496 | /* | 
|---|
| 497 | Shouldn't happen, but ... | 
|---|
| 498 | */ | 
|---|
| 499 | if (nfcols <= 0) return (next) ; | 
|---|
| 500 |  | 
|---|
| 501 | action *actions = new action[nfcols]; | 
|---|
| 502 |  | 
|---|
| 503 | /* | 
|---|
| 504 | Scan the set of indices specifying variables to be fixed. For each variable, | 
|---|
| 505 | stash the unused bound in the action and set the bounds equal. If the client | 
|---|
| 506 | has passed in a primal solution, update it if the value of the variable | 
|---|
| 507 | changes. | 
|---|
| 508 | */ | 
|---|
| 509 | for (int ckc = 0 ; ckc < nfcols ; ckc++) | 
|---|
| 510 | { int j = fcols[ckc] ; | 
|---|
| 511 | double movement = 0 ; | 
|---|
| 512 |  | 
|---|
| 513 | action &f = actions[ckc] ; | 
|---|
| 514 |  | 
|---|
| 515 | f.col = j ; | 
|---|
| 516 | if (fix_to_lower) { | 
|---|
| 517 | f.bound = cup[j]; | 
|---|
| 518 | cup[j] = clo[j]; | 
|---|
| 519 | if (csol) { | 
|---|
| 520 | movement = clo[j]-csol[j] ; | 
|---|
| 521 | csol[j] = clo[j] ; | 
|---|
| 522 | } | 
|---|
| 523 | } else { | 
|---|
| 524 | f.bound = clo[j]; | 
|---|
| 525 | clo[j] = cup[j]; | 
|---|
| 526 | if (csol) { | 
|---|
| 527 | movement = cup[j]-csol[j]; | 
|---|
| 528 | csol[j] = cup[j]; | 
|---|
| 529 | } | 
|---|
| 530 | } | 
|---|
| 531 | if (movement) { | 
|---|
| 532 | CoinBigIndex k; | 
|---|
| 533 | for (k = mcstrt[j] ; k < mcstrt[j]+hincol[j] ; k++) { | 
|---|
| 534 | int row = hrow[k]; | 
|---|
| 535 | acts[row] += movement*colels[k]; | 
|---|
| 536 | } | 
|---|
| 537 | } | 
|---|
| 538 | } | 
|---|
| 539 | /* | 
|---|
| 540 | Original comment: | 
|---|
| 541 | This is unusual in that the make_fixed_action transform | 
|---|
| 542 | contains within it a remove_fixed_action transform | 
|---|
| 543 | bad idea? | 
|---|
| 544 |  | 
|---|
| 545 | Explanatory comment: | 
|---|
| 546 | Now that we've adjusted the bounds, time to create the postsolve action | 
|---|
| 547 | that will restore the original bounds. But wait! We're not done. By calling | 
|---|
| 548 | remove_fixed_action::presolve, we will remove these variables from the | 
|---|
| 549 | model, caching the postsolve transform that will restore them inside the | 
|---|
| 550 | postsolve transform for fixing the bounds. | 
|---|
| 551 | */ | 
|---|
| 552 | if (nfcols > 0) | 
|---|
| 553 | { next = new make_fixed_action(nfcols, actions, fix_to_lower, | 
|---|
| 554 | remove_fixed_action::presolve(prob,fcols, nfcols,0), | 
|---|
| 555 | next) ; } | 
|---|
| 556 | return (next) ; | 
|---|
| 557 | } | 
|---|
| 558 |  | 
|---|
| 559 | /* | 
|---|
| 560 | Recall that in presolve, make_fixed_action forced a bound to fix a variable, | 
|---|
| 561 | then called remove_fixed_action to empty the column. removed_fixed_action | 
|---|
| 562 | left a postsolve object hanging off faction_, and our first act here is to | 
|---|
| 563 | call r_f_a::postsolve to repopulate the columns. The m_f_a postsolve activity | 
|---|
| 564 | consists of relaxing one of the bounds and making sure that the status is | 
|---|
| 565 | still viable (we can potentially eliminate the bound here). | 
|---|
| 566 | */ | 
|---|
| 567 | void make_fixed_action::postsolve(CoinPostsolveMatrix *prob) const | 
|---|
| 568 | { | 
|---|
| 569 | const action *const actions = actions_; | 
|---|
| 570 | const int nactions = nactions_; | 
|---|
| 571 | const bool fix_to_lower = fix_to_lower_; | 
|---|
| 572 |  | 
|---|
| 573 | double *clo	= prob->clo_; | 
|---|
| 574 | double *cup	= prob->cup_; | 
|---|
| 575 | double *sol	= prob->sol_ ; | 
|---|
| 576 | unsigned char *colstat = prob->colstat_; | 
|---|
| 577 | /* | 
|---|
| 578 | Repopulate the columns. | 
|---|
| 579 | */ | 
|---|
| 580 | assert(nactions == faction_->nactions_) ; | 
|---|
| 581 | faction_->postsolve(prob); | 
|---|
| 582 | /* | 
|---|
| 583 | Walk the actions: restore each bound and check that the status is still | 
|---|
| 584 | appropriate. Given that we're unfixing a fixed variable, it's safe to assume | 
|---|
| 585 | that the unaffected bound is finite. | 
|---|
| 586 | */ | 
|---|
| 587 | for (int cnt = nactions-1 ; cnt >= 0 ; cnt--) | 
|---|
| 588 | { const action *f = &actions[cnt]; | 
|---|
| 589 | int icol = f->col; | 
|---|
| 590 | double xj = sol[icol] ; | 
|---|
| 591 |  | 
|---|
| 592 | assert(faction_->actions_[cnt].col == icol) ; | 
|---|
| 593 |  | 
|---|
| 594 | if (fix_to_lower) | 
|---|
| 595 | { double ub = f->bound ; | 
|---|
| 596 | cup[icol] = ub ; | 
|---|
| 597 | if (colstat) | 
|---|
| 598 | { if (ub >= PRESOLVE_INF || xj != ub) | 
|---|
| 599 | { prob->setColumnStatus(icol, | 
|---|
| 600 | CoinPrePostsolveMatrix::atLowerBound) ; } } } | 
|---|
| 601 | else | 
|---|
| 602 | { double lb = f->bound ; | 
|---|
| 603 | clo[icol] = lb ; | 
|---|
| 604 | if (colstat) | 
|---|
| 605 | { if (lb <= -PRESOLVE_INF || xj != lb) | 
|---|
| 606 | { prob->setColumnStatus(icol, | 
|---|
| 607 | CoinPrePostsolveMatrix::atUpperBound) ; } } } } | 
|---|
| 608 |  | 
|---|
| 609 | # if PRESOLVE_CONSISTENCY || PRESOLVE_DEBUG | 
|---|
| 610 | presolve_check_threads(prob) ; | 
|---|
| 611 | presolve_check_sol(prob) ; | 
|---|
| 612 | presolve_check_nbasic(prob) ; | 
|---|
| 613 | std::cout << "Leaving make_fixed_action::postsolve."<< std::endl ; | 
|---|
| 614 | # endif | 
|---|
| 615 | return ; } | 
|---|
| 616 |  | 
|---|
| 617 | /*! | 
|---|
| 618 | Scan the columns and collect indices of columns that have upper and lower | 
|---|
| 619 | bounds within the zero tolerance of one another. Hand this list to | 
|---|
| 620 | make_fixed_action::presolve() to do the heavy lifting. | 
|---|
| 621 |  | 
|---|
| 622 | make_fixed_action will compensate for variables which are infeasible, forcing | 
|---|
| 623 | them to feasibility and correcting the row activity, before invoking | 
|---|
| 624 | remove_fixed_action to remove the variable from the problem. If you're | 
|---|
| 625 | confident of feasibility, consider remove_fixed. | 
|---|
| 626 | */ | 
|---|
| 627 | const CoinPresolveAction *make_fixed (CoinPresolveMatrix *prob, | 
|---|
| 628 | const CoinPresolveAction *next) | 
|---|
| 629 | { | 
|---|
| 630 | int ncols	= prob->ncols_; | 
|---|
| 631 | int *fcols	= new int[ncols]; | 
|---|
| 632 | int nfcols	= 0; | 
|---|
| 633 |  | 
|---|
| 634 | int *hincol	= prob->hincol_; | 
|---|
| 635 |  | 
|---|
| 636 | double *clo	= prob->clo_; | 
|---|
| 637 | double *cup	= prob->cup_; | 
|---|
| 638 |  | 
|---|
| 639 | for (int i = 0 ; i < ncols ; i++) | 
|---|
| 640 | { if (hincol[i] > 0 && | 
|---|
| 641 | fabs(cup[i] - clo[i]) < ZTOLDP && !prob->colProhibited2(i)) | 
|---|
| 642 | { fcols[nfcols++] = i ; } } | 
|---|
| 643 |  | 
|---|
| 644 | /* | 
|---|
| 645 | Call m_f_a::presolve to do the heavy lifting. This will create a new | 
|---|
| 646 | CoinPresolveAction, which will become the head of the list of | 
|---|
| 647 | CoinPresolveAction's currently pointed to by next. | 
|---|
| 648 | */ | 
|---|
| 649 | next = make_fixed_action::presolve(prob,fcols,nfcols,true,next) ; | 
|---|
| 650 |  | 
|---|
| 651 | delete[]fcols ; | 
|---|
| 652 | return (next) ; } | 
|---|
| 653 | // Transfers costs | 
|---|
| 654 | void | 
|---|
| 655 | transferCosts(CoinPresolveMatrix * prob) | 
|---|
| 656 | { | 
|---|
| 657 | double *colels	= prob->colels_; | 
|---|
| 658 | int *hrow		= prob->hrow_; | 
|---|
| 659 | CoinBigIndex *mcstrt	= prob->mcstrt_; | 
|---|
| 660 | int *hincol		= prob->hincol_; | 
|---|
| 661 |  | 
|---|
| 662 | double *rowels	= prob->rowels_; | 
|---|
| 663 | int *hcol		= prob->hcol_; | 
|---|
| 664 | CoinBigIndex *mrstrt	= prob->mrstrt_; | 
|---|
| 665 | int *hinrow		= prob->hinrow_; | 
|---|
| 666 |  | 
|---|
| 667 | double *rlo	= prob->rlo_; | 
|---|
| 668 | double *rup	= prob->rup_; | 
|---|
| 669 | double *clo	= prob->clo_; | 
|---|
| 670 | double *cup	= prob->cup_; | 
|---|
| 671 | int ncols = prob->ncols_; | 
|---|
| 672 | double *dcost	= prob->cost_; | 
|---|
| 673 | unsigned char * integerType = prob->integerType_; | 
|---|
| 674 | double bias = prob->dobias_; | 
|---|
| 675 | int icol; | 
|---|
| 676 | int numberIntegers=0; | 
|---|
| 677 | for (icol=0;icol<ncols;icol++) { | 
|---|
| 678 | if (integerType[icol]) | 
|---|
| 679 | numberIntegers++; | 
|---|
| 680 | } | 
|---|
| 681 | int nchanged=0; | 
|---|
| 682 | for (icol=0;icol<ncols;icol++) { | 
|---|
| 683 | if (dcost[icol]&&hincol[icol]==1&&cup[icol]>clo[icol]) { | 
|---|
| 684 | int irow=hrow[mcstrt[icol]]; | 
|---|
| 685 | if (rlo[irow]==rup[irow]) { | 
|---|
| 686 | // transfer costs so can be made slack | 
|---|
| 687 | double ratio = dcost[icol]/colels[mcstrt[icol]]; | 
|---|
| 688 | bias += rlo[irow]*ratio; | 
|---|
| 689 | for (CoinBigIndex j=mrstrt[irow];j<mrstrt[irow]+hinrow[irow];j++) { | 
|---|
| 690 | int jcol = hcol[j]; | 
|---|
| 691 | double value = rowels[j]; | 
|---|
| 692 | dcost[jcol] -= ratio*value; | 
|---|
| 693 | } | 
|---|
| 694 | dcost[icol]=0.0; | 
|---|
| 695 | nchanged++; | 
|---|
| 696 | } | 
|---|
| 697 | } | 
|---|
| 698 | } | 
|---|
| 699 | //if (nchanged) | 
|---|
| 700 | //printf("%d singleton columns have transferred costs\n",nchanged); | 
|---|
| 701 | if (numberIntegers) { | 
|---|
| 702 | int changed=-1; | 
|---|
| 703 | while (changed) { | 
|---|
| 704 | changed=0; | 
|---|
| 705 | for (icol=0;icol<ncols;icol++) { | 
|---|
| 706 | if (dcost[icol]&&cup[icol]>clo[icol]) { | 
|---|
| 707 | for (CoinBigIndex k=mcstrt[icol];k<mcstrt[icol]+hincol[icol];k++) { | 
|---|
| 708 | int irow=hrow[k]; | 
|---|
| 709 | if (rlo[irow]==rup[irow]) { | 
|---|
| 710 | // See if can give more integer variables costs | 
|---|
| 711 | CoinBigIndex j; | 
|---|
| 712 | int nNow = integerType[icol] ? 1 : 0; | 
|---|
| 713 | int nThen=0; | 
|---|
| 714 | for (j=mrstrt[irow];j<mrstrt[irow]+hinrow[irow];j++) { | 
|---|
| 715 | int jcol = hcol[j]; | 
|---|
| 716 | if (!dcost[jcol]&&integerType[jcol]) | 
|---|
| 717 | nThen++; | 
|---|
| 718 | } | 
|---|
| 719 | if (nThen>nNow) { | 
|---|
| 720 | // transfer costs so can be made slack | 
|---|
| 721 | double ratio = dcost[icol]/colels[mcstrt[icol]]; | 
|---|
| 722 | bias += rlo[irow]*ratio; | 
|---|
| 723 | for (j=mrstrt[irow];j<mrstrt[irow]+hinrow[irow];j++) { | 
|---|
| 724 | int jcol = hcol[j]; | 
|---|
| 725 | double value = rowels[j]; | 
|---|
| 726 | dcost[jcol] -= ratio*value; | 
|---|
| 727 | } | 
|---|
| 728 | dcost[icol]=0.0; | 
|---|
| 729 | changed++; | 
|---|
| 730 | break; | 
|---|
| 731 | } | 
|---|
| 732 | } | 
|---|
| 733 | } | 
|---|
| 734 | } | 
|---|
| 735 | } | 
|---|
| 736 | if (changed) { | 
|---|
| 737 | nchanged+=changed; | 
|---|
| 738 | //printf("%d changed this pass\n",changed); | 
|---|
| 739 | } | 
|---|
| 740 | } | 
|---|
| 741 | } | 
|---|
| 742 | //if (bias!=prob->dobias_) | 
|---|
| 743 | //printf("new bias %g\n",bias); | 
|---|
| 744 | prob->dobias_ = bias; | 
|---|
| 745 | } | 
|---|
| 746 |  | 
|---|