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 | |