1 | /* $Id: CoinPresolveTripleton.cpp 1448 2011-06-19 15:34:41Z stefan $ */ |
2 | // Copyright (C) 2003, 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 "CoinFinite.hpp" |
10 | #include "CoinHelperFunctions.hpp" |
11 | #include "CoinPresolveMatrix.hpp" |
12 | |
13 | #include "CoinPresolveEmpty.hpp" // for DROP_COL/DROP_ROW |
14 | #include "CoinPresolveZeros.hpp" |
15 | #include "CoinPresolveFixed.hpp" |
16 | #include "CoinPresolveTripleton.hpp" |
17 | |
18 | #include "CoinPresolvePsdebug.hpp" |
19 | #include "CoinMessage.hpp" |
20 | |
21 | #if PRESOLVE_DEBUG || PRESOLVE_CONSISTENCY |
22 | #include "CoinPresolvePsdebug.hpp" |
23 | #endif |
24 | |
25 | /* |
26 | * Substituting y away: |
27 | * |
28 | * y = (c - a x - d z) / b |
29 | * |
30 | * so adjust bounds by: c/b |
31 | * and x by: -a/b |
32 | * and z by: -d/b |
33 | * |
34 | * This affects both the row and col representations. |
35 | * |
36 | * mcstrt only modified if the column must be moved. |
37 | * |
38 | * for every row in icoly |
39 | * if icolx is also has an entry for row |
40 | * modify the icolx entry for row |
41 | * drop the icoly entry from row and modify the icolx entry |
42 | * else |
43 | * add a new entry to icolx column |
44 | * create a new icolx entry |
45 | * (this may require moving the column in memory) |
46 | * replace icoly entry from row and replace with icolx entry |
47 | * |
48 | * same for icolz |
49 | * The row and column reps are inconsistent during the routine, |
50 | * because icolx in the column rep is updated, and the entries corresponding |
51 | * to icolx in the row rep are updated, but nothing concerning icoly |
52 | * in the col rep is changed. icoly entries in the row rep are deleted, |
53 | * and icolx entries in both reps are consistent. |
54 | * At the end, we set the length of icoly to be zero, so the reps would |
55 | * be consistent if the row were deleted from the row rep. |
56 | * Both the row and icoly must be removed from both reps. |
57 | * In the col rep, icoly will be eliminated entirely, at the end of the routine; |
58 | * irow occurs in just two columns, one of which (icoly) is eliminated |
59 | * entirely, the other is icolx, which is not deleted here. |
60 | * In the row rep, irow will be eliminated entirely, but not here; |
61 | * icoly is removed from the rows it occurs in. |
62 | */ |
63 | static bool elim_tripleton(const char * |
64 | #ifdef PRESOLVE_DEBUG |
65 | msg |
66 | #endif |
67 | , |
68 | CoinBigIndex *mcstrt, |
69 | double *rlo, double * acts, double *rup, |
70 | double *colels, |
71 | int *hrow, int *hcol, |
72 | int *hinrow, int *hincol, |
73 | presolvehlink *clink, int ncols, |
74 | presolvehlink *rlink, int nrows, |
75 | CoinBigIndex *mrstrt, double *rowels, |
76 | //double a, double b, double c, |
77 | double coeff_factorx,double coeff_factorz, |
78 | double bounds_factor, |
79 | int row0, int icolx, int icoly, int icolz) |
80 | { |
81 | CoinBigIndex kcs = mcstrt[icoly]; |
82 | CoinBigIndex kce = kcs + hincol[icoly]; |
83 | CoinBigIndex kcsx = mcstrt[icolx]; |
84 | CoinBigIndex kcex = kcsx + hincol[icolx]; |
85 | CoinBigIndex kcsz = mcstrt[icolz]; |
86 | CoinBigIndex kcez = kcsz + hincol[icolz]; |
87 | |
88 | # if PRESOLVE_DEBUG |
89 | printf("%s %d x=%d y=%d z=%d cfx=%g cfz=%g nx=%d yrows=(" , msg, |
90 | row0,icolx,icoly,icolz,coeff_factorx,coeff_factorz,hincol[icolx]) ; |
91 | # endif |
92 | for (CoinBigIndex kcoly=kcs; kcoly<kce; kcoly++) { |
93 | int row = hrow[kcoly]; |
94 | |
95 | // even though these values are updated, they remain consistent |
96 | PRESOLVEASSERT(kcex == kcsx + hincol[icolx]); |
97 | PRESOLVEASSERT(kcez == kcsz + hincol[icolz]); |
98 | |
99 | // we don't need to update the row being eliminated |
100 | if (row != row0/* && hinrow[row] > 0*/) { |
101 | if (bounds_factor != 0.0) { |
102 | // (1) |
103 | if (-PRESOLVE_INF < rlo[row]) |
104 | rlo[row] -= colels[kcoly] * bounds_factor; |
105 | |
106 | // (2) |
107 | if (rup[row] < PRESOLVE_INF) |
108 | rup[row] -= colels[kcoly] * bounds_factor; |
109 | |
110 | // and solution |
111 | if (acts) |
112 | { acts[row] -= colels[kcoly] * bounds_factor; } |
113 | } |
114 | // see if row appears in colx |
115 | CoinBigIndex kcolx = presolve_find_row1(row, kcsx, kcex, hrow); |
116 | # if PRESOLVE_DEBUG |
117 | printf("%d%s " ,row,(kcolx<kcex)?"x+" :"" ) ; |
118 | # endif |
119 | // see if row appears in colz |
120 | CoinBigIndex kcolz = presolve_find_row1(row, kcsz, kcez, hrow); |
121 | # if PRESOLVE_DEBUG |
122 | printf("%d%s " ,row,(kcolz<kcez)?"x+" :"" ) ; |
123 | # endif |
124 | |
125 | if (kcolx>=kcex&&kcolz<kcez) { |
126 | // swap |
127 | int iTemp; |
128 | iTemp=kcolx; |
129 | kcolx=kcolz; |
130 | kcolz=iTemp; |
131 | iTemp=kcsx; |
132 | kcsx=kcsz; |
133 | kcsz=iTemp; |
134 | iTemp=kcex; |
135 | kcex=kcez; |
136 | kcez=iTemp; |
137 | iTemp=icolx; |
138 | icolx=icolz; |
139 | icolz=iTemp; |
140 | double dTemp=coeff_factorx; |
141 | coeff_factorx=coeff_factorz; |
142 | coeff_factorz=dTemp; |
143 | } |
144 | if (kcolx<kcex) { |
145 | // before: both x and y are in the row |
146 | // after: only x is in the row |
147 | // so: number of elems in col x unchanged, and num elems in row is one less |
148 | |
149 | // update col rep - just modify coefficent |
150 | // column y is deleted as a whole at the end of the loop |
151 | colels[kcolx] += colels[kcoly] * coeff_factorx; |
152 | // update row rep |
153 | // first, copy new value for col x into proper place in rowels |
154 | CoinBigIndex k2 = presolve_find_col(icolx, mrstrt[row], mrstrt[row]+hinrow[row], hcol); |
155 | rowels[k2] = colels[kcolx]; |
156 | if (kcolz<kcez) { |
157 | // before: both z and y are in the row |
158 | // after: only z is in the row |
159 | // so: number of elems in col z unchanged, and num elems in row is one less |
160 | |
161 | // update col rep - just modify coefficent |
162 | // column y is deleted as a whole at the end of the loop |
163 | colels[kcolz] += colels[kcoly] * coeff_factorz; |
164 | // update row rep |
165 | // first, copy new value for col z into proper place in rowels |
166 | CoinBigIndex k2 = presolve_find_col(icolz, mrstrt[row], mrstrt[row]+hinrow[row], hcol); |
167 | rowels[k2] = colels[kcolz]; |
168 | // now delete col y from the row; this changes hinrow[row] |
169 | presolve_delete_from_row(row, icoly, mrstrt, hinrow, hcol, rowels); |
170 | } else { |
171 | // before: only y is in the row |
172 | // after: only z is in the row |
173 | // so: number of elems in col z is one greater, but num elems in row remains same |
174 | // update entry corresponding to icolz in row rep |
175 | // by just overwriting the icoly entry |
176 | { |
177 | CoinBigIndex k2 = presolve_find_col(icoly, mrstrt[row], mrstrt[row]+hinrow[row], hcol); |
178 | hcol[k2] = icolz; |
179 | rowels[k2] = colels[kcoly] * coeff_factorz; |
180 | } |
181 | |
182 | { |
183 | bool no_mem = presolve_expand_col(mcstrt,colels,hrow,hincol, |
184 | clink,ncols,icolz); |
185 | if (no_mem) |
186 | return (true); |
187 | |
188 | // have to adjust various induction variables |
189 | kcolx = mcstrt[icolx] + (kcolx - kcsx); |
190 | kcsx = mcstrt[icolx]; |
191 | kcex = mcstrt[icolx] + hincol[icolx]; |
192 | kcoly = mcstrt[icoly] + (kcoly - kcs); |
193 | kcs = mcstrt[icoly]; // do this for ease of debugging |
194 | kce = mcstrt[icoly] + hincol[icoly]; |
195 | |
196 | kcolz = mcstrt[icolz] + (kcolz - kcs); // don't really need to do this |
197 | kcsz = mcstrt[icolz]; |
198 | kcez = mcstrt[icolz] + hincol[icolz]; |
199 | } |
200 | |
201 | // there is now an unused entry in the memory after the column - use it |
202 | // mcstrt[ncols] == penultimate index of arrays hrow/colels |
203 | hrow[kcez] = row; |
204 | colels[kcez] = colels[kcoly] * coeff_factorz; // y factor is 0.0 |
205 | hincol[icolz]++, kcez++; // expand the col |
206 | } |
207 | } else { |
208 | // before: only y is in the row |
209 | // after: only x and z are in the row |
210 | // update entry corresponding to icolx in row rep |
211 | // by just overwriting the icoly entry |
212 | { |
213 | CoinBigIndex k2 = presolve_find_col(icoly, mrstrt[row], mrstrt[row]+hinrow[row], hcol); |
214 | hcol[k2] = icolx; |
215 | rowels[k2] = colels[kcoly] * coeff_factorx; |
216 | } |
217 | presolve_expand_row(mrstrt,rowels,hcol,hinrow,rlink,nrows,row) ; |
218 | // there is now an unused entry in the memory after the column - use it |
219 | int krez = mrstrt[row]+hinrow[row]; |
220 | hcol[krez] = icolz; |
221 | rowels[krez] = colels[kcoly] * coeff_factorz; |
222 | hinrow[row]++; |
223 | |
224 | { |
225 | bool no_mem = presolve_expand_col(mcstrt,colels,hrow,hincol, |
226 | clink,ncols,icolx) ; |
227 | if (no_mem) |
228 | return (true); |
229 | |
230 | // have to adjust various induction variables |
231 | kcoly = mcstrt[icoly] + (kcoly - kcs); |
232 | kcs = mcstrt[icoly]; // do this for ease of debugging |
233 | kce = mcstrt[icoly] + hincol[icoly]; |
234 | |
235 | kcolx = mcstrt[icolx] + (kcolx - kcs); // don't really need to do this |
236 | kcsx = mcstrt[icolx]; |
237 | kcex = mcstrt[icolx] + hincol[icolx]; |
238 | kcolz = mcstrt[icolz] + (kcolz - kcs); // don't really need to do this |
239 | kcsz = mcstrt[icolz]; |
240 | kcez = mcstrt[icolz] + hincol[icolz]; |
241 | } |
242 | |
243 | // there is now an unused entry in the memory after the column - use it |
244 | hrow[kcex] = row; |
245 | colels[kcex] = colels[kcoly] * coeff_factorx; // y factor is 0.0 |
246 | hincol[icolx]++, kcex++; // expand the col |
247 | |
248 | { |
249 | bool no_mem = presolve_expand_col(mcstrt,colels,hrow,hincol,clink, |
250 | ncols,icolz); |
251 | if (no_mem) |
252 | return (true); |
253 | |
254 | // have to adjust various induction variables |
255 | kcoly = mcstrt[icoly] + (kcoly - kcs); |
256 | kcs = mcstrt[icoly]; // do this for ease of debugging |
257 | kce = mcstrt[icoly] + hincol[icoly]; |
258 | |
259 | kcsx = mcstrt[icolx]; |
260 | kcex = mcstrt[icolx] + hincol[icolx]; |
261 | kcsz = mcstrt[icolz]; |
262 | kcez = mcstrt[icolz] + hincol[icolz]; |
263 | } |
264 | |
265 | // there is now an unused entry in the memory after the column - use it |
266 | hrow[kcez] = row; |
267 | colels[kcez] = colels[kcoly] * coeff_factorz; // y factor is 0.0 |
268 | hincol[icolz]++, kcez++; // expand the col |
269 | } |
270 | } |
271 | } |
272 | |
273 | # if PRESOLVE_DEBUG |
274 | printf(")\n" ) ; |
275 | # endif |
276 | |
277 | // delete the whole column |
278 | hincol[icoly] = 0; |
279 | |
280 | return (false); |
281 | } |
282 | |
283 | |
284 | |
285 | |
286 | /* |
287 | * |
288 | * The col rep and row rep must be consistent. |
289 | */ |
290 | const CoinPresolveAction *tripleton_action::presolve(CoinPresolveMatrix *prob, |
291 | const CoinPresolveAction *next) |
292 | { |
293 | double startTime = 0.0; |
294 | int startEmptyRows=0; |
295 | int startEmptyColumns = 0; |
296 | if (prob->tuning_) { |
297 | startTime = CoinCpuTime(); |
298 | startEmptyRows = prob->countEmptyRows(); |
299 | startEmptyColumns = prob->countEmptyCols(); |
300 | } |
301 | double *colels = prob->colels_; |
302 | int *hrow = prob->hrow_; |
303 | CoinBigIndex *mcstrt = prob->mcstrt_; |
304 | int *hincol = prob->hincol_; |
305 | int ncols = prob->ncols_; |
306 | |
307 | double *clo = prob->clo_; |
308 | double *cup = prob->cup_; |
309 | |
310 | double *rowels = prob->rowels_; |
311 | int *hcol = prob->hcol_; |
312 | CoinBigIndex *mrstrt = prob->mrstrt_; |
313 | int *hinrow = prob->hinrow_; |
314 | int nrows = prob->nrows_; |
315 | |
316 | double *rlo = prob->rlo_; |
317 | double *rup = prob->rup_; |
318 | |
319 | presolvehlink *clink = prob->clink_; |
320 | presolvehlink *rlink = prob->rlink_; |
321 | |
322 | const unsigned char *integerType = prob->integerType_; |
323 | |
324 | double *cost = prob->cost_; |
325 | |
326 | int numberLook = prob->numberRowsToDo_; |
327 | int iLook; |
328 | int * look = prob->rowsToDo_; |
329 | const double ztolzb = prob->ztolzb_; |
330 | |
331 | action * actions = new action [nrows]; |
332 | # ifdef ZEROFAULT |
333 | // initialise alignment padding bytes |
334 | memset(actions,0,nrows*sizeof(action)) ; |
335 | # endif |
336 | int nactions = 0; |
337 | |
338 | int *zeros = prob->usefulColumnInt_; //new int[ncols]; |
339 | char * mark = reinterpret_cast<char *>(zeros+ncols); |
340 | memset(mark,0,ncols); |
341 | int nzeros = 0; |
342 | |
343 | // If rowstat exists then all do |
344 | unsigned char *rowstat = prob->rowstat_; |
345 | double *acts = prob->acts_; |
346 | // unsigned char * colstat = prob->colstat_; |
347 | |
348 | |
349 | # if PRESOLVE_CONSISTENCY |
350 | presolve_links_ok(prob) ; |
351 | # endif |
352 | |
353 | // wasfor (int irow=0; irow<nrows; irow++) |
354 | for (iLook=0;iLook<numberLook;iLook++) { |
355 | int irow = look[iLook]; |
356 | if (hinrow[irow] == 3 && |
357 | fabs(rup[irow] - rlo[irow]) <= ZTOLDP) { |
358 | double rhs = rlo[irow]; |
359 | CoinBigIndex krs = mrstrt[irow]; |
360 | CoinBigIndex kre = krs + hinrow[irow]; |
361 | int icolx, icoly, icolz; |
362 | double coeffx, coeffy, coeffz; |
363 | CoinBigIndex k; |
364 | |
365 | /* locate first column */ |
366 | for (k=krs; k<kre; k++) { |
367 | if (hincol[hcol[k]] > 0) { |
368 | break; |
369 | } |
370 | } |
371 | PRESOLVEASSERT(k<kre); |
372 | coeffx = rowels[k]; |
373 | if (fabs(coeffx) < ZTOLDP2) |
374 | continue; |
375 | icolx = hcol[k]; |
376 | |
377 | |
378 | /* locate second column */ |
379 | for (k++; k<kre; k++) { |
380 | if (hincol[hcol[k]] > 0) { |
381 | break; |
382 | } |
383 | } |
384 | PRESOLVEASSERT(k<kre); |
385 | coeffy = rowels[k]; |
386 | if (fabs(coeffy) < ZTOLDP2) |
387 | continue; |
388 | icoly = hcol[k]; |
389 | |
390 | /* locate third column */ |
391 | for (k++; k<kre; k++) { |
392 | if (hincol[hcol[k]] > 0) { |
393 | break; |
394 | } |
395 | } |
396 | PRESOLVEASSERT(k<kre); |
397 | coeffz = rowels[k]; |
398 | if (fabs(coeffz) < ZTOLDP2) |
399 | continue; |
400 | icolz = hcol[k]; |
401 | |
402 | // For now let's do obvious one |
403 | if (coeffx*coeffz>0.0) { |
404 | if(coeffx*coeffy>0.0) |
405 | continue; |
406 | } else if (coeffx*coeffy>0.0) { |
407 | int iTemp = icoly; |
408 | icoly=icolz; |
409 | icolz=iTemp; |
410 | double dTemp = coeffy; |
411 | coeffy=coeffz; |
412 | coeffz=dTemp; |
413 | } else { |
414 | int iTemp = icoly; |
415 | icoly=icolx; |
416 | icolx=iTemp; |
417 | double dTemp = coeffy; |
418 | coeffy=coeffx; |
419 | coeffx=dTemp; |
420 | } |
421 | // Not all same sign and y is odd one out |
422 | // don't bother with fixed variables |
423 | if (!(fabs(cup[icolx] - clo[icolx]) < ZTOLDP) && |
424 | !(fabs(cup[icoly] - clo[icolx]) < ZTOLDP) && |
425 | !(fabs(cup[icolz] - clo[icoly]) < ZTOLDP)) { |
426 | assert (coeffx*coeffz>0.0&&coeffx*coeffy<0.0); |
427 | // Only do if does not give implicit bounds on x and z |
428 | double cx = - coeffx/coeffy; |
429 | double cz = - coeffz/coeffy; |
430 | /* don't do if y integer for now */ |
431 | if (integerType[icoly]) { |
432 | #define PRESOLVE_DANGEROUS |
433 | #ifndef PRESOLVE_DANGEROUS |
434 | continue; |
435 | #else |
436 | if (!integerType[icolx]||!integerType[icolz]) |
437 | continue; |
438 | if (cx!=floor(cx+0.5)||cz!=floor(cz+0.5)) |
439 | continue; |
440 | #endif |
441 | } |
442 | double rhsRatio = rhs/coeffy; |
443 | if (clo[icoly]>-1.0e30) { |
444 | if (clo[icolx]<-1.0e30||clo[icolz]<-1.0e30) |
445 | continue; |
446 | if (cx*clo[icolx]+cz*clo[icolz]+rhsRatio<clo[icoly]-ztolzb) |
447 | continue; |
448 | } |
449 | if (cup[icoly]<1.0e30) { |
450 | if (cup[icolx]>1.0e30||cup[icolz]>1.0e30) |
451 | continue; |
452 | if (cx*cup[icolx]+cz*cup[icolz]+rhsRatio>cup[icoly]+ztolzb) |
453 | continue; |
454 | } |
455 | CoinBigIndex krowx,krowy,krowz; |
456 | /* find this row in each of the columns and do counts */ |
457 | bool singleton=false; |
458 | for (k=mcstrt[icoly]; k<mcstrt[icoly]+hincol[icoly]; k++) { |
459 | int jrow=hrow[k]; |
460 | if (hinrow[jrow]==1) |
461 | singleton=true; |
462 | if (jrow == irow) |
463 | krowy=k; |
464 | else |
465 | prob->setRowUsed(jrow); |
466 | } |
467 | int nDuplicate=0; |
468 | for (k=mcstrt[icolx]; k<mcstrt[icolx]+hincol[icolx]; k++) { |
469 | int jrow=hrow[k]; |
470 | if (jrow == irow) |
471 | krowx=k; |
472 | else if (prob->rowUsed(jrow)) |
473 | nDuplicate++; |
474 | } |
475 | for (k=mcstrt[icolz]; k<mcstrt[icolz]+hincol[icolz]; k++) { |
476 | int jrow=hrow[k]; |
477 | if (jrow == irow) |
478 | krowz=k; |
479 | else if (prob->rowUsed(jrow)) |
480 | nDuplicate++; |
481 | } |
482 | int nAdded=hincol[icoly]-3-nDuplicate; |
483 | for (k=mcstrt[icoly]; k<mcstrt[icoly]+hincol[icoly]; k++) { |
484 | int jrow=hrow[k]; |
485 | prob->unsetRowUsed(jrow); |
486 | } |
487 | // let singleton rows be taken care of first |
488 | if (singleton) |
489 | continue; |
490 | //if (nAdded<=1) |
491 | //printf("%d elements added, hincol %d , dups %d\n",nAdded,hincol[icoly],nDuplicate); |
492 | if (nAdded>2) |
493 | continue; |
494 | |
495 | // it is possible that both x/z and y are singleton columns |
496 | // that can cause problems |
497 | if ((hincol[icolx] == 1 ||hincol[icolz] == 1) && hincol[icoly] == 1) |
498 | continue; |
499 | |
500 | // common equations are of the form ax + by = 0, or x + y >= lo |
501 | { |
502 | action *s = &actions[nactions]; |
503 | nactions++; |
504 | PRESOLVE_DETAIL_PRINT(printf("pre_tripleton %dR %dC %dC %dC E\n" , |
505 | irow,icoly,icolx,icolz)); |
506 | |
507 | s->row = irow; |
508 | s->icolx = icolx; |
509 | s->icolz = icolz; |
510 | |
511 | s->icoly = icoly; |
512 | s->cloy = clo[icoly]; |
513 | s->cupy = cup[icoly]; |
514 | s->costy = cost[icoly]; |
515 | |
516 | s->rlo = rlo[irow]; |
517 | s->rup = rup[irow]; |
518 | |
519 | s->coeffx = coeffx; |
520 | s->coeffy = coeffy; |
521 | s->coeffz = coeffz; |
522 | |
523 | s->ncoly = hincol[icoly]; |
524 | s->colel = presolve_dupmajor(colels, hrow, hincol[icoly], |
525 | mcstrt[icoly]); |
526 | } |
527 | |
528 | // costs |
529 | // the effect of maxmin cancels out |
530 | cost[icolx] += cost[icoly] * cx; |
531 | cost[icolz] += cost[icoly] * cz; |
532 | |
533 | prob->change_bias(cost[icoly] * rhs / coeffy); |
534 | //if (cost[icoly]*rhs) |
535 | //printf("change %g col %d cost %g rhs %g coeff %g\n",cost[icoly]*rhs/coeffy, |
536 | // icoly,cost[icoly],rhs,coeffy); |
537 | |
538 | if (rowstat) { |
539 | // update solution and basis |
540 | int numberBasic=0; |
541 | if (prob->columnIsBasic(icoly)) |
542 | numberBasic++; |
543 | if (prob->rowIsBasic(irow)) |
544 | numberBasic++; |
545 | if (numberBasic>1) { |
546 | if (!prob->columnIsBasic(icolx)) |
547 | prob->setColumnStatus(icolx,CoinPrePostsolveMatrix::basic); |
548 | else |
549 | prob->setColumnStatus(icolz,CoinPrePostsolveMatrix::basic); |
550 | } |
551 | } |
552 | |
553 | // Update next set of actions |
554 | { |
555 | prob->addCol(icolx); |
556 | int i,kcs,kce; |
557 | kcs = mcstrt[icoly]; |
558 | kce = kcs + hincol[icoly]; |
559 | for (i=kcs;i<kce;i++) { |
560 | int row = hrow[i]; |
561 | prob->addRow(row); |
562 | } |
563 | kcs = mcstrt[icolx]; |
564 | kce = kcs + hincol[icolx]; |
565 | for (i=kcs;i<kce;i++) { |
566 | int row = hrow[i]; |
567 | prob->addRow(row); |
568 | } |
569 | prob->addCol(icolz); |
570 | kcs = mcstrt[icolz]; |
571 | kce = kcs + hincol[icolz]; |
572 | for (i=kcs;i<kce;i++) { |
573 | int row = hrow[i]; |
574 | prob->addRow(row); |
575 | } |
576 | } |
577 | |
578 | /* transfer the colx factors to coly */ |
579 | bool no_mem = elim_tripleton("ELIMT" , |
580 | mcstrt, rlo, acts, rup, colels, |
581 | hrow, hcol, hinrow, hincol, |
582 | clink, ncols, rlink, nrows, |
583 | mrstrt, rowels, |
584 | cx, |
585 | cz, |
586 | rhs / coeffy, |
587 | irow, icolx, icoly,icolz); |
588 | if (no_mem) |
589 | throwCoinError("out of memory" , |
590 | "tripleton_action::presolve" ); |
591 | |
592 | // now remove irow from icolx and icolz in the col rep |
593 | // better if this were first. |
594 | presolve_delete_from_col(irow,icolx,mcstrt,hincol,hrow,colels) ; |
595 | presolve_delete_from_col(irow,icolz,mcstrt,hincol,hrow,colels) ; |
596 | |
597 | // eliminate irow entirely from the row rep |
598 | hinrow[irow] = 0; |
599 | |
600 | // eliminate irow entirely from the row rep |
601 | PRESOLVE_REMOVE_LINK(rlink, irow); |
602 | |
603 | // eliminate coly entirely from the col rep |
604 | PRESOLVE_REMOVE_LINK(clink, icoly); |
605 | cost[icoly] = 0.0; |
606 | |
607 | rlo[irow] = 0.0; |
608 | rup[irow] = 0.0; |
609 | |
610 | if (!mark[icolx]) { |
611 | mark[icolx]=1; |
612 | zeros[nzeros++]=icolx; |
613 | } |
614 | if (!mark[icolz]) { |
615 | mark[icolz]=1; |
616 | zeros[nzeros++]=icolz; |
617 | } |
618 | } |
619 | |
620 | # if PRESOLVE_CONSISTENCY |
621 | presolve_links_ok(prob) ; |
622 | presolve_consistent(prob); |
623 | # endif |
624 | } |
625 | } |
626 | if (nactions) { |
627 | # if PRESOLVE_SUMMARY |
628 | printf("NTRIPLETONS: %d\n" , nactions); |
629 | # endif |
630 | action *actions1 = new action[nactions]; |
631 | CoinMemcpyN(actions, nactions, actions1); |
632 | |
633 | next = new tripleton_action(nactions, actions1, next); |
634 | |
635 | if (nzeros) { |
636 | next = drop_zero_coefficients_action::presolve(prob, zeros, nzeros, next); |
637 | } |
638 | } |
639 | |
640 | //delete[]zeros; |
641 | deleteAction(actions,action*); |
642 | |
643 | if (prob->tuning_) { |
644 | double thisTime=CoinCpuTime(); |
645 | int droppedRows = prob->countEmptyRows() - startEmptyRows ; |
646 | int droppedColumns = prob->countEmptyCols() - startEmptyColumns; |
647 | printf("CoinPresolveTripleton(8) - %d rows, %d columns dropped in time %g, total %g\n" , |
648 | droppedRows,droppedColumns,thisTime-startTime,thisTime-prob->startTime_); |
649 | } |
650 | return (next); |
651 | } |
652 | |
653 | |
654 | void tripleton_action::postsolve(CoinPostsolveMatrix *prob) const |
655 | { |
656 | const action *const actions = actions_; |
657 | const int nactions = nactions_; |
658 | |
659 | double *colels = prob->colels_; |
660 | int *hrow = prob->hrow_; |
661 | CoinBigIndex *mcstrt = prob->mcstrt_; |
662 | int *hincol = prob->hincol_; |
663 | int *link = prob->link_; |
664 | |
665 | double *clo = prob->clo_; |
666 | double *cup = prob->cup_; |
667 | |
668 | double *rlo = prob->rlo_; |
669 | double *rup = prob->rup_; |
670 | |
671 | double *dcost = prob->cost_; |
672 | |
673 | double *sol = prob->sol_; |
674 | double *rcosts = prob->rcosts_; |
675 | |
676 | double *acts = prob->acts_; |
677 | double *rowduals = prob->rowduals_; |
678 | |
679 | unsigned char *colstat = prob->colstat_; |
680 | unsigned char *rowstat = prob->rowstat_; |
681 | |
682 | const double maxmin = prob->maxmin_; |
683 | |
684 | # if PRESOLVE_DEBUG || PRESOLVE_CONSISTENCY |
685 | char *cdone = prob->cdone_; |
686 | char *rdone = prob->rdone_; |
687 | # endif |
688 | |
689 | CoinBigIndex &free_list = prob->free_list_; |
690 | |
691 | const double ztolzb = prob->ztolzb_; |
692 | const double ztoldj = prob->ztoldj_; |
693 | |
694 | // Space for accumulating two columns |
695 | int nrows = prob->nrows_; |
696 | int * index1 = new int[nrows]; |
697 | double * element1 = new double[nrows]; |
698 | memset(element1,0,nrows*sizeof(double)); |
699 | int * index2 = new int[nrows]; |
700 | double * element2 = new double[nrows]; |
701 | memset(element2,0,nrows*sizeof(double)); |
702 | |
703 | for (const action *f = &actions[nactions-1]; actions<=f; f--) { |
704 | int irow = f->row; |
705 | |
706 | // probably don't need this |
707 | double ylo0 = f->cloy; |
708 | double yup0 = f->cupy; |
709 | |
710 | double coeffx = f->coeffx; |
711 | double coeffy = f->coeffy; |
712 | double coeffz = f->coeffz; |
713 | int jcolx = f->icolx; |
714 | int jcoly = f->icoly; |
715 | int jcolz = f->icolz; |
716 | |
717 | // needed? |
718 | double rhs = f->rlo; |
719 | |
720 | /* the column was in the reduced problem */ |
721 | PRESOLVEASSERT(cdone[jcolx] && rdone[irow]==DROP_ROW&&cdone[jcolz]); |
722 | PRESOLVEASSERT(cdone[jcoly]==DROP_COL); |
723 | |
724 | // probably don't need this |
725 | rlo[irow] = f->rlo; |
726 | rup[irow] = f->rup; |
727 | |
728 | // probably don't need this |
729 | clo[jcoly] = ylo0; |
730 | cup[jcoly] = yup0; |
731 | |
732 | dcost[jcoly] = f->costy; |
733 | dcost[jcolx] += f->costy*coeffx/coeffy; |
734 | dcost[jcolz] += f->costy*coeffz/coeffy; |
735 | |
736 | // this is why we want coeffx < coeffy (55) |
737 | sol[jcoly] = (rhs - coeffx * sol[jcolx] - coeffz * sol[jcolz]) / coeffy; |
738 | |
739 | // since this row is fixed |
740 | acts[irow] = rhs; |
741 | |
742 | // acts[irow] always ok, since slack is fixed |
743 | if (rowstat) |
744 | prob->setRowStatus(irow,CoinPrePostsolveMatrix::atLowerBound); |
745 | |
746 | |
747 | // CLAIM: |
748 | // if the new pi value is chosen to keep the reduced cost |
749 | // of col x at its prior value, then the reduced cost of |
750 | // col y will be 0. |
751 | |
752 | // also have to update row activities and bounds for rows affected by jcoly |
753 | // |
754 | // sol[jcolx] was found for coeffx that |
755 | // was += colels[kcoly] * coeff_factor; |
756 | // where coeff_factor == -coeffx / coeffy |
757 | // |
758 | // its contribution to activity was |
759 | // (colels[kcolx] + colels[kcoly] * coeff_factor) * sol[jcolx] (1) |
760 | // |
761 | // After adjustment, the two columns contribute: |
762 | // colels[kcoly] * sol[jcoly] + colels[kcolx] * sol[jcolx] |
763 | // == colels[kcoly] * ((rhs - coeffx * sol[jcolx]) / coeffy) + colels[kcolx] * sol[jcolx] |
764 | // == colels[kcoly] * rhs/coeffy + colels[kcoly] * coeff_factor * sol[jcolx] + colels[kcolx] * sol[jcolx] |
765 | // colels[kcoly] * rhs/coeffy + the expression (1) |
766 | // |
767 | // therefore, we must increase the row bounds by colels[kcoly] * rhs/coeffy, |
768 | // which is similar to the bias |
769 | double djy = maxmin * dcost[jcoly]; |
770 | double djx = maxmin * dcost[jcolx]; |
771 | double djz = maxmin * dcost[jcolz]; |
772 | double bounds_factor = rhs/coeffy; |
773 | // need to reconstruct x and z |
774 | double multiplier1 = coeffx/coeffy; |
775 | double multiplier2 = coeffz/coeffy; |
776 | int * indy = reinterpret_cast<int *>(f->colel+f->ncoly); |
777 | int ystart = NO_LINK; |
778 | int nX=0,nZ=0; |
779 | int i,iRow; |
780 | for (i=0; i<f->ncoly; ++i) { |
781 | int iRow = indy[i]; |
782 | double yValue = f->colel[i]; |
783 | CoinBigIndex k = free_list; |
784 | assert(k >= 0 && k < prob->bulk0_) ; |
785 | free_list = link[free_list]; |
786 | if (iRow != irow) { |
787 | // are these tests always true??? |
788 | |
789 | // undo elim_tripleton(1) |
790 | if (-PRESOLVE_INF < rlo[iRow]) |
791 | rlo[iRow] += yValue * bounds_factor; |
792 | |
793 | // undo elim_tripleton(2) |
794 | if (rup[iRow] < PRESOLVE_INF) |
795 | rup[iRow] += yValue * bounds_factor; |
796 | |
797 | acts[iRow] += yValue * bounds_factor; |
798 | |
799 | djy -= rowduals[iRow] * yValue; |
800 | } |
801 | |
802 | hrow[k] = iRow; |
803 | PRESOLVEASSERT(rdone[hrow[k]] || hrow[k] == irow); |
804 | colels[k] = yValue; |
805 | link[k] = ystart; |
806 | ystart = k; |
807 | element1[iRow]=yValue*multiplier1; |
808 | index1[nX++]=iRow; |
809 | element2[iRow]=yValue*multiplier2; |
810 | index2[nZ++]=iRow; |
811 | } |
812 | # if PRESOLVE_CONSISTENCY |
813 | presolve_check_free_list(prob) ; |
814 | # endif |
815 | mcstrt[jcoly] = ystart; |
816 | hincol[jcoly] = f->ncoly; |
817 | // find the tail |
818 | CoinBigIndex k=mcstrt[jcolx]; |
819 | CoinBigIndex last = NO_LINK; |
820 | int numberInColumn = hincol[jcolx]; |
821 | int numberToDo=numberInColumn; |
822 | for (i=0; i<numberToDo; ++i) { |
823 | iRow = hrow[k]; |
824 | assert (iRow>=0&&iRow<nrows); |
825 | double value = colels[k]+element1[iRow]; |
826 | element1[iRow]=0.0; |
827 | if (fabs(value)>=1.0e-15) { |
828 | colels[k]=value; |
829 | last=k; |
830 | k = link[k]; |
831 | if (iRow != irow) |
832 | djx -= rowduals[iRow] * value; |
833 | } else { |
834 | numberInColumn--; |
835 | // add to free list |
836 | int nextk = link[k]; |
837 | link[k]=free_list; |
838 | free_list=k; |
839 | assert (k>=0); |
840 | k=nextk; |
841 | if (last!=NO_LINK) |
842 | link[last]=k; |
843 | else |
844 | mcstrt[jcolx]=k; |
845 | } |
846 | } |
847 | for (i=0;i<nX;i++) { |
848 | int iRow = index1[i]; |
849 | double xValue = element1[iRow]; |
850 | element1[iRow]=0.0; |
851 | if (fabs(xValue)>=1.0e-15) { |
852 | if (iRow != irow) |
853 | djx -= rowduals[iRow] * xValue; |
854 | numberInColumn++; |
855 | CoinBigIndex k = free_list; |
856 | assert(k >= 0 && k < prob->bulk0_) ; |
857 | free_list = link[free_list]; |
858 | hrow[k] = iRow; |
859 | PRESOLVEASSERT(rdone[hrow[k]] || hrow[k] == irow); |
860 | colels[k] = xValue; |
861 | if (last!=NO_LINK) |
862 | link[last]=k; |
863 | else |
864 | mcstrt[jcolx]=k; |
865 | last = k; |
866 | } |
867 | } |
868 | # if PRESOLVE_CONSISTENCY |
869 | presolve_check_free_list(prob) ; |
870 | # endif |
871 | link[last]=NO_LINK; |
872 | assert(numberInColumn); |
873 | hincol[jcolx] = numberInColumn; |
874 | // find the tail |
875 | k=mcstrt[jcolz]; |
876 | last = NO_LINK; |
877 | numberInColumn = hincol[jcolz]; |
878 | numberToDo=numberInColumn; |
879 | for (i=0; i<numberToDo; ++i) { |
880 | iRow = hrow[k]; |
881 | assert (iRow>=0&&iRow<nrows); |
882 | double value = colels[k]+element2[iRow]; |
883 | element2[iRow]=0.0; |
884 | if (fabs(value)>=1.0e-15) { |
885 | colels[k]=value; |
886 | last=k; |
887 | k = link[k]; |
888 | if (iRow != irow) |
889 | djz -= rowduals[iRow] * value; |
890 | } else { |
891 | numberInColumn--; |
892 | // add to free list |
893 | int nextk = link[k]; |
894 | assert(free_list>=0); |
895 | link[k]=free_list; |
896 | free_list=k; |
897 | assert (k>=0); |
898 | k=nextk; |
899 | if (last!=NO_LINK) |
900 | link[last]=k; |
901 | else |
902 | mcstrt[jcolz]=k; |
903 | } |
904 | } |
905 | for (i=0;i<nZ;i++) { |
906 | int iRow = index2[i]; |
907 | double zValue = element2[iRow]; |
908 | element2[iRow]=0.0; |
909 | if (fabs(zValue)>=1.0e-15) { |
910 | if (iRow != irow) |
911 | djz -= rowduals[iRow] * zValue; |
912 | numberInColumn++; |
913 | CoinBigIndex k = free_list; |
914 | assert(k >= 0 && k < prob->bulk0_) ; |
915 | free_list = link[free_list]; |
916 | hrow[k] = iRow; |
917 | PRESOLVEASSERT(rdone[hrow[k]] || hrow[k] == irow); |
918 | colels[k] = zValue; |
919 | if (last!=NO_LINK) |
920 | link[last]=k; |
921 | else |
922 | mcstrt[jcolz]=k; |
923 | last = k; |
924 | } |
925 | } |
926 | # if PRESOLVE_CONSISTENCY |
927 | presolve_check_free_list(prob) ; |
928 | # endif |
929 | link[last]=NO_LINK; |
930 | assert(numberInColumn); |
931 | hincol[jcolz] = numberInColumn; |
932 | |
933 | |
934 | |
935 | // The only problem with keeping the reduced costs the way they were |
936 | // was that the variable's bound may have moved, requiring it |
937 | // to become basic. |
938 | //printf("djs x - %g (%g), y - %g (%g)\n",djx,coeffx,djy,coeffy); |
939 | if (colstat) { |
940 | if (prob->columnIsBasic(jcolx) || |
941 | (fabs(clo[jcolx] - sol[jcolx]) < ztolzb && rcosts[jcolx] >= -ztoldj) || |
942 | (fabs(cup[jcolx] - sol[jcolx]) < ztolzb && rcosts[jcolx] <= ztoldj) || |
943 | (prob->getColumnStatus(jcolx) ==CoinPrePostsolveMatrix::isFree&& |
944 | fabs(rcosts[jcolx]) <= ztoldj)) { |
945 | // colx or y is fine as it is - make coly basic |
946 | |
947 | prob->setColumnStatus(jcoly,CoinPrePostsolveMatrix::basic); |
948 | // this is the coefficient we need to force col y's reduced cost to 0.0; |
949 | // for example, this is obviously true if y is a singleton column |
950 | rowduals[irow] = djy / coeffy; |
951 | rcosts[jcolx] = djx - rowduals[irow] * coeffx; |
952 | # if PRESOLVE_DEBUG |
953 | if (prob->columnIsBasic(jcolx)&&fabs(rcosts[jcolx])>1.0e-5) |
954 | printf("bad dj %d %g\n" ,jcolx,rcosts[jcolx]); |
955 | # endif |
956 | rcosts[jcolz] = djz - rowduals[irow] * coeffz; |
957 | //if (prob->columnIsBasic(jcolz)) |
958 | //assert (fabs(rcosts[jcolz])<1.0e-5); |
959 | rcosts[jcoly] = 0.0; |
960 | } else { |
961 | prob->setColumnStatus(jcolx,CoinPrePostsolveMatrix::basic); |
962 | prob->setColumnStatusUsingValue(jcoly); |
963 | |
964 | // change rowduals[jcolx] enough to cancel out rcosts[jcolx] |
965 | rowduals[irow] = djx / coeffx; |
966 | rcosts[jcolx] = 0.0; |
967 | // change rowduals[jcolx] enough to cancel out rcosts[jcolx] |
968 | //rowduals[irow] = djz / coeffz; |
969 | //rcosts[jcolz] = 0.0; |
970 | rcosts[jcolz] = djz - rowduals[irow] * coeffz; |
971 | rcosts[jcoly] = djy - rowduals[irow] * coeffy; |
972 | } |
973 | } else { |
974 | // No status array |
975 | // this is the coefficient we need to force col y's reduced cost to 0.0; |
976 | // for example, this is obviously true if y is a singleton column |
977 | rowduals[irow] = djy / coeffy; |
978 | rcosts[jcoly] = 0.0; |
979 | } |
980 | |
981 | // DEBUG CHECK |
982 | # if PRESOLVE_DEBUG |
983 | { |
984 | CoinBigIndex k = mcstrt[jcolx]; |
985 | int nx = hincol[jcolx]; |
986 | double dj = maxmin * dcost[jcolx]; |
987 | |
988 | for (int i=0; i<nx; ++i) { |
989 | int row = hrow[k]; |
990 | double coeff = colels[k]; |
991 | k = link[k]; |
992 | |
993 | dj -= rowduals[row] * coeff; |
994 | } |
995 | if (! (fabs(rcosts[jcolx] - dj) < 100*ZTOLDP)) |
996 | printf("BAD DOUBLE X DJ: %d %d %g %g\n" , |
997 | irow, jcolx, rcosts[jcolx], dj); |
998 | rcosts[jcolx]=dj; |
999 | } |
1000 | { |
1001 | CoinBigIndex k = mcstrt[jcoly]; |
1002 | int ny = hincol[jcoly]; |
1003 | double dj = maxmin * dcost[jcoly]; |
1004 | |
1005 | for (int i=0; i<ny; ++i) { |
1006 | int row = hrow[k]; |
1007 | double coeff = colels[k]; |
1008 | k = link[k]; |
1009 | |
1010 | dj -= rowduals[row] * coeff; |
1011 | //printf("b %d coeff %g dual %g dj %g\n", |
1012 | // row,coeff,rowduals[row],dj); |
1013 | } |
1014 | if (! (fabs(rcosts[jcoly] - dj) < 100*ZTOLDP)) |
1015 | printf("BAD DOUBLE Y DJ: %d %d %g %g\n" , |
1016 | irow, jcoly, rcosts[jcoly], dj); |
1017 | rcosts[jcoly]=dj; |
1018 | //exit(0); |
1019 | } |
1020 | # endif |
1021 | |
1022 | # if PRESOLVE_DEBUG || PRESOLVE_CONSISTENCY |
1023 | cdone[jcoly] = TRIPLETON; |
1024 | rdone[irow] = TRIPLETON; |
1025 | # endif |
1026 | } |
1027 | delete [] index1; |
1028 | delete [] element1; |
1029 | delete [] index2; |
1030 | delete [] element2; |
1031 | |
1032 | # if PRESOLVE_CONSISTENCY |
1033 | presolve_check_threads(prob) ; |
1034 | # endif |
1035 | |
1036 | } |
1037 | |
1038 | |
1039 | tripleton_action::~tripleton_action() |
1040 | { |
1041 | for (int i=nactions_-1; i>=0; i--) { |
1042 | delete[]actions_[i].colel; |
1043 | } |
1044 | deleteAction(actions_,action*); |
1045 | } |
1046 | |
1047 | |
1048 | |
1049 | static double *tripleton_mult; |
1050 | static int *tripleton_id; |
1051 | void check_tripletons(const CoinPresolveAction * paction) |
1052 | { |
1053 | const CoinPresolveAction * paction0 = paction; |
1054 | |
1055 | if (paction) { |
1056 | check_tripletons(paction->next); |
1057 | |
1058 | if (strcmp(paction0->name(), "tripleton_action" ) == 0) { |
1059 | const tripleton_action *daction = reinterpret_cast<const tripleton_action *>(paction0); |
1060 | for (int i=daction->nactions_-1; i>=0; --i) { |
1061 | int icolx = daction->actions_[i].icolx; |
1062 | int icoly = daction->actions_[i].icoly; |
1063 | double coeffx = daction->actions_[i].coeffx; |
1064 | double coeffy = daction->actions_[i].coeffy; |
1065 | |
1066 | tripleton_mult[icoly] = -coeffx/coeffy; |
1067 | tripleton_id[icoly] = icolx; |
1068 | } |
1069 | } |
1070 | } |
1071 | } |
1072 | |