Scippy

SoPlex

Sequential object-oriented simPlex

spxmainsm.cpp
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the class library */
4 /* SoPlex --- the Sequential object-oriented simPlex. */
5 /* */
6 /* Copyright (C) 1996-2019 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SoPlex is distributed under the terms of the ZIB Academic Licence. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SoPlex; see the file COPYING. If not email to soplex@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 #include <iostream>
17 
18 #include "soplex/spxmainsm.h"
19 #include "soplex/array.h"
20 #include "soplex/dataarray.h"
21 #include "soplex/sorter.h"
22 #include "soplex/spxout.h"
23 #include <sstream>
24 #include <iostream>
25 #include <fstream>
26 
27 
28 //rows
29 #define FREE_LHS_RHS 1
30 #define FREE_CONSTRAINT 1
31 #define EMPTY_CONSTRAINT 1
32 #define ROW_SINGLETON 1
33 #define AGGREGATE_VARS 1
34 #define FORCE_CONSTRAINT 1
35 //cols
36 #define FREE_BOUNDS 1
37 #define EMPTY_COLUMN 1
38 #define FIX_VARIABLE 1
39 #define FREE_ZERO_OBJ_VARIABLE 1
40 #define ZERO_OBJ_COL_SINGLETON 1
41 #define DOUBLETON_EQUATION 1
42 #define FREE_COL_SINGLETON 1
43 //dual
44 #define DOMINATED_COLUMN 1
45 #define WEAKLY_DOMINATED_COLUMN 1
46 #define MULTI_AGGREGATE 1
47 //other
48 #define TRIVIAL_HEURISTICS 1
49 #define PSEUDOOBJ 1
50 
51 
52 #define EXTREMES 1
53 #define ROWS 1
54 #define COLS 1
55 #define DUAL 1
56 ///@todo check: with this simplification step, the unsimplified basis seems to be slightly suboptimal for some instances
57 #define DUPLICATE_ROWS 1
58 #define DUPLICATE_COLS 1
59 
60 
61 #ifndef NDEBUG
62 #define CHECK_BASIC_DIM
63 #endif // NDEBUG
64 
65 namespace soplex
66 {
69 {
70  int numBasis = 0;
71 
72  for(int rs = 0; rs < nRows; ++rs)
73  {
74  if(rows[rs] == SPxSolver::BASIC)
75  numBasis++;
76  }
77 
78  for(int cs = 0; cs < nCols; ++cs)
79  {
80  if(cols[cs] == SPxSolver::BASIC)
81  numBasis++;
82  }
83 
84  assert(numBasis == nRows);
85  return numBasis == nRows;
86 }
87 
90  DataArray<SPxSolver::VarStatus>& rStatus, bool isOptimal) const
91 {
92  assert(isZero(s[m_i], 1e-9));
93  s[m_i] = -x[m_j];
94 
95  assert(rStatus[m_i] != SPxSolver::UNDEFINED);
96  assert(cStatus[m_j] != SPxSolver::UNDEFINED);
97  assert(rStatus[m_i] != SPxSolver::BASIC || cStatus[m_j] != SPxSolver::BASIC);
98 
99  MSG_DEBUG(std::cout << "RowObjPS: removing slack column " << m_j << " (" << cStatus[m_j] <<
100  ") for row " << m_i << " (" << rStatus[m_i] << ").\n");
101 
102  if(rStatus[m_i] != SPxSolver::BASIC)
103  {
104  switch(cStatus[m_j])
105  {
106  case SPxSolver::ON_UPPER:
107  rStatus[m_i] = SPxSolver::ON_LOWER;
108  break;
109 
110  case SPxSolver::ON_LOWER:
111  rStatus[m_i] = SPxSolver::ON_UPPER;
112  break;
113 
114  default:
115  rStatus[m_i] = cStatus[m_j];
116  }
117 
118  // otherwise checkBasisDim() may fail
119  cStatus[m_j] = SPxSolver::ZERO;
120  }
121 
122 #ifdef CHECK_BASIC_DIM
123 
124  if(!checkBasisDim(rStatus, cStatus))
125  {
126  assert(false);
127  throw SPxInternalCodeException("XMAISM15 Dimension doesn't match after this step.");
128  }
129 
130 #endif
131 }
132 
135  DataArray<SPxSolver::VarStatus>& rStatus, bool isOptimal) const
136 {
137  // correcting the change of idx by deletion of the row:
138  s[m_old_i] = s[m_i];
139  y[m_old_i] = y[m_i];
140  rStatus[m_old_i] = rStatus[m_i];
141 
142  // primal:
143  Real slack = 0.0;
144 
145  for(int k = 0; k < m_row.size(); ++k)
146  slack += m_row.value(k) * x[m_row.index(k)];
147 
148  s[m_i] = slack;
149 
150  // dual:
151  y[m_i] = m_row_obj;
152 
153  // basis:
154  rStatus[m_i] = SPxSolver::BASIC;
155 
156 #ifdef CHECK_BASIC_DIM
157 
158  if(!checkBasisDim(rStatus, cStatus))
159  {
160  throw SPxInternalCodeException("XMAISM15 Dimension doesn't match after this step.");
161  }
162 
163 #endif
164 }
165 
168  DataArray<SPxSolver::VarStatus>& rStatus, bool isOptimal) const
169 {
170  // correcting the change of idx by deletion of the row:
171  s[m_old_i] = s[m_i];
172  y[m_old_i] = y[m_i];
173  rStatus[m_old_i] = rStatus[m_i];
174 
175  // primal:
176  s[m_i] = 0.0;
177 
178  // dual:
179  y[m_i] = m_row_obj;
180 
181  // basis:
182  rStatus[m_i] = SPxSolver::BASIC;
183 
184 #ifdef CHECK_BASIC_DIM
185 
186  if(!checkBasisDim(rStatus, cStatus))
187  {
188  throw SPxInternalCodeException("XMAISM16 Dimension doesn't match after this step.");
189  }
190 
191 #endif
192 }
193 
196  DataArray<SPxSolver::VarStatus>& rStatus, bool isOptimal) const
197 {
198  // correcting the change of idx by deletion of the row:
199  s[m_old_i] = s[m_i];
200  y[m_old_i] = y[m_i];
201  rStatus[m_old_i] = rStatus[m_i];
202 
203  Real aij = m_col[m_i];
204 
205  // primal:
206  s[m_i] = aij * x[m_j];
207 
208  // dual & basis:
209  Real val = m_obj;
210 
211  for(int k = 0; k < m_col.size(); ++k)
212  {
213  if(m_col.index(k) != m_i)
214  val -= m_col.value(k) * y[m_col.index(k)];
215  }
216 
217  Real newLo = (aij > 0) ? m_lhs / aij : m_rhs / aij; // implicit lhs
218  Real newUp = (aij > 0) ? m_rhs / aij : m_lhs / aij; // implicit rhs
219 
220  switch(cStatus[m_j])
221  {
222  case SPxSolver::FIXED:
223  if(newLo <= m_oldLo && newUp >= m_oldUp)
224  {
225  // this row is totally redundant, has not changed bound of xj
226  rStatus[m_i] = SPxSolver::BASIC;
227  y[m_i] = m_row_obj;
228  }
229  else if(EQrel(newLo, newUp, eps()))
230  {
231  // row is in the type aij * xj = b
232  assert(EQrel(newLo, x[m_j], eps()));
233 
234  if(EQrel(m_oldLo, m_oldUp, eps()))
235  {
236  // xj has been fixed in other row
237  rStatus[m_i] = SPxSolver::BASIC;
238  y[m_i] = m_row_obj;
239  }
240  else if((EQrel(m_oldLo, x[m_j], eps()) && r[m_j] <= -eps())
241  || (EQrel(m_oldUp, x[m_j], eps()) && r[m_j] >= eps())
242  || (!EQrel(m_oldLo, x[m_j], eps()) && !(EQrel(m_oldUp, x[m_j], eps()))))
243  {
244  // if x_j on lower but reduced cost is negative, or x_j on upper but reduced cost is positive, or x_j not on bound: basic
245  rStatus[m_i] = (EQrel(m_lhs, x[m_j] * aij, eps())) ? SPxSolver::ON_LOWER : SPxSolver::ON_UPPER;
246  cStatus[m_j] = SPxSolver::BASIC;
247  y[m_i] = val / aij;
248  r[m_j] = 0.0;
249  }
250  else
251  {
252  // set x_j on one of the bound
253  assert(EQrel(m_oldLo, x[m_j], eps()) || EQrel(m_oldUp, x[m_j], eps()));
254 
255  cStatus[m_j] = EQrel(m_oldLo, x[m_j], eps()) ? SPxSolver::ON_LOWER : SPxSolver::ON_UPPER;
256  rStatus[m_i] = SPxSolver::BASIC;
257  y[m_i] = m_row_obj;
258  r[m_j] = val;
259  }
260  }
261  else if(EQrel(newLo, m_oldUp, eps()))
262  {
263  // row is in the type xj >= b/aij, try to set xj on upper
264  if(r[m_j] >= eps())
265  {
266  // the reduced cost is positive, xj should in the basic
267  assert(EQrel(m_rhs, x[m_j]*aij, eps()) || EQrel(m_lhs, x[m_j]*aij, eps()));
268 
269  rStatus[m_i] = (EQrel(m_lhs, x[m_j] * aij, eps())) ? SPxSolver::ON_LOWER : SPxSolver::ON_UPPER;
270  cStatus[m_j] = SPxSolver::BASIC;
271  y[m_i] = val / aij;
272  r[m_j] = 0.0;
273  }
274  else
275  {
276  assert(EQrel(m_oldUp, x[m_j], eps()));
277 
278  cStatus[m_j] = SPxSolver::ON_UPPER;
279  rStatus[m_i] = SPxSolver::BASIC;
280  y[m_i] = m_row_obj;
281  r[m_j] = val;
282  }
283  }
284  else if(EQrel(newUp, m_oldLo, eps()))
285  {
286  // row is in the type xj <= b/aij, try to set xj on lower
287  if(r[m_j] <= -eps())
288  {
289  // the reduced cost is negative, xj should in the basic
290  assert(EQrel(m_rhs, x[m_j]*aij, eps()) || EQrel(m_lhs, x[m_j]*aij, eps()));
291 
292  rStatus[m_i] = (EQrel(m_lhs, x[m_j] * aij, eps())) ? SPxSolver::ON_LOWER : SPxSolver::ON_UPPER;
293  cStatus[m_j] = SPxSolver::BASIC;
294  y[m_i] = val / aij;
295  r[m_j] = 0.0;
296  }
297  else
298  {
299  assert(EQrel(m_oldLo, x[m_j], eps()));
300 
301  cStatus[m_j] = SPxSolver::ON_LOWER;
302  rStatus[m_i] = SPxSolver::BASIC;
303  y[m_i] = m_row_obj;
304  r[m_j] = val;
305  }
306  }
307  else
308  {
309  // the variable is set to FIXED by other constraints, i.e., this singleton row is redundant
310  rStatus[m_i] = SPxSolver::BASIC;
311  y[m_i] = m_row_obj;
312  }
313 
314  break;
315 
316  case SPxSolver::BASIC:
317  rStatus[m_i] = SPxSolver::BASIC;
318  y[m_i] = m_row_obj;
319  r[m_j] = 0.0;
320  break;
321 
322  case SPxSolver::ON_LOWER:
323  if(EQrel(m_oldLo, x[m_j], eps())) // xj may stay on lower
324  {
325  rStatus[m_i] = SPxSolver::BASIC;
326  y[m_i] = m_row_obj;
327  r[m_j] = val;
328  }
329  else // if reduced costs are negative or old lower bound not equal to xj, we need to change xj into the basis
330  {
331  assert(EQrel(m_rhs, x[m_j]*aij, eps()) || EQrel(m_lhs, x[m_j]*aij, eps()));
332 
333  cStatus[m_j] = SPxSolver::BASIC;
334  rStatus[m_i] = (EQrel(m_lhs, x[m_j] * aij, eps())) ? SPxSolver::ON_LOWER : SPxSolver::ON_UPPER;
335  y[m_i] = val / aij;
336  r[m_j] = 0.0;
337  }
338 
339  break;
340 
341  case SPxSolver::ON_UPPER:
342  if(EQrel(m_oldUp, x[m_j], eps())) // xj may stay on upper
343  {
344  rStatus[m_i] = SPxSolver::BASIC;
345  y[m_i] = m_row_obj;
346  r[m_j] = val;
347  }
348  else // if reduced costs are positive or old upper bound not equal to xj, we need to change xj into the basis
349  {
350  assert(EQrel(m_rhs, x[m_j]*aij, eps()) || EQrel(m_lhs, x[m_j]*aij, eps()));
351 
352  cStatus[m_j] = SPxSolver::BASIC;
353  rStatus[m_i] = (EQrel(m_lhs, x[m_j] * aij, eps())) ? SPxSolver::ON_LOWER : SPxSolver::ON_UPPER;
354  y[m_i] = val / aij;
355  r[m_j] = 0.0;
356  }
357 
358  break;
359 
360  case SPxSolver::ZERO:
361  rStatus[m_i] = SPxSolver::BASIC;
362  y[m_i] = m_row_obj;
363  r[m_j] = val;
364  break;
365 
366  default:
367  break;
368  }
369 
370 #ifdef CHECK_BASIC_DIM
371 
372  if(!checkBasisDim(rStatus, cStatus))
373  {
374  throw SPxInternalCodeException("XMAISM17 Dimension doesn't match after this step.");
375  }
376 
377 #endif
378 }
379 
382  DataArray<SPxSolver::VarStatus>& rStatus, bool isOptimal) const
383 {
384  // correcting the change of idx by deletion of the row:
385  s[m_old_i] = s[m_i];
386  y[m_old_i] = y[m_i];
387  rStatus[m_old_i] = rStatus[m_i];
388 
389  // primal:
390  s[m_i] = m_lRhs;
391 
392  // basis:
393  int cBasisCandidate = -1;
394  Real maxViolation = -1.0;
395  int bas_k = -1;
396 
397  for(int k = 0; k < m_row.size(); ++k)
398  {
399  int cIdx = m_row.index(k);
400  Real aij = m_row.value(k);
401  Real oldLo = m_oldLowers[k];
402  Real oldUp = m_oldUppers[k];
403 
404  switch(cStatus[cIdx])
405  {
406  case SPxSolver::FIXED:
407  if(m_fixed[k])
408  {
409  assert(EQrel(oldLo, x[cIdx], eps()) || EQrel(oldUp, x[cIdx], eps()));
410 
411  Real violation = spxAbs(r[cIdx] / aij);
412 
413  cStatus[cIdx] = EQrel(oldLo, x[cIdx], eps()) ? SPxSolver::ON_LOWER : SPxSolver::ON_UPPER;
414 
415  if(violation > maxViolation && ((EQrel(oldLo, x[cIdx], eps()) && r[cIdx] < -eps())
416  || (EQrel(oldUp, x[cIdx], eps()) && r[cIdx] > eps())))
417  {
418  maxViolation = violation;
419  cBasisCandidate = cIdx;
420  bas_k = k;
421  }
422  } // do nothing, if the old bounds are equal, i.e. variable has been not fixed in this row
423 
424  break;
425 
426  case SPxSolver::ON_LOWER:
427  case SPxSolver::ON_UPPER:
428  case SPxSolver::BASIC:
429  break;
430 
431  default:
432  break;
433  }
434  }
435 
436  // dual and basis :
437  if(cBasisCandidate >= 0) // one of the variable in the row should in the basis
438  {
439  assert(EQrel(m_lRhs, m_rhs, eps()) || EQrel(m_lRhs, m_lhs, eps()));
440  assert(bas_k >= 0);
441  assert(cBasisCandidate == m_row.index(bas_k));
442 
443  cStatus[cBasisCandidate] = SPxSolver::BASIC;
444  rStatus[m_i] = (EQrel(m_lRhs, m_lhs, eps())) ? SPxSolver::ON_LOWER : SPxSolver::ON_UPPER;
445 
446  Real aij = m_row.value(bas_k);
447  Real multiplier = r[cBasisCandidate] / aij;
448  r[cBasisCandidate] = 0.0;
449 
450  for(int k = 0; k < m_row.size(); ++k) // update the reduced cost
451  {
452  if(k == bas_k)
453  {
454  continue;
455  }
456 
457  r[m_row.index(k)] -= m_row.value(k) * multiplier;
458  }
459 
460  // compute the value of new dual variable (because we have a new row)
461  Real val = m_objs[bas_k];
462  DSVector basis_col = m_cols[bas_k];
463 
464  for(int k = 0; k < basis_col.size(); ++k)
465  {
466  if(basis_col.index(k) != m_i)
467  val -= basis_col.value(k) * y[basis_col.index(k)];
468  }
469 
470  y[m_i] = val / aij;
471  }
472  else // slack in the basis
473  {
474  rStatus[m_i] = SPxSolver::BASIC;
475  y[m_i] = m_rowobj;
476  }
477 
478 #ifdef CHECK_BASIC_DIM
479 
480  if(!checkBasisDim(rStatus, cStatus))
481  {
482  throw SPxInternalCodeException("XMAISM18 Dimension doesn't match after this step.");
483  }
484 
485 #endif
486 }
487 
490  DataArray<SPxSolver::VarStatus>& rStatus, bool isOptimal) const
491 {
492  // update the index mapping; if m_correctIdx is false, we assume that this has happened already
493  if(m_correctIdx)
494  {
495  x[m_old_j] = x[m_j];
496  r[m_old_j] = r[m_j];
497  cStatus[m_old_j] = cStatus[m_j];
498  }
499 
500  // primal:
501  x[m_j] = m_val;
502 
503  for(int k = 0; k < m_col.size(); ++k)
504  s[m_col.index(k)] += m_col.value(k) * x[m_j];
505 
506  // dual:
507  Real val = m_obj;
508 
509  for(int k = 0; k < m_col.size(); ++k)
510  val -= m_col.value(k) * y[m_col.index(k)];
511 
512  r[m_j] = val;
513 
514  // basis:
515  if(m_lower == m_upper)
516  {
517  assert(EQrel(m_lower, m_val));
518 
519  cStatus[m_j] = SPxSolver::FIXED;
520  }
521  else
522  {
523  assert(EQrel(m_val, m_lower) || EQrel(m_val, m_upper) || m_val == 0.0);
524 
525  cStatus[m_j] = EQrel(m_val, m_lower) ? SPxSolver::ON_LOWER : (EQrel(m_val,
526  m_upper) ? SPxSolver::ON_UPPER : SPxSolver::ZERO);
527  }
528 
529 #ifdef CHECK_BASIC_DIM
530 
531  if(m_correctIdx)
532  {
533  if(!checkBasisDim(rStatus, cStatus))
534  {
535  throw SPxInternalCodeException("XMAISM19 Dimension doesn't match after this step.");
536  }
537  }
538 
539 #endif
540 }
541 
544  DataArray<SPxSolver::VarStatus>&, bool isOptimal) const
545 {
546  // basis:
547  cStatus[m_j] = m_status;
548 }
549 
552  DataArray<SPxSolver::VarStatus>& rStatus, bool isOptimal) const
553 {
554  // correcting the change of idx by deletion of the column and corresponding rows:
555  x[m_old_j] = x[m_j];
556  r[m_old_j] = r[m_j];
557  cStatus[m_old_j] = cStatus[m_j];
558 
559  int rIdx = m_old_i - m_col.size() + 1;
560 
561  for(int k = 0; k < m_col.size(); ++k)
562  {
563  int rIdx_new = m_col.index(k);
564  s[rIdx] = s[rIdx_new];
565  y[rIdx] = y[rIdx_new];
566  rStatus[rIdx] = rStatus[rIdx_new];
567  rIdx++;
568  }
569 
570  // primal:
571  int domIdx = -1;
572  DSVector slack(m_col.size());
573 
574  if(m_loFree)
575  {
576  Real minRowUp = infinity;
577 
578  for(int k = 0; k < m_rows.size(); ++k)
579  {
580  Real val = 0.0;
581  const SVector& row = m_rows[k];
582 
583  for(int l = 0; l < row.size(); ++l)
584  {
585  if(row.index(l) != m_j)
586  val += row.value(l) * x[row.index(l)];
587  }
588 
589  Real scale = maxAbs(m_lRhs[k], val);
590 
591  if(scale < 1.0)
592  scale = 1.0;
593 
594  Real z = (m_lRhs[k] / scale) - (val / scale);
595 
596  if(isZero(z))
597  z = 0.0;
598 
599  Real up = z * scale / row[m_j];
600  slack.add(k, val);
601 
602  if(up < minRowUp)
603  {
604  minRowUp = up;
605  domIdx = k;
606  }
607  }
608 
609  if(m_bnd < minRowUp)
610  {
611  x[m_j] = m_bnd;
612  domIdx = -1;
613  }
614  else
615  x[m_j] = minRowUp;
616  }
617  else
618  {
619  Real maxRowLo = -infinity;
620 
621  for(int k = 0; k < m_rows.size(); ++k)
622  {
623  Real val = 0.0;
624  const SVector& row = m_rows[k];
625 
626  for(int l = 0; l < row.size(); ++l)
627  {
628  if(row.index(l) != m_j)
629  val += row.value(l) * x[row.index(l)];
630  }
631 
632  Real scale = maxAbs(m_lRhs[k], val);
633 
634  if(scale < 1.0)
635  scale = 1.0;
636 
637  Real z = (m_lRhs[k] / scale) - (val / scale);
638 
639  if(isZero(z))
640  z = 0.0;
641 
642  Real lo = z * scale / row[m_j];
643  slack.add(k, val);
644 
645  if(lo > maxRowLo)
646  {
647  maxRowLo = lo;
648  domIdx = k;
649  }
650  }
651 
652  if(m_bnd > maxRowLo)
653  {
654  x[m_j] = m_bnd;
655  domIdx = -1;
656  }
657  else
658  x[m_j] = maxRowLo;
659  }
660 
661  for(int k = 0; k < m_col.size(); ++k)
662  s[m_col.index(k)] = slack[k] + m_col.value(k) * x[m_j];
663 
664  // dual:
665  r[m_j] = 0.0;
666 
667  for(int k = 0; k < m_col.size(); ++k)
668  {
669  int idx = m_col.index(k);
670  y[idx] = m_rowObj[idx];
671  }
672 
673  // basis:
674  for(int k = 0; k < m_col.size(); ++k)
675  {
676  if(k != domIdx)
677  rStatus[m_col.index(k)] = SPxSolver::BASIC;
678 
679  else
680  {
681  cStatus[m_j] = SPxSolver::BASIC;
682 
683  if(m_loFree)
684  rStatus[m_col.index(k)] = (m_col.value(k) > 0) ? SPxSolver::ON_UPPER : SPxSolver::ON_LOWER;
685  else
686  rStatus[m_col.index(k)] = (m_col.value(k) > 0) ? SPxSolver::ON_LOWER : SPxSolver::ON_UPPER;
687  }
688  }
689 
690  if(domIdx == -1)
691  {
692  if(m_loFree)
693  cStatus[m_j] = SPxSolver::ON_UPPER;
694  else
695  cStatus[m_j] = SPxSolver::ON_LOWER;
696  }
697 
698 #ifdef CHECK_BASIC_DIM
699 
700  if(!checkBasisDim(rStatus, cStatus))
701  {
702  throw SPxInternalCodeException("XMAISM20 Dimension doesn't match after this step.");
703  }
704 
705 #endif
706 }
707 
710  DataArray<SPxSolver::VarStatus>& rStatus, bool isOptimal) const
711 {
712  // correcting the change of idx by deletion of the column and corresponding rows:
713  x[m_old_j] = x[m_j];
714  r[m_old_j] = r[m_j];
715  cStatus[m_old_j] = cStatus[m_j];
716 
717  // primal & basis:
718  Real aij = m_row[m_j];
719 
720  if(isZero(s[m_i], 1e-6))
721  s[m_i] = 0.0;
722  else if(s[m_i] >= soplex::infinity)
723  // this is a fix for a highly ill conditioned instance that is "solved" in presolving (ilaser0 from MINLP, mittelmann)
724  throw SPxException("Simplifier: infinite activities - aborting unsimplification");
725 
726  Real scale1 = maxAbs(m_lhs, s[m_i]);
727  Real scale2 = maxAbs(m_rhs, s[m_i]);
728 
729  if(scale1 < 1.0)
730  scale1 = 1.0;
731 
732  if(scale2 < 1.0)
733  scale2 = 1.0;
734 
735  Real z1 = (m_lhs / scale1) - (s[m_i] / scale1);
736  Real z2 = (m_rhs / scale2) - (s[m_i] / scale2);
737 
738  if(isZero(z1))
739  z1 = 0.0;
740 
741  if(isZero(z2))
742  z2 = 0.0;
743 
744  Real lo = (aij > 0) ? z1 * scale1 / aij : z2 * scale2 / aij;
745  Real up = (aij > 0) ? z2 * scale2 / aij : z1 * scale1 / aij;
746 
747  if(isZero(lo, eps()))
748  lo = 0.0;
749 
750  if(isZero(up, eps()))
751  up = 0.0;
752 
753  assert(LErel(lo, up));
754  ASSERT_WARN("WMAISM01", isNotZero(aij, 1.0 / infinity));
755 
756  if(rStatus[m_i] == SPxSolver::ON_LOWER)
757  {
758  if(m_lower <= -infinity && m_upper >= infinity)
759  {
760  x[m_j] = 0.0;
761  cStatus[m_j] = SPxSolver::ZERO;
762  }
763  else if(m_lower == m_upper)
764  {
765  x[m_j] = m_lower;
766  cStatus[m_j] = SPxSolver::FIXED;
767  }
768  else if(aij > 0)
769  {
770  x[m_j] = m_upper;
771  cStatus[m_j] = SPxSolver::ON_UPPER;
772  }
773  else if(aij < 0)
774  {
775  x[m_j] = m_lower;
776  cStatus[m_j] = SPxSolver::ON_LOWER;
777  }
778  else
779  throw SPxInternalCodeException("XMAISM01 This should never happen.");
780  }
781  else if(rStatus[m_i] == SPxSolver::ON_UPPER)
782  {
783  if(m_lower <= -infinity && m_upper >= infinity)
784  {
785  x[m_j] = 0.0;
786  cStatus[m_j] = SPxSolver::ZERO;
787  }
788  else if(m_lower == m_upper)
789  {
790  x[m_j] = m_lower;
791  cStatus[m_j] = SPxSolver::FIXED;
792  }
793  else if(aij > 0)
794  {
795  x[m_j] = m_lower;
796  cStatus[m_j] = SPxSolver::ON_LOWER;
797  }
798  else if(aij < 0)
799  {
800  x[m_j] = m_upper;
801  cStatus[m_j] = SPxSolver::ON_UPPER;
802  }
803  else
804  throw SPxInternalCodeException("XMAISM02 This should never happen.");
805  }
806  else if(rStatus[m_i] == SPxSolver::FIXED)
807  {
808  if(m_lower <= -infinity && m_upper >= infinity)
809  {
810  x[m_j] = 0.0;
811  cStatus[m_j] = SPxSolver::ZERO;
812  }
813  else
814  {
815  assert(EQrel(m_lower, m_upper));
816 
817  x[m_j] = m_lower;
818  cStatus[m_j] = SPxSolver::FIXED;
819  }
820  }
821  else if(rStatus[m_i] == SPxSolver::BASIC)
822  {
823  if(GErel(m_lower, lo, eps()) && m_lower > -infinity)
824  {
825  x[m_j] = m_lower;
826  cStatus[m_j] = (m_lower == m_upper) ? SPxSolver::FIXED : SPxSolver::ON_LOWER;
827  }
828  else if(LErel(m_upper, up, eps()) && m_upper < infinity)
829  {
830  x[m_j] = m_upper;
831  cStatus[m_j] = (m_lower == m_upper) ? SPxSolver::FIXED : SPxSolver::ON_UPPER;
832  }
833  else if(lo > -infinity)
834  {
835  // make m_i non-basic and m_j basic
836  x[m_j] = lo;
837  cStatus[m_j] = SPxSolver::BASIC;
838  rStatus[m_i] = (aij > 0 ? SPxSolver::ON_LOWER : SPxSolver::ON_UPPER);
839  }
840  else if(up < infinity)
841  {
842  // make m_i non-basic and m_j basic
843  x[m_j] = up;
844  cStatus[m_j] = SPxSolver::BASIC;
845  rStatus[m_i] = (aij > 0 ? SPxSolver::ON_UPPER : SPxSolver::ON_LOWER);
846  }
847  else
848  throw SPxInternalCodeException("XMAISM03 This should never happen.");
849  }
850  else
851  throw SPxInternalCodeException("XMAISM04 This should never happen.");
852 
853  s[m_i] += aij * x[m_j];
854 
855  // dual:
856  r[m_j] = -1.0 * aij * y[m_i];
857 
858  assert(!isOptimal || (cStatus[m_j] != SPxSolver::BASIC || isZero(r[m_j], eps())));
859 
860 #ifdef CHECK_BASIC_DIM
861 
862  if(!checkBasisDim(rStatus, cStatus))
863  {
864  throw SPxInternalCodeException("XMAISM21 Dimension doesn't match after this step.");
865  }
866 
867 #endif
868 }
869 
872  DataArray<SPxSolver::VarStatus>& rStatus, bool isOptimal) const
873 {
874 
875  // correcting the change of idx by deletion of the row:
876  s[m_old_i] = s[m_i];
877  y[m_old_i] = y[m_i];
878  rStatus[m_old_i] = rStatus[m_i];
879 
880  // correcting the change of idx by deletion of the column:
881  x[m_old_j] = x[m_j];
882  r[m_old_j] = r[m_j];
883  cStatus[m_old_j] = cStatus[m_j];
884 
885  // primal:
886  Real val = 0.0;
887  Real aij = m_row[m_j];
888 
889  for(int k = 0; k < m_row.size(); ++k)
890  {
891  if(m_row.index(k) != m_j)
892  val += m_row.value(k) * x[m_row.index(k)];
893  }
894 
895  Real scale = maxAbs(m_lRhs, val);
896 
897  if(scale < 1.0)
898  scale = 1.0;
899 
900  Real z = (m_lRhs / scale) - (val / scale);
901 
902  if(isZero(z))
903  z = 0.0;
904 
905  x[m_j] = z * scale / aij;
906  s[m_i] = m_lRhs;
907 
908  // dual:
909  y[m_i] = m_obj / aij;
910  r[m_j] = 0.0;
911 
912  // basis:
913  cStatus[m_j] = SPxSolver::BASIC;
914 
915  if(m_eqCons)
916  rStatus[m_i] = SPxSolver::FIXED;
917  else if(m_onLhs)
918  rStatus[m_i] = SPxSolver::ON_LOWER;
919  else
920  rStatus[m_i] = SPxSolver::ON_UPPER;
921 
922 #ifdef CHECK_BASIC_DIM
923 
924  if(!checkBasisDim(rStatus, cStatus))
925  {
926  throw SPxInternalCodeException("XMAISM22 Dimension doesn't match after this step.");
927  }
928 
929 #endif
930 }
931 
934  DataArray<SPxSolver::VarStatus>& rStatus, bool isOptimal) const
935 {
936  // dual:
937  if((cStatus[m_k] != SPxSolver::BASIC) &&
938  ((cStatus[m_k] == SPxSolver::ON_LOWER && m_strictLo) ||
939  (cStatus[m_k] == SPxSolver::ON_UPPER && m_strictUp) ||
940  (cStatus[m_k] == SPxSolver::FIXED &&
941  ((m_maxSense && ((r[m_j] > 0 && m_strictUp) || (r[m_j] < 0 && m_strictLo))) ||
942  (!m_maxSense && ((r[m_j] > 0 && m_strictLo) || (r[m_j] < 0 && m_strictUp)))))))
943  {
944  Real val = m_kObj;
945  Real aik = m_col[m_i];
946 
947  for(int _k = 0; _k < m_col.size(); ++_k)
948  {
949  if(m_col.index(_k) != m_i)
950  val -= m_col.value(_k) * y[m_col.index(_k)];
951  }
952 
953  y[m_i] = val / aik;
954  r[m_k] = 0.0;
955 
956  r[m_j] = m_jObj - val * m_aij / aik;
957 
958  ASSERT_WARN("WMAISM73", isNotZero(m_aij * aik));
959 
960  // basis:
961  if(m_jFixed)
962  cStatus[m_j] = SPxSolver::FIXED;
963  else
964  {
965  if(GT(r[m_j], 0) || (isZero(r[m_j]) && EQ(x[m_j], m_Lo_j)))
966  cStatus[m_j] = SPxSolver::ON_LOWER;
967  else
968  cStatus[m_j] = SPxSolver::ON_UPPER;
969  }
970 
971  cStatus[m_k] = SPxSolver::BASIC;
972  }
973 
974 #ifdef CHECK_BASIC_DIM
975 
976  if(!checkBasisDim(rStatus, cStatus))
977  {
978  throw SPxInternalCodeException("XMAISM23 Dimension doesn't match after this step.");
979  }
980 
981 #endif
982 }
983 
986  DataArray<SPxSolver::VarStatus>& rStatus, bool isOptimal) const
987 {
988  // correcting the change of idx by deletion of the duplicated rows:
989  if(m_isLast)
990  {
991  for(int i = m_perm.size() - 1; i >= 0; --i)
992  {
993  if(m_perm[i] >= 0)
994  {
995  int rIdx_new = m_perm[i];
996  int rIdx = i;
997  s[rIdx] = s[rIdx_new];
998  y[rIdx] = y[rIdx_new];
999  rStatus[rIdx] = rStatus[rIdx_new];
1000  }
1001  }
1002  }
1003 
1004  // primal:
1005  for(int k = 0; k < m_scale.size(); ++k)
1006  {
1007  if(m_scale.index(k) != m_i)
1008  s[m_scale.index(k)] = s[m_i] / m_scale.value(k);
1009  }
1010 
1011  // dual & basis:
1012  bool haveSetBasis = false;
1013 
1014  for(int k = 0; k < m_scale.size(); ++k)
1015  {
1016  int i = m_scale.index(k);
1017 
1018  if(rStatus[m_i] == SPxSolver::BASIC || (haveSetBasis && i != m_i))
1019  // if the row with tightest lower and upper bound in the basic, every duplicate row should in basic
1020  // or basis status of row m_i has been set, this row should be in basis
1021  {
1022  y[i] = m_rowObj.value(k);
1023  rStatus[i] = SPxSolver::BASIC;
1024  continue;
1025  }
1026 
1027  ASSERT_WARN("WMAISM02", isNotZero(m_scale.value(k)));
1028 
1029  if(rStatus[m_i] == SPxSolver::FIXED && (i == m_maxLhsIdx || i == m_minRhsIdx))
1030  {
1031  // this row leads to the tightest lower or upper bound, slack should not be in the basis
1032  y[i] = y[m_i] * m_scale.value(k);
1033  y[m_i] = m_i_rowObj;
1034 
1035  if(m_isLhsEqualRhs[k])
1036  {
1037  rStatus[i] = SPxSolver::FIXED;
1038  }
1039  else if(i == m_maxLhsIdx)
1040  {
1041  rStatus[i] = m_scale.value(k) * m_scale.value(0) > 0 ? SPxSolver::ON_LOWER : SPxSolver::ON_UPPER;
1042  }
1043  else
1044  {
1045  assert(i == m_minRhsIdx);
1046 
1047  rStatus[i] = m_scale.value(k) * m_scale.value(0) > 0 ? SPxSolver::ON_UPPER : SPxSolver::ON_LOWER;
1048  }
1049 
1050  if(i != m_i)
1051  rStatus[m_i] = SPxSolver::BASIC;
1052 
1053  haveSetBasis = true;
1054  }
1055  else if(i == m_maxLhsIdx && rStatus[m_i] == SPxSolver::ON_LOWER)
1056  {
1057  // this row leads to the tightest lower bound, slack should not be in the basis
1058  y[i] = y[m_i] * m_scale.value(k);
1059  y[m_i] = m_i_rowObj;
1060 
1061  rStatus[i] = m_scale.value(k) * m_scale.value(0) > 0 ? SPxSolver::ON_LOWER : SPxSolver::ON_UPPER;
1062 
1063  if(i != m_i)
1064  rStatus[m_i] = SPxSolver::BASIC;
1065 
1066  haveSetBasis = true;
1067  }
1068  else if(i == m_minRhsIdx && rStatus[m_i] == SPxSolver::ON_UPPER)
1069  {
1070  // this row leads to the tightest upper bound, slack should not be in the basis
1071  y[i] = y[m_i] * m_scale.value(k);
1072  y[m_i] = m_i_rowObj;
1073 
1074  rStatus[i] = m_scale.value(k) * m_scale.value(0) > 0 ? SPxSolver::ON_UPPER : SPxSolver::ON_LOWER;
1075 
1076  if(i != m_i)
1077  rStatus[m_i] = SPxSolver::BASIC;
1078 
1079  haveSetBasis = true;
1080  }
1081  else if(i != m_i)
1082  {
1083  // this row does not lead to the tightest lower or upper bound, slack should be in the basis
1084  y[i] = m_rowObj.value(k);
1085  rStatus[i] = SPxSolver::BASIC;
1086  }
1087  }
1088 
1089 #ifdef CHECK_BASIC_DIM
1090 
1091  if(m_isFirst && !checkBasisDim(rStatus, cStatus))
1092  {
1093  throw SPxInternalCodeException("XMAISM24 Dimension doesn't match after this step.");
1094  }
1095 
1096 #endif
1097 
1098  // nothing to do for the reduced cost values
1099 }
1100 
1102  DVector&,
1103  DVector&,
1104  DVector& r,
1106  DataArray<SPxSolver::VarStatus>& rStatus, bool isOptimal) const
1107 {
1108 
1109  if(m_isFirst)
1110  {
1111 #ifdef CHECK_BASIC_DIM
1112 
1113  if(!checkBasisDim(rStatus, cStatus))
1114  {
1115  throw SPxInternalCodeException("XMAISM25 Dimension doesn't match after this step.");
1116  }
1117 
1118 #endif
1119  return;
1120  }
1121 
1122 
1123  // correcting the change of idx by deletion of the columns:
1124  if(m_isLast)
1125  {
1126  for(int i = m_perm.size() - 1; i >= 0; --i)
1127  {
1128  if(m_perm[i] >= 0)
1129  {
1130  int cIdx_new = m_perm[i];
1131  int cIdx = i;
1132  x[cIdx] = x[cIdx_new];
1133  r[cIdx] = r[cIdx_new];
1134  cStatus[cIdx] = cStatus[cIdx_new];
1135  }
1136  }
1137 
1138  return;
1139  }
1140 
1141  // primal & basis:
1142  ASSERT_WARN("WMAISM03", isNotZero(m_scale));
1143 
1144  if(cStatus[m_k] == SPxSolver::ON_LOWER)
1145  {
1146  x[m_k] = m_loK;
1147 
1148  if(m_scale > 0)
1149  {
1150  x[m_j] = m_loJ;
1151  cStatus[m_j] = (m_loJ == m_upJ) ? SPxSolver::FIXED : SPxSolver::ON_LOWER;
1152  }
1153  else
1154  {
1155  x[m_j] = m_upJ;
1156  cStatus[m_j] = (m_loJ == m_upJ) ? SPxSolver::FIXED : SPxSolver::ON_UPPER;
1157  }
1158  }
1159  else if(cStatus[m_k] == SPxSolver::ON_UPPER)
1160  {
1161  x[m_k] = m_upK;
1162 
1163  if(m_scale > 0)
1164  {
1165  x[m_j] = m_upJ;
1166  cStatus[m_j] = (m_loJ == m_upJ) ? SPxSolver::FIXED : SPxSolver::ON_UPPER;
1167  }
1168  else
1169  {
1170  x[m_j] = m_loJ;
1171  cStatus[m_j] = (m_loJ == m_upJ) ? SPxSolver::FIXED : SPxSolver::ON_LOWER;
1172  }
1173  }
1174  else if(cStatus[m_k] == SPxSolver::FIXED)
1175  {
1176  // => x[m_k] and x[m_j] are also fixed before the corresponding preprocessing step
1177  x[m_j] = m_loJ;
1178  cStatus[m_j] = SPxSolver::FIXED;
1179  }
1180  else if(cStatus[m_k] == SPxSolver::ZERO)
1181  {
1182  /* we only aggregate duplicate columns if 0 is contained in their bounds, so we can handle this case properly */
1183  assert(isZero(x[m_k]));
1184  assert(LErel(m_loJ, 0.0));
1185  assert(GErel(m_upJ, 0.0));
1186  assert(LErel(m_loK, 0.0));
1187  assert(GErel(m_upK, 0.0));
1188 
1189  if(isZero(m_loK) && isZero(m_upK) && m_loK == m_upK)
1190  cStatus[m_k] = SPxSolver::FIXED;
1191  else if(isZero(m_loK))
1192  cStatus[m_k] = SPxSolver::ON_LOWER;
1193  else if(isZero(m_upK))
1194  cStatus[m_k] = SPxSolver::ON_UPPER;
1195  else if(LErel(m_loK, 0.0) && GErel(m_upK, 0.0))
1196  cStatus[m_k] = SPxSolver::ZERO;
1197  else
1198  throw SPxInternalCodeException("XMAISM05 This should never happen.");
1199 
1200  x[m_j] = 0.0;
1201 
1202  if(isZero(m_loJ) && isZero(m_upJ) && m_loJ == m_upJ)
1203  cStatus[m_j] = SPxSolver::FIXED;
1204  else if(isZero(m_loJ))
1205  cStatus[m_j] = SPxSolver::ON_LOWER;
1206  else if(isZero(m_upJ))
1207  cStatus[m_j] = SPxSolver::ON_UPPER;
1208  else if(LErel(m_loJ, 0.0) && GErel(m_upJ, 0.0))
1209  cStatus[m_j] = SPxSolver::ZERO;
1210  else
1211  throw SPxInternalCodeException("XMAISM06 This should never happen.");
1212  }
1213  else if(cStatus[m_k] == SPxSolver::BASIC)
1214  {
1215  Real scale1 = maxAbs(x[m_k], m_loK);
1216  Real scale2 = maxAbs(x[m_k], m_upK);
1217 
1218  if(scale1 < 1.0)
1219  scale1 = 1.0;
1220 
1221  if(scale2 < 1.0)
1222  scale2 = 1.0;
1223 
1224  Real z1 = (x[m_k] / scale1) - (m_loK / scale1);
1225  Real z2 = (x[m_k] / scale2) - (m_upK / scale2);
1226 
1227  if(isZero(z1))
1228  z1 = 0.0;
1229 
1230  if(isZero(z2))
1231  z2 = 0.0;
1232 
1233  if(m_loJ <= -infinity && m_upJ >= infinity && m_loK <= -infinity && m_upK >= infinity)
1234  {
1235  cStatus[m_j] = SPxSolver::ZERO;
1236  x[m_j] = 0.0;
1237  }
1238  else if(m_scale > 0.0)
1239  {
1240  if(GErel(x[m_k], m_upK + m_scale * m_upJ))
1241  {
1242  assert(m_upJ < infinity);
1243  cStatus[m_j] = (m_loJ == m_upJ) ? SPxSolver::FIXED : SPxSolver::ON_UPPER;
1244  x[m_j] = m_upJ;
1245  x[m_k] -= m_scale * x[m_j];
1246  }
1247  else if(GErel(x[m_k], m_loK + m_scale * m_upJ) && m_upJ < infinity)
1248  {
1249  cStatus[m_j] = (m_loJ == m_upJ) ? SPxSolver::FIXED : SPxSolver::ON_UPPER;
1250  x[m_j] = m_upJ;
1251  x[m_k] -= m_scale * x[m_j];
1252  }
1253  else if(GErel(x[m_k], m_upK + m_scale * m_loJ) && m_upK < infinity)
1254  {
1255  cStatus[m_k] = (m_loK == m_upK) ? SPxSolver::FIXED : SPxSolver::ON_UPPER;
1256  x[m_k] = m_upK;
1257  cStatus[m_j] = SPxSolver::BASIC;
1258  x[m_j] = z2 * scale2 / m_scale;
1259  }
1260  else if(GErel(x[m_k], m_loK + m_scale * m_loJ) && m_loJ > -infinity)
1261  {
1262  cStatus[m_j] = (m_loJ == m_upJ) ? SPxSolver::FIXED : SPxSolver::ON_LOWER;
1263  x[m_j] = m_loJ;
1264  x[m_k] -= m_scale * x[m_j];
1265  }
1266  else if(GErel(x[m_k], m_loK + m_scale * m_loJ) && m_loK > -infinity)
1267  {
1268  cStatus[m_k] = (m_loK == m_upK) ? SPxSolver::FIXED : SPxSolver::ON_LOWER;
1269  x[m_k] = m_loK;
1270  cStatus[m_j] = SPxSolver::BASIC;
1271  x[m_j] = z1 * scale1 / m_scale;
1272  }
1273  else if(LTrel(x[m_k], m_loK + m_scale * m_loJ))
1274  {
1275  assert(m_loJ > -infinity);
1276  cStatus[m_j] = (m_loJ == m_upJ) ? SPxSolver::FIXED : SPxSolver::ON_LOWER;
1277  x[m_j] = m_loJ;
1278  x[m_k] -= m_scale * x[m_j];
1279  }
1280  else
1281  {
1282  throw SPxInternalCodeException("XMAISM08 This should never happen.");
1283  }
1284  }
1285  else
1286  {
1287  assert(m_scale < 0.0);
1288 
1289  if(GErel(x[m_k], m_upK + m_scale * m_loJ))
1290  {
1291  assert(m_loJ > -infinity);
1292  cStatus[m_j] = (m_loJ == m_upJ) ? SPxSolver::FIXED : SPxSolver::ON_LOWER;
1293  x[m_j] = m_loJ;
1294  x[m_k] -= m_scale * x[m_j];
1295  }
1296  else if(GErel(x[m_k], m_loK + m_scale * m_loJ) && m_loJ > -infinity)
1297  {
1298  cStatus[m_j] = (m_loJ == m_upJ) ? SPxSolver::FIXED : SPxSolver::ON_LOWER;
1299  x[m_j] = m_loJ;
1300  x[m_k] -= m_scale * x[m_j];
1301  }
1302  else if(GErel(x[m_k], m_upK + m_scale * m_upJ) && m_upK < infinity)
1303  {
1304  cStatus[m_k] = (m_loK == m_upK) ? SPxSolver::FIXED : SPxSolver::ON_UPPER;
1305  x[m_k] = m_upK;
1306  cStatus[m_j] = SPxSolver::BASIC;
1307  x[m_j] = z2 * scale2 / m_scale;
1308  }
1309  else if(GErel(x[m_k], m_loK + m_scale * m_upJ) && m_upJ < infinity)
1310  {
1311  cStatus[m_j] = (m_loJ == m_upJ) ? SPxSolver::FIXED : SPxSolver::ON_UPPER;
1312  x[m_j] = m_upJ;
1313  x[m_k] -= m_scale * x[m_j];
1314  }
1315  else if(GErel(x[m_k], m_loK + m_scale * m_upJ) && m_loK > -infinity)
1316  {
1317  cStatus[m_k] = (m_loK == m_upK) ? SPxSolver::FIXED : SPxSolver::ON_LOWER;
1318  x[m_k] = m_loK;
1319  cStatus[m_j] = SPxSolver::BASIC;
1320  x[m_j] = z1 * scale1 / m_scale;
1321  }
1322  else if(LTrel(x[m_k], m_loK + m_scale * m_upJ))
1323  {
1324  assert(m_upJ < infinity);
1325  cStatus[m_j] = (m_loJ == m_upJ) ? SPxSolver::FIXED : SPxSolver::ON_UPPER;
1326  x[m_j] = m_upJ;
1327  x[m_k] -= m_scale * x[m_j];
1328  }
1329  else
1330  {
1331  throw SPxInternalCodeException("XMAISM09 This should never happen.");
1332  }
1333  }
1334  }
1335 
1336  // dual:
1337  r[m_j] = m_scale * r[m_k];
1338 }
1339 
1342  DataArray<SPxSolver::VarStatus>& rStatus, bool isOptimal) const
1343 {
1344  // correcting the change of idx by deletion of the row:
1345  s[m_old_i] = s[m_i];
1346  y[m_old_i] = y[m_i];
1347  rStatus[m_old_i] = rStatus[m_i];
1348 
1349  // correcting the change of idx by deletion of the column:
1350  x[m_old_j] = x[m_j];
1351  r[m_old_j] = r[m_j];
1352  cStatus[m_old_j] = cStatus[m_j];
1353 
1354  // primal:
1355  Real val = 0.0;
1356  Real aij = m_row[m_j];
1357  int active_idx = -1;
1358 
1359  assert(m_row.size() == 2);
1360 
1361  for(int k = 0; k < 2; ++k)
1362  {
1363  if(m_row.index(k) != m_j)
1364  {
1365  active_idx = m_row.index(k);
1366  val = m_row.value(k) * x[active_idx];
1367  }
1368  }
1369 
1370  assert(active_idx >= 0);
1371 
1372  Real scale = maxAbs(m_rhs, val);
1373 
1374  if(scale < 1.0)
1375  scale = 1.0;
1376 
1377  Real z = (m_rhs / scale) - (val / scale);
1378 
1379  if(isZero(z))
1380  z = 0.0;
1381 
1382  x[m_j] = z * scale / aij;
1383  s[m_i] = 0.0;
1384 
1385  if(isOptimal && (LT(x[m_j], m_lower, eps()) || GT(x[m_j], m_upper, eps())))
1386  {
1387  MSG_ERROR(std::cerr << "EMAISM: numerical violation after disaggregating variable" << std::endl;)
1388  }
1389 
1390  // dual:
1391  Real dualVal = 0.0;
1392 
1393  for(int k = 0; k < m_col.size(); ++k)
1394  {
1395  if(m_col.index(k) != m_i)
1396  dualVal += m_col.value(k) * y[m_col.index(k)];
1397  }
1398 
1399  z = m_obj - dualVal;
1400 
1401  y[m_i] = z / aij;
1402  r[m_j] = 0.0;
1403 
1404  // basis:
1405  if(((cStatus[active_idx] == SPxSolver::ON_UPPER || cStatus[active_idx] == SPxSolver::FIXED)
1406  && NE(x[active_idx], m_oldupper, eps())) ||
1407  ((cStatus[active_idx] == SPxSolver::ON_LOWER || cStatus[active_idx] == SPxSolver::FIXED)
1408  && NE(x[active_idx], m_oldlower, eps())))
1409  {
1410  cStatus[active_idx] = SPxSolver::BASIC;
1411  r[active_idx] = 0.0;
1412  assert(NE(m_upper, m_lower));
1413 
1414  if(EQ(x[m_j], m_upper, eps()))
1415  cStatus[m_j] = SPxSolver::ON_UPPER;
1416  else if(EQ(x[m_j], m_lower, eps()))
1417  cStatus[m_j] = SPxSolver::ON_LOWER;
1418  else if(m_upper >= infinity && m_lower <= -infinity)
1419  cStatus[m_j] = SPxSolver::ZERO;
1420  else
1421  throw SPxInternalCodeException("XMAISM unexpected basis status in aggregation unsimplifier.");
1422  }
1423  else
1424  {
1425  cStatus[m_j] = SPxSolver::BASIC;
1426  }
1427 
1428  // sides may not be equal and we always only consider the rhs during aggregation, so set ON_UPPER
1429  // (in theory and with exact arithmetic setting it to FIXED would be correct)
1430  rStatus[m_i] = SPxSolver::ON_UPPER;
1431 
1432 #ifdef CHECK_BASIC_DIM
1433 
1434  if(!checkBasisDim(rStatus, cStatus))
1435  {
1436  throw SPxInternalCodeException("XMAISM22 Dimension doesn't match after this step.");
1437  }
1438 
1439 #endif
1440 }
1441 
1444  DataArray<SPxSolver::VarStatus>& rStatus, bool isOptimal) const
1445 {
1446 
1447  // correcting the change of idx by deletion of the row:
1448  s[m_old_i] = s[m_i];
1449  y[m_old_i] = y[m_i];
1450  rStatus[m_old_i] = rStatus[m_i];
1451 
1452  // correcting the change of idx by deletion of the column:
1453  x[m_old_j] = x[m_j];
1454  r[m_old_j] = r[m_j];
1455  cStatus[m_old_j] = cStatus[m_j];
1456 
1457  // primal:
1458  Real val = 0.0;
1459  Real aij = m_row[m_j];
1460 
1461  for(int k = 0; k < m_row.size(); ++k)
1462  {
1463  if(m_row.index(k) != m_j)
1464  val += m_row.value(k) * x[m_row.index(k)];
1465  }
1466 
1467  Real scale = maxAbs(m_const, val);
1468 
1469  if(scale < 1.0)
1470  scale = 1.0;
1471 
1472  Real z = (m_const / scale) - (val / scale);
1473 
1474  if(isZero(z))
1475  z = 0.0;
1476 
1477  x[m_j] = z * scale / aij;
1478  s[m_i] = 0.0;
1479 
1480 #ifndef NDEBUG
1481 
1482  if(isOptimal && (LT(x[m_j], m_lower, eps()) || GT(x[m_j], m_upper, eps())))
1483  MSG_ERROR(std::cerr << "numerical violation in original space due to MultiAggregation\n";)
1484 #endif
1485 
1486  // dual:
1487  Real dualVal = 0.0;
1488 
1489  for(int k = 0; k < m_col.size(); ++k)
1490  {
1491  if(m_col.index(k) != m_i)
1492  dualVal += m_col.value(k) * y[m_col.index(k)];
1493  }
1494 
1495  z = m_obj - dualVal;
1496 
1497  y[m_i] = z / aij;
1498  r[m_j] = 0.0;
1499 
1500  // basis:
1501  cStatus[m_j] = SPxSolver::BASIC;
1502 
1503  if(m_eqCons)
1504  rStatus[m_i] = SPxSolver::FIXED;
1505  else if(m_onLhs)
1506  rStatus[m_i] = SPxSolver::ON_LOWER;
1507  else
1508  rStatus[m_i] = SPxSolver::ON_UPPER;
1509 
1510 #ifdef CHECK_BASIC_DIM
1511 
1512  if(!checkBasisDim(rStatus, cStatus))
1513  {
1514  throw SPxInternalCodeException("XMAISM22 Dimension doesn't match after this step.");
1515  }
1516 
1517 #endif
1518 }
1519 
1522  DataArray<SPxSolver::VarStatus>& rStatus, bool isOptimal) const
1523 {
1524  // basis:
1525  switch(cStatus[m_j])
1526  {
1527  case SPxSolver::FIXED:
1528  if(LT(x[m_j], m_origupper, eps()) && GT(x[m_j], m_origlower, eps()))
1529  cStatus[m_j] = SPxSolver::BASIC;
1530  else if(LT(x[m_j], m_origupper, eps()))
1531  cStatus[m_j] = SPxSolver::ON_LOWER;
1532  else if(GT(x[m_j], m_origlower, eps()))
1533  cStatus[m_j] = SPxSolver::ON_UPPER;
1534 
1535  break;
1536 
1537  case SPxSolver::ON_LOWER:
1538  if(GT(x[m_j], m_origlower, eps()))
1539  cStatus[m_j] = SPxSolver::BASIC;
1540 
1541  break;
1542 
1543  case SPxSolver::ON_UPPER:
1544  if(LT(x[m_j], m_origupper, eps()))
1545  cStatus[m_j] = SPxSolver::BASIC;
1546 
1547  break;
1548 
1549  default:
1550  break;
1551  }
1552 
1553 #ifdef CHECK_BASIC_DIM
1554 
1555  if(!checkBasisDim(rStatus, cStatus))
1556  {
1557  throw SPxInternalCodeException("XMAISM22 Dimension doesn't match after this step.");
1558  }
1559 
1560 #endif
1561 }
1562 
1564 {
1565  for(int i = lp.nRows() - 1; i >= 0; --i)
1566  {
1567  if(lp.maxRowObj(i) != 0.0)
1568  {
1569  RowObjPS* RowObjPSptr = 0;
1570  spx_alloc(RowObjPSptr);
1571  m_hist.append(new(RowObjPSptr) RowObjPS(lp, i, lp.nCols()));
1572  lp.addCol(lp.rowObj(i), -lp.rhs(i), UnitVector(i), -lp.lhs(i));
1573  lp.changeRange(i, 0.0, 0.0);
1574  lp.changeRowObj(i, 0.0);
1575  m_addedcols++;
1576  }
1577  }
1578 }
1579 
1581 {
1582 
1583  // This method handles extreme value of the given LP by
1584  //
1585  // 1. setting numbers of very small absolute values to zero and
1586  // 2. setting numbers of very large absolute values to -infinity or +infinity, respectively.
1587 
1588  Real maxVal = infinity / 5.0;
1589  Real tol = feastol() * 1e-2;
1590  tol = (tol < epsZero()) ? epsZero() : tol;
1591  int remRows = 0;
1592  int remNzos = 0;
1593  int chgBnds = 0;
1594  int chgLRhs = 0;
1595  int objCnt = 0;
1596 
1597  for(int i = lp.nRows() - 1; i >= 0; --i)
1598  {
1599  // lhs
1600  Real lhs = lp.lhs(i);
1601 
1602  if(lhs != 0.0 && isZero(lhs, epsZero()))
1603  {
1604  lp.changeLhs(i, 0.0);
1605  ++chgLRhs;
1606  }
1607  else if(lhs > -infinity && lhs < -maxVal)
1608  {
1609  lp.changeLhs(i, -infinity);
1610  ++chgLRhs;
1611  }
1612  else if(lhs < infinity && lhs > maxVal)
1613  {
1614  lp.changeLhs(i, infinity);
1615  ++chgLRhs;
1616  }
1617 
1618  // rhs
1619  Real rhs = lp.rhs(i);
1620 
1621  if(rhs != 0.0 && isZero(rhs, epsZero()))
1622  {
1623  lp.changeRhs(i, 0.0);
1624  ++chgLRhs;
1625  }
1626  else if(rhs > -infinity && rhs < -maxVal)
1627  {
1628  lp.changeRhs(i, -infinity);
1629  ++chgLRhs;
1630  }
1631  else if(rhs < infinity && rhs > maxVal)
1632  {
1633  lp.changeRhs(i, infinity);
1634  ++chgLRhs;
1635  }
1636 
1637  if(lp.lhs(i) <= -infinity && lp.rhs(i) >= infinity)
1638  {
1639  FreeConstraintPS* FreeConstraintPSptr = 0;
1640  spx_alloc(FreeConstraintPSptr);
1641  m_hist.append(new(FreeConstraintPSptr) FreeConstraintPS(lp, i));
1642 
1643  removeRow(lp, i);
1644  ++remRows;
1645 
1646  ++m_stat[FREE_ROW];
1647  }
1648  }
1649 
1650  for(int j = 0; j < lp.nCols(); ++j)
1651  {
1652  // lower bound
1653  Real lo = lp.lower(j);
1654 
1655  if(lo != 0.0 && isZero(lo, epsZero()))
1656  {
1657  lp.changeLower(j, 0.0);
1658  ++chgBnds;
1659  }
1660  else if(lo > -infinity && lo < -maxVal)
1661  {
1662  lp.changeLower(j, -infinity);
1663  ++chgBnds;
1664  }
1665  else if(lo < infinity && lo > maxVal)
1666  {
1667  lp.changeLower(j, infinity);
1668  ++chgBnds;
1669  }
1670 
1671  // upper bound
1672  Real up = lp.upper(j);
1673 
1674  if(up != 0.0 && isZero(up, epsZero()))
1675  {
1676  lp.changeUpper(j, 0.0);
1677  ++chgBnds;
1678  }
1679  else if(up > -infinity && up < -maxVal)
1680  {
1681  lp.changeUpper(j, -infinity);
1682  ++chgBnds;
1683  }
1684  else if(up < infinity && up > maxVal)
1685  {
1686  lp.changeUpper(j, infinity);
1687  ++chgBnds;
1688  }
1689 
1690  // fixed columns will be eliminated later
1691  if(NE(lo, up))
1692  {
1693  lo = spxAbs(lo);
1694  up = spxAbs(up);
1695 
1696  Real absBnd = (lo > up) ? lo : up;
1697 
1698  if(absBnd < 1.0)
1699  absBnd = 1.0;
1700 
1701  // non-zeros
1702  SVector& col = lp.colVector_w(j);
1703  int i = 0;
1704 
1705  while(i < col.size())
1706  {
1707  Real aij = spxAbs(col.value(i));
1708 
1709  if(isZero(aij * absBnd, tol))
1710  {
1711  SVector& row = lp.rowVector_w(col.index(i));
1712  int row_j = row.pos(j);
1713 
1714  // this changes col.size()
1715  if(row_j >= 0)
1716  row.remove(row_j);
1717 
1718  col.remove(i);
1719 
1720  MSG_DEBUG((*spxout) << "IMAISM04 aij=" << aij
1721  << " removed, absBnd=" << absBnd
1722  << std::endl;)
1723  ++remNzos;
1724  }
1725  else
1726  {
1727  if(aij > maxVal)
1728  {
1729  MSG_WARNING((*spxout), (*spxout) << "WMAISM05 Warning! Big matrix coefficient " << aij <<
1730  std::endl);
1731  }
1732  else if(isZero(aij, tol))
1733  {
1734  MSG_WARNING((*spxout), (*spxout) << "WMAISM06 Warning! Tiny matrix coefficient " << aij <<
1735  std::endl);
1736  }
1737 
1738  ++i;
1739  }
1740  }
1741  }
1742 
1743  // objective
1744  Real obj = lp.obj(j);
1745 
1746  if(obj != 0.0 && isZero(obj, epsZero()))
1747  {
1748  lp.changeObj(j, 0.0);
1749  ++objCnt;
1750  }
1751  else if(obj > -infinity && obj < -maxVal)
1752  {
1753  lp.changeObj(j, -infinity);
1754  ++objCnt;
1755  }
1756  else if(obj < infinity && obj > maxVal)
1757  {
1758  lp.changeObj(j, infinity);
1759  ++objCnt;
1760  }
1761  }
1762 
1763  if(remRows + remNzos + chgLRhs + chgBnds + objCnt > 0)
1764  {
1765  m_remRows += remRows;
1766  m_remNzos += remNzos;
1767  m_chgLRhs += chgLRhs;
1768  m_chgBnds += chgBnds;
1769 
1770  MSG_INFO2((*spxout), (*spxout) << "Simplifier (extremes) removed "
1771  << remRows << " rows, "
1772  << remNzos << " non-zeros, "
1773  << chgBnds << " col bounds, "
1774  << chgLRhs << " row bounds, "
1775  << objCnt << " objective coefficients" << std::endl;)
1776  }
1777 
1778  assert(lp.isConsistent());
1779 }
1780 
1781 /// computes the minimum and maximum residual activity for a given variable
1782 void SPxMainSM::computeMinMaxResidualActivity(SPxLP& lp, int rowNumber, int colNumber, Real& minAct,
1783  Real& maxAct)
1784 {
1785  const SVector& row = lp.rowVector(rowNumber);
1786  bool minNegInfinite = false;
1787  bool maxInfinite = false;
1788 
1789  minAct = 0; // this is the minimum value that the aggregation can attain
1790  maxAct = 0; // this is the maximum value that the aggregation can attain
1791 
1792  for(int l = 0; l < row.size(); ++l)
1793  {
1794  if(colNumber < 0 || row.index(l) != colNumber)
1795  {
1796  // computing the minimum activity of the aggregated variables
1797  if(GT(row.value(l), 0.0))
1798  {
1799  if(LE(lp.lower(row.index(l)), -infinity))
1800  minNegInfinite = true;
1801  else
1802  minAct += row.value(l) * lp.lower(row.index(l));
1803  }
1804  else if(LT(row.value(l), 0.0))
1805  {
1806  if(GE(lp.upper(row.index(l)), infinity))
1807  minNegInfinite = true;
1808  else
1809  minAct += row.value(l) * lp.upper(row.index(l));
1810  }
1811 
1812  // computing the maximum activity of the aggregated variables
1813  if(GT(row.value(l), 0.0))
1814  {
1815  if(GE(lp.upper(row.index(l)), infinity))
1816  maxInfinite = true;
1817  else
1818  maxAct += row.value(l) * lp.upper(row.index(l));
1819  }
1820  else if(LT(row.value(l), 0.0))
1821  {
1822  if(LE(lp.lower(row.index(l)), -infinity))
1823  maxInfinite = true;
1824  else
1825  maxAct += row.value(l) * lp.lower(row.index(l));
1826  }
1827  }
1828  }
1829 
1830  // if an infinite value exists for the minimum activity, then that it taken
1831  if(minNegInfinite)
1832  minAct = -infinity;
1833 
1834  // if an -infinite value exists for the maximum activity, then that value is taken
1835  if(maxInfinite)
1836  maxAct = infinity;
1837 }
1838 
1839 
1840 /// calculate min/max value for the multi aggregated variables
1841 void SPxMainSM::computeMinMaxValues(SPxLP& lp, Real side, Real val, Real minRes, Real maxRes,
1842  Real& minVal, Real& maxVal)
1843 {
1844  minVal = 0;
1845  maxVal = 0;
1846 
1847  if(LT(val, 0.0))
1848  {
1849  if(LE(minRes, -infinity))
1850  minVal = -infinity;
1851  else
1852  minVal = (side - minRes) / val;
1853 
1854  if(GE(maxRes, infinity))
1855  maxVal = infinity;
1856  else
1857  maxVal = (side - maxRes) / val;
1858  }
1859  else if(GT(val, 0.0))
1860  {
1861  if(GE(maxRes, infinity))
1862  minVal = -infinity;
1863  else
1864  minVal = (side - maxRes) / val;
1865 
1866  if(LE(minRes, -infinity))
1867  maxVal = infinity;
1868  else
1869  maxVal = (side - minRes) / val;
1870  }
1871 }
1872 
1873 
1874 /// tries to find good lower bound solutions by applying some trivial heuristics
1876 {
1877  DVector zerosol(lp.nCols()); // the zero solution vector
1878  DVector lowersol(lp.nCols()); // the lower bound solution vector
1879  DVector uppersol(lp.nCols()); // the upper bound solution vector
1880  DVector locksol(lp.nCols()); // the locks solution vector
1881 
1882  DVector upLocks(lp.nCols());
1883  DVector downLocks(lp.nCols());
1884 
1885  Real zeroObj = m_objoffset;
1886  Real lowerObj = m_objoffset;
1887  Real upperObj = m_objoffset;
1888  Real lockObj = m_objoffset;
1889 
1890  bool zerovalid = true;
1891 
1892  Real largeValue = infinity;
1893 
1894  if(LT(1.0 / feastol(), infinity))
1895  largeValue = 1.0 / feastol();
1896 
1897 
1898 
1899  for(int j = lp.nCols() - 1; j >= 0; --j)
1900  {
1901  upLocks[j] = 0;
1902  downLocks[j] = 0;
1903 
1904  // computing the locks on the variables
1905  const SVector& col = lp.colVector(j);
1906 
1907  for(int k = 0; k < col.size(); ++k)
1908  {
1909  Real aij = col.value(k);
1910 
1911  ASSERT_WARN("WMAISM45", isNotZero(aij, 1.0 / infinity));
1912 
1913  if(GT(lp.lhs(col.index(k)), -infinity) && LT(lp.rhs(col.index(k)), infinity))
1914  {
1915  upLocks[j]++;
1916  downLocks[j]++;
1917  }
1918  else if(GT(lp.lhs(col.index(k)), -infinity))
1919  {
1920  if(aij > 0)
1921  downLocks[j]++;
1922  else if(aij < 0)
1923  upLocks[j]++;
1924  }
1925  else if(LT(lp.rhs(col.index(k)), infinity))
1926  {
1927  if(aij > 0)
1928  upLocks[j]++;
1929  else if(aij < 0)
1930  downLocks[j]++;
1931  }
1932  }
1933 
1934  Real lower = lp.lower(j);
1935  Real upper = lp.upper(j);
1936 
1937  if(LE(lower, -infinity))
1938  lower = MINIMUM(-largeValue, upper);
1939 
1940  if(GE(upper, infinity))
1941  upper = MAXIMUM(lp.lower(j), largeValue);
1942 
1943  if(zerovalid)
1944  {
1945  if(LE(lower, 0.0, feastol()) && GE(upper, 0.0, feastol()))
1946  zerosol[j] = 0.0;
1947  else
1948  zerovalid = false;
1949  }
1950 
1951  lowersol[j] = lower;
1952  uppersol[j] = upper;
1953 
1954  if(downLocks[j] > upLocks[j])
1955  locksol[j] = upper;
1956  else if(downLocks[j] < upLocks[j])
1957  locksol[j] = lower;
1958  else
1959  locksol[j] = (lower + upper) / 2.0;
1960 
1961  lowerObj += lp.maxObj(j) * lowersol[j];
1962  upperObj += lp.maxObj(j) * uppersol[j];
1963  lockObj += lp.maxObj(j) * locksol[j];
1964  }
1965 
1966  // trying the lower bound solution
1967  if(checkSolution(lp, lowersol))
1968  {
1969  if(lowerObj > m_cutoffbound)
1970  m_cutoffbound = lowerObj;
1971  }
1972 
1973  // trying the upper bound solution
1974  if(checkSolution(lp, uppersol))
1975  {
1976  if(upperObj > m_cutoffbound)
1977  m_cutoffbound = upperObj;
1978  }
1979 
1980  // trying the zero solution
1981  if(zerovalid && checkSolution(lp, zerosol))
1982  {
1983  if(zeroObj > m_cutoffbound)
1984  m_cutoffbound = zeroObj;
1985  }
1986 
1987  // trying the lock solution
1988  if(checkSolution(lp, locksol))
1989  {
1990  if(lockObj > m_cutoffbound)
1991  m_cutoffbound = lockObj;
1992  }
1993 }
1994 
1995 
1996 /// checks a solution for feasibility
1998 {
1999  for(int i = lp.nRows() - 1; i >= 0; --i)
2000  {
2001  const SVector& row = lp.rowVector(i);
2002  Real activity = 0;
2003 
2004  for(int k = 0; k < row.size(); k++)
2005  activity += row.value(k) * sol[row.index(k)];
2006 
2007  if(!GE(activity, lp.lhs(i), feastol()) || !LE(activity, lp.rhs(i), feastol()))
2008  return false;
2009  }
2010 
2011  return true;
2012 }
2013 
2014 
2015 
2016 /// tightens variable bounds by propagating the pseudo objective function value.
2018 {
2019  Real pseudoObj = m_objoffset;
2020 
2021  for(int j = lp.nCols() - 1; j >= 0; --j)
2022  {
2023  Real val = lp.maxObj(j);
2024 
2025  if(val < 0)
2026  {
2027  if(lp.lower(j) <= -infinity)
2028  return;
2029 
2030  pseudoObj += val * lp.lower(j);
2031  }
2032  else if(val > 0)
2033  {
2034  if(lp.upper(j) >= -infinity)
2035  return;
2036 
2037  pseudoObj += val * lp.upper(j);
2038  }
2039  }
2040 
2042  {
2043  if(pseudoObj > m_pseudoobj)
2044  m_pseudoobj = pseudoObj;
2045 
2046  for(int j = lp.nCols() - 1; j >= 0; --j)
2047  {
2048  Real objval = lp.maxObj(j);
2049 
2050  if(EQ(objval, 0.0))
2051  continue;
2052 
2053  if(objval < 0.0)
2054  {
2055  Real newbound = lp.lower(j) + (m_cutoffbound - m_pseudoobj) / objval;
2056 
2057  if(LT(newbound, lp.upper(j)))
2058  {
2059  TightenBoundsPS* TightenBoundsPSptr = 0;
2060  spx_alloc(TightenBoundsPSptr);
2061  m_hist.append(new(TightenBoundsPSptr) TightenBoundsPS(lp, j, lp.upper(j), lp.lower(j)));
2062  lp.changeUpper(j, newbound);
2063  }
2064  }
2065  else if(objval > 0.0)
2066  {
2067  Real newbound = lp.upper(j) + (m_cutoffbound - m_pseudoobj) / objval;
2068 
2069  if(GT(newbound, lp.lower(j)))
2070  {
2071  TightenBoundsPS* TightenBoundsPSptr = 0;
2072  spx_alloc(TightenBoundsPSptr);
2073  m_hist.append(new(TightenBoundsPSptr) TightenBoundsPS(lp, j, lp.upper(j), lp.lower(j)));
2074  lp.changeLower(j, newbound);
2075  }
2076  }
2077  }
2078  }
2079 }
2080 
2081 
2082 
2084 {
2085 
2086  // This method removes empty rows and columns from the LP.
2087 
2088  int remRows = 0;
2089  int remCols = 0;
2090 
2091  for(int i = lp.nRows() - 1; i >= 0; --i)
2092  {
2093  const SVector& row = lp.rowVector(i);
2094 
2095  if(row.size() == 0)
2096  {
2097  MSG_DEBUG((*spxout) << "IMAISM07 row " << i
2098  << ": empty ->";)
2099 
2100  if(LT(lp.rhs(i), 0.0, feastol()) || GT(lp.lhs(i), 0.0, feastol()))
2101  {
2102  MSG_DEBUG((*spxout) << " infeasible lhs=" << lp.lhs(i)
2103  << " rhs=" << lp.rhs(i) << std::endl;)
2104  return INFEASIBLE;
2105  }
2106 
2107  MSG_DEBUG((*spxout) << " removed" << std::endl;)
2108 
2109  EmptyConstraintPS* EmptyConstraintPSptr = 0;
2110  spx_alloc(EmptyConstraintPSptr);
2111  m_hist.append(new(EmptyConstraintPSptr) EmptyConstraintPS(lp, i));
2112 
2113  ++remRows;
2114  removeRow(lp, i);
2115 
2116  ++m_stat[EMPTY_ROW];
2117  }
2118  }
2119 
2120  for(int j = lp.nCols() - 1; j >= 0; --j)
2121  {
2122  const SVector& col = lp.colVector(j);
2123 
2124  if(col.size() == 0)
2125  {
2126  MSG_DEBUG((*spxout) << "IMAISM08 col " << j
2127  << ": empty -> maxObj=" << lp.maxObj(j)
2128  << " lower=" << lp.lower(j)
2129  << " upper=" << lp.upper(j);)
2130 
2131  Real val;
2132 
2133  if(GT(lp.maxObj(j), 0.0, epsZero()))
2134  {
2135  if(lp.upper(j) >= infinity)
2136  {
2137  MSG_DEBUG((*spxout) << " unbounded" << std::endl;)
2138  return UNBOUNDED;
2139  }
2140 
2141  val = lp.upper(j);
2142  }
2143  else if(LT(lp.maxObj(j), 0.0, epsZero()))
2144  {
2145  if(lp.lower(j) <= -infinity)
2146  {
2147  MSG_DEBUG((*spxout) << " unbounded" << std::endl;)
2148  return UNBOUNDED;
2149  }
2150 
2151  val = lp.lower(j);
2152  }
2153  else
2154  {
2155  ASSERT_WARN("WMAISM09", isZero(lp.maxObj(j), epsZero()));
2156 
2157  // any value within the bounds is ok
2158  if(lp.lower(j) > -infinity)
2159  val = lp.lower(j);
2160  else if(lp.upper(j) < infinity)
2161  val = lp.upper(j);
2162  else
2163  val = 0.0;
2164  }
2165 
2166  MSG_DEBUG((*spxout) << " removed" << std::endl;)
2167 
2168  FixBoundsPS* FixBoundsPSptr = 0;
2169  FixVariablePS* FixVariablePSptr = 0;
2170  spx_alloc(FixBoundsPSptr);
2171  spx_alloc(FixVariablePSptr);
2172  m_hist.append(new(FixBoundsPSptr) FixBoundsPS(lp, j, val));
2173  m_hist.append(new(FixVariablePSptr) FixVariablePS(lp, *this, j, val));
2174 
2175  ++remCols;
2176  removeCol(lp, j);
2177 
2178  ++m_stat[EMPTY_COL];
2179  }
2180  }
2181 
2182  if(remRows + remCols > 0)
2183  {
2184  m_remRows += remRows;
2185  m_remCols += remCols;
2186 
2187  MSG_INFO2((*spxout), (*spxout) << "Simplifier (empty rows/colums) removed "
2188  << remRows << " rows, "
2189  << remCols << " cols"
2190  << std::endl;)
2191 
2192  }
2193 
2194  return OKAY;
2195 }
2196 
2198 {
2199  assert(row.size() == 1);
2200 
2201  Real aij = row.value(0);
2202  int j = row.index(0);
2203  Real lo = -infinity;
2204  Real up = infinity;
2205 
2206  MSG_DEBUG((*spxout) << "IMAISM22 row " << i
2207  << ": singleton -> val=" << aij
2208  << " lhs=" << lp.lhs(i)
2209  << " rhs=" << lp.rhs(i);)
2210 
2211  if(GT(aij, 0.0, epsZero())) // aij > 0
2212  {
2213  lo = (lp.lhs(i) <= -infinity) ? -infinity : lp.lhs(i) / aij;
2214  up = (lp.rhs(i) >= infinity) ? infinity : lp.rhs(i) / aij;
2215  }
2216  else if(LT(aij, 0.0, epsZero())) // aij < 0
2217  {
2218  lo = (lp.rhs(i) >= infinity) ? -infinity : lp.rhs(i) / aij;
2219  up = (lp.lhs(i) <= -infinity) ? infinity : lp.lhs(i) / aij;
2220  }
2221  else if(LT(lp.rhs(i), 0.0, feastol()) || GT(lp.lhs(i), 0.0, feastol()))
2222  {
2223  // aij == 0, rhs < 0 or lhs > 0
2224  MSG_DEBUG((*spxout) << " infeasible" << std::endl;)
2225  return INFEASIBLE;
2226  }
2227 
2228  if(isZero(lo, epsZero()))
2229  lo = 0.0;
2230 
2231  if(isZero(up, epsZero()))
2232  up = 0.0;
2233 
2234  MSG_DEBUG((*spxout) << " removed, lower=" << lo
2235  << " (" << lp.lower(j)
2236  << ") upper=" << up
2237  << " (" << lp.upper(j)
2238  << ")" << std::endl;)
2239 
2240  bool stricterUp = false;
2241  bool stricterLo = false;
2242 
2243  Real oldLo = lp.lower(j);
2244  Real oldUp = lp.upper(j);
2245 
2246  if(LTrel(up, lp.upper(j), feastol()))
2247  {
2248  lp.changeUpper(j, up);
2249  stricterUp = true;
2250  }
2251 
2252  if(GTrel(lo, lp.lower(j), feastol()))
2253  {
2254  lp.changeLower(j, lo);
2255  stricterLo = true;
2256  }
2257 
2258  RowSingletonPS* RowSingletonPSptr = 0;
2259  spx_alloc(RowSingletonPSptr);
2260  m_hist.append(new(RowSingletonPSptr) RowSingletonPS(lp, i, j, stricterLo, stricterUp, lp.lower(j),
2261  lp.upper(j), oldLo, oldUp));
2262 
2263  removeRow(lp, i);
2264 
2265  m_remRows++;
2266  m_remNzos++;
2267  ++m_stat[SINGLETON_ROW];
2268 
2269  return OKAY;
2270 }
2271 
2272 /// aggregate variable x_j to x_j = (rhs - aik * x_k) / aij from row i: aij * x_j + aik * x_k = rhs
2274 {
2275  assert(row.size() == 2);
2276  assert(EQrel(lp.lhs(i), lp.rhs(i), feastol()));
2277 
2278  Real rhs = lp.rhs(i);
2279  assert(rhs < infinity && rhs > -infinity);
2280 
2281  int j = row.index(0);
2282  int k = row.index(1);
2283  Real aij = row.value(0);
2284  Real aik = row.value(1);
2285  Real lower_j = lp.lower(j);
2286  Real upper_j = lp.upper(j);
2287  Real lower_k = lp.lower(k);
2288  Real upper_k = lp.upper(k);
2289 
2290  // fixed variables should be removed by simplifyCols()
2291  if(EQrel(lower_j, upper_j, feastol()) || EQrel(lower_k, upper_k, feastol()))
2292  return OKAY;
2293 
2294  assert(isNotZero(aij, epsZero()) && isNotZero(aik, epsZero()));
2295 
2296  MSG_DEBUG((*spxout) << "IMAISM22 row " << i << ": doubleton equation -> "
2297  << aij << " x_" << j << " + " << aik << " x_" << k << " = " << rhs;)
2298 
2299  // determine which variable can be aggregated without requiring bound tightening of the other variable
2300  Real new_lo_j;
2301  Real new_up_j;
2302  Real new_lo_k;
2303  Real new_up_k;
2304 
2305  if(aij * aik < 0.0)
2306  {
2307  // orientation persists
2308  new_lo_j = (upper_k >= infinity) ? -infinity : (rhs - aik * upper_k) / aij;
2309  new_up_j = (lower_k <= -infinity) ? infinity : (rhs - aik * lower_k) / aij;
2310  new_lo_k = (upper_j >= infinity) ? -infinity : (rhs - aij * upper_j) / aik;
2311  new_up_k = (lower_j <= -infinity) ? infinity : (rhs - aij * lower_j) / aik;
2312  }
2313  else if(aij * aik > 0.0)
2314  {
2315  // orientation is reversed
2316  new_lo_j = (lower_k <= -infinity) ? -infinity : (rhs - aik * lower_k) / aij;
2317  new_up_j = (upper_k >= infinity) ? infinity : (rhs - aik * upper_k) / aij;
2318  new_lo_k = (lower_j <= -infinity) ? -infinity : (rhs - aij * lower_j) / aik;
2319  new_up_k = (upper_j >= infinity) ? infinity : (rhs - aij * upper_j) / aik;
2320  }
2321  else
2322  throw SPxInternalCodeException("XMAISM12 This should never happen.");
2323 
2324  bool flip_jk = false;
2325 
2326  if(new_lo_j <= -infinity && new_up_j >= infinity)
2327  {
2328  // no bound tightening on x_j when x_k is aggregated
2329  flip_jk = true;
2330  }
2331  else if(new_lo_k <= -infinity && new_up_k >= infinity)
2332  {
2333  // no bound tightening on x_k when x_j is aggregated
2334  flip_jk = false;
2335  }
2336  else if(LE(new_lo_j, lower_j) && GE(new_up_j, upper_j))
2337  {
2338  if(LE(new_lo_k, lower_k) && GE(new_up_k, upper_k))
2339  {
2340  // both variables' bounds are not affected by aggregation; choose the better aggregation coeff (aik/aij)
2341  if(spxAbs(aij) > spxAbs(aik))
2342  flip_jk = false;
2343  else
2344  flip_jk = true;
2345  }
2346  else
2347  flip_jk = false;
2348  }
2349  else if(LE(new_lo_k, lower_k) && GE(new_up_k, upper_k))
2350  {
2351  flip_jk = true;
2352  }
2353  else
2354  {
2355  if(spxAbs(aij) > spxAbs(aik))
2356  flip_jk = false;
2357  else
2358  flip_jk = true;
2359  }
2360 
2361  if(flip_jk)
2362  {
2363  int _j = j;
2364  Real _aij = aij;
2365  Real _lower_j = lower_j;
2366  Real _upper_j = upper_j;
2367  j = k;
2368  k = _j;
2369  aij = aik;
2370  aik = _aij;
2371  lower_j = lower_k;
2372  lower_k = _lower_j;
2373  upper_j = upper_k;
2374  upper_k = _upper_j;
2375  }
2376 
2377  const SVector& col_j = lp.colVector(j);
2378  const SVector& col_k = lp.colVector(k);
2379 
2380  // aggregation coefficients (x_j = aggr_coef * x_k + aggr_const)
2381  Real aggr_coef = - (aik / aij);
2382  Real aggr_const = rhs / aij;
2383 
2384  MSG_DEBUG((*spxout) << " removed, replacing x_" << j << " with "
2385  << aggr_const << " + " << aggr_coef << " * x_" << k << std::endl;)
2386 
2387  // replace all occurrences of x_j
2388  for(int r = 0; r < col_j.size(); ++r)
2389  {
2390  int row_r = col_j.index(r);
2391  Real arj = col_j.value(r);
2392 
2393  // skip row i
2394  if(row_r == i)
2395  continue;
2396 
2397  // adapt sides of row r
2398  Real lhs_r = lp.lhs(row_r);
2399  Real rhs_r = lp.rhs(row_r);
2400 
2401  if(lhs_r > -infinity)
2402  {
2403  lp.changeLhs(row_r, lhs_r - aggr_const * arj);
2404  m_chgLRhs++;
2405  }
2406 
2407  if(rhs_r < infinity)
2408  {
2409  lp.changeRhs(row_r, rhs_r - aggr_const * arj);
2410  m_chgLRhs++;
2411  }
2412 
2413  Real newcoef = aggr_coef * arj;
2414  int pos_rk = col_k.pos(row_r);
2415 
2416  // check whether x_k is also present in row r and get its coefficient
2417  if(pos_rk >= 0)
2418  {
2419  Real ark = col_k.value(pos_rk);
2420  newcoef += ark;
2421  m_remNzos++;
2422  }
2423 
2424  // add new column k to row r or adapt the coefficient a_rk
2425  lp.changeElement(row_r, k, newcoef);
2426  }
2427 
2428  // adapt objective function
2429  Real obj_j = lp.obj(j);
2430 
2431  if(isNotZero(obj_j, epsZero()))
2432  {
2433  addObjoffset(aggr_const * obj_j);
2434  Real obj_k = lp.obj(k);
2435  lp.changeObj(k, obj_k + aggr_coef * obj_j);
2436  }
2437 
2438  // adapt bounds of x_k
2439  Real scale1 = maxAbs(rhs, aij * upper_j);
2440  Real scale2 = maxAbs(rhs, aij * lower_j);
2441 
2442  if(scale1 < 1.0)
2443  scale1 = 1.0;
2444 
2445  if(scale2 < 1.0)
2446  scale2 = 1.0;
2447 
2448  Real z1 = (rhs / scale1) - (aij * upper_j / scale1);
2449  Real z2 = (rhs / scale2) - (aij * lower_j / scale2);
2450 
2451  // just some rounding
2452  if(isZero(z1, epsZero()))
2453  z1 = 0.0;
2454 
2455  if(isZero(z2, epsZero()))
2456  z2 = 0.0;
2457 
2458  // determine which side has to be used for the bounds comparison below
2459  if(aik * aij > 0.0)
2460  {
2461  new_lo_k = (upper_j >= infinity) ? -infinity : z1 * scale1 / aik;
2462  new_up_k = (lower_j <= -infinity) ? infinity : z2 * scale2 / aik;
2463  }
2464  else if(aik * aij < 0.0)
2465  {
2466  new_lo_k = (lower_j <= -infinity) ? -infinity : z2 * scale2 / aik;
2467  new_up_k = (upper_j >= infinity) ? infinity : z1 * scale1 / aik;
2468  }
2469  else
2470  throw SPxInternalCodeException("XMAISM12 This should never happen.");
2471 
2472  // change bounds of x_k if the new ones are tighter
2473  Real oldlower_k = lower_k;
2474  Real oldupper_k = upper_k;
2475 
2476  if(GT(new_lo_k, lower_k, epsZero()))
2477  {
2478  lp.changeLower(k, new_lo_k);
2479  m_chgBnds++;
2480  }
2481 
2482  if(LT(new_up_k, upper_k, epsZero()))
2483  {
2484  lp.changeUpper(k, new_up_k);
2485  m_chgBnds++;
2486  }
2487 
2488  AggregationPS* AggregationPSptr = 0;
2489  spx_alloc(AggregationPSptr);
2490  m_hist.append(new(AggregationPSptr) AggregationPS(lp, i, j, rhs, oldupper_k, oldlower_k));
2491 
2492  removeRow(lp, i);
2493  removeCol(lp, j);
2494 
2495  m_remRows++;
2496  m_remCols++;
2497  m_remNzos += 2;
2498 
2499  ++m_stat[AGGREGATION];
2500 
2501  return OKAY;
2502 }
2503 
2505 {
2506 
2507  // This method simplifies the rows of the LP.
2508  //
2509  // The following operations are done:
2510  // 1. detect implied free variables
2511  // 2. detect implied free constraints
2512  // 3. detect infeasible constraints
2513  // 4. remove unconstrained constraints
2514  // 5. remove empty constraints
2515  // 6. remove row singletons and tighten the corresponding variable bounds if necessary
2516  // 7. remove doubleton equation, aka aggregation
2517  // 8. detect forcing rows and fix the corresponding variables
2518 
2519  int remRows = 0;
2520  int remNzos = 0;
2521  int chgLRhs = 0;
2522  int chgBnds = 0;
2523  int keptBnds = 0;
2524  int keptLRhs = 0;
2525 
2526  int oldRows = lp.nRows();
2527 
2528  bool redundantLower;
2529  bool redundantUpper;
2530  bool redundantLhs;
2531  bool redundantRhs;
2532 
2533  for(int i = lp.nRows() - 1; i >= 0; --i)
2534  {
2535  const SVector& row = lp.rowVector(i);
2536 
2537 
2538  // compute bounds on constraint value
2539  Real lhsBnd = 0.0; // minimal activity (finite summands)
2540  Real rhsBnd = 0.0; // maximal activity (finite summands)
2541  int lhsCnt = 0; // number of -infinity summands in minimal activity
2542  int rhsCnt = 0; // number of +infinity summands in maximal activity
2543 
2544  for(int k = 0; k < row.size(); ++k)
2545  {
2546  Real aij = row.value(k);
2547  int j = row.index(k);
2548 
2549  if(!isNotZero(aij, 1.0 / infinity))
2550  {
2551  MSG_WARNING((*spxout), (*spxout) << "Warning: tiny nonzero coefficient " << aij << " in row " << i
2552  << "\n");
2553  }
2554 
2555  if(aij > 0.0)
2556  {
2557  if(lp.lower(j) <= -infinity)
2558  ++lhsCnt;
2559  else
2560  lhsBnd += aij * lp.lower(j);
2561 
2562  if(lp.upper(j) >= infinity)
2563  ++rhsCnt;
2564  else
2565  rhsBnd += aij * lp.upper(j);
2566  }
2567  else if(aij < 0.0)
2568  {
2569  if(lp.lower(j) <= -infinity)
2570  ++rhsCnt;
2571  else
2572  rhsBnd += aij * lp.lower(j);
2573 
2574  if(lp.upper(j) >= infinity)
2575  ++lhsCnt;
2576  else
2577  lhsBnd += aij * lp.upper(j);
2578  }
2579  }
2580 
2581 #if FREE_BOUNDS
2582 
2583  // 1. detect implied free variables
2584  if(rhsCnt <= 1 || lhsCnt <= 1)
2585  {
2586  for(int k = 0; k < row.size(); ++k)
2587  {
2588  Real aij = row.value(k);
2589  int j = row.index(k);
2590 
2591  redundantLower = false;
2592  redundantUpper = false;
2593 
2594  ASSERT_WARN("WMAISM12", isNotZero(aij, 1.0 / infinity));
2595 
2596  if(aij > 0.0)
2597  {
2598  if(lp.lhs(i) > -infinity && lp.lower(j) > -infinity && rhsCnt <= 1
2599  && NErel(lp.lhs(i), rhsBnd, feastol())
2600  // do not perform if strongly different orders of magnitude occur
2601  && spxAbs(lp.lhs(i) / maxAbs(rhsBnd, 1.0)) > Param::epsilon())
2602  {
2603  Real lo = -infinity;
2604  Real scale = maxAbs(lp.lhs(i), rhsBnd);
2605 
2606  if(scale < 1.0)
2607  scale = 1.0;
2608 
2609  Real z = (lp.lhs(i) / scale) - (rhsBnd / scale);
2610 
2611  if(isZero(z, epsZero()))
2612  z = 0.0;
2613 
2614  assert(rhsCnt > 0 || lp.upper(j) < infinity);
2615 
2616  if(rhsCnt == 0)
2617  lo = lp.upper(j) + z * scale / aij;
2618  else if(lp.upper(j) >= infinity)
2619  lo = z * scale / aij;
2620 
2621  if(isZero(lo, epsZero()))
2622  lo = 0.0;
2623 
2624  if(GErel(lo, lp.lower(j), feastol()))
2625  {
2626  MSG_DEBUG((*spxout) << "IMAISM13 row " << i
2627  << ": redundant lower bound on x" << j
2628  << " -> lower=" << lo
2629  << " (" << lp.lower(j)
2630  << ")" << std::endl;)
2631 
2632  redundantLower = true;
2633  }
2634 
2635  }
2636 
2637  if(lp.rhs(i) < infinity && lp.upper(j) < infinity && lhsCnt <= 1
2638  && NErel(lp.rhs(i), lhsBnd, feastol())
2639  // do not perform if strongly different orders of magnitude occur
2640  && spxAbs(lp.rhs(i) / maxAbs(lhsBnd, 1.0)) > Param::epsilon())
2641  {
2642  Real up = infinity;
2643  Real scale = maxAbs(lp.rhs(i), lhsBnd);
2644 
2645  if(scale < 1.0)
2646  scale = 1.0;
2647 
2648  Real z = (lp.rhs(i) / scale) - (lhsBnd / scale);
2649 
2650  if(isZero(z, epsZero()))
2651  z = 0.0;
2652 
2653  assert(lhsCnt > 0 || lp.lower(j) > -infinity);
2654 
2655  if(lhsCnt == 0)
2656  up = lp.lower(j) + z * scale / aij;
2657  else if(lp.lower(j) <= -infinity)
2658  up = z * scale / aij;
2659 
2660  if(isZero(up, epsZero()))
2661  up = 0.0;
2662 
2663  if(LErel(up, lp.upper(j), feastol()))
2664  {
2665  MSG_DEBUG((*spxout) << "IMAISM14 row " << i
2666  << ": redundant upper bound on x" << j
2667  << " -> upper=" << up
2668  << " (" << lp.upper(j)
2669  << ")" << std::endl;)
2670 
2671  redundantUpper = true;
2672  }
2673  }
2674 
2675  if(redundantLower)
2676  {
2677  // no upper bound on x_j OR redundant upper bound
2678  if((lp.upper(j) >= infinity) || redundantUpper || (!m_keepbounds))
2679  {
2680  ++lhsCnt;
2681  lhsBnd -= aij * lp.lower(j);
2682 
2683  lp.changeLower(j, -infinity);
2684  ++chgBnds;
2685  }
2686  else
2687  ++keptBnds;
2688  }
2689 
2690  if(redundantUpper)
2691  {
2692  // no lower bound on x_j OR redundant lower bound
2693  if((lp.lower(j) <= -infinity) || redundantLower || (!m_keepbounds))
2694  {
2695  ++rhsCnt;
2696  rhsBnd -= aij * lp.upper(j);
2697 
2698  lp.changeUpper(j, infinity);
2699  ++chgBnds;
2700  }
2701  else
2702  ++keptBnds;
2703  }
2704  }
2705  else if(aij < 0.0)
2706  {
2707  if(lp.lhs(i) > -infinity && lp.upper(j) < infinity && rhsCnt <= 1
2708  && NErel(lp.lhs(i), rhsBnd, feastol())
2709  // do not perform if strongly different orders of magnitude occur
2710  && spxAbs(lp.lhs(i) / maxAbs(rhsBnd, 1.0)) > Param::epsilon())
2711  {
2712  Real up = infinity;
2713  Real scale = maxAbs(lp.lhs(i), rhsBnd);
2714 
2715  if(scale < 1.0)
2716  scale = 1.0;
2717 
2718  Real z = (lp.lhs(i) / scale) - (rhsBnd / scale);
2719 
2720  if(isZero(z, epsZero()))
2721  z = 0.0;
2722 
2723  assert(rhsCnt > 0 || lp.lower(j) > -infinity);
2724 
2725  if(rhsCnt == 0)
2726  up = lp.lower(j) + z * scale / aij;
2727  else if(lp.lower(j) <= -infinity)
2728  up = z * scale / aij;
2729 
2730  if(isZero(up, epsZero()))
2731  up = 0.0;
2732 
2733  if(LErel(up, lp.upper(j), feastol()))
2734  {
2735  MSG_DEBUG((*spxout) << "IMAISM15 row " << i
2736  << ": redundant upper bound on x" << j
2737  << " -> upper=" << up
2738  << " (" << lp.upper(j)
2739  << ")" << std::endl;)
2740 
2741  redundantUpper = true;
2742  }
2743  }
2744 
2745  if(lp.rhs(i) < infinity && lp.lower(j) > -infinity && lhsCnt <= 1
2746  && NErel(lp.rhs(i), lhsBnd, feastol())
2747  // do not perform if strongly different orders of magnitude occur
2748  && spxAbs(lp.rhs(i) / maxAbs(lhsBnd, 1.0)) > Param::epsilon())
2749  {
2750  Real lo = -infinity;
2751  Real scale = maxAbs(lp.rhs(i), lhsBnd);
2752 
2753  if(scale < 1.0)
2754  scale = 1.0;
2755 
2756  Real z = (lp.rhs(i) / scale) - (lhsBnd / scale);
2757 
2758  if(isZero(z, epsZero()))
2759  z = 0.0;
2760 
2761  assert(lhsCnt > 0 || lp.upper(j) < infinity);
2762 
2763  if(lhsCnt == 0)
2764  lo = lp.upper(j) + z * scale / aij;
2765  else if(lp.upper(j) >= infinity)
2766  lo = z * scale / aij;
2767 
2768  if(isZero(lo, epsZero()))
2769  lo = 0.0;
2770 
2771  if(GErel(lo, lp.lower(j)))
2772  {
2773  MSG_DEBUG((*spxout) << "IMAISM16 row " << i
2774  << ": redundant lower bound on x" << j
2775  << " -> lower=" << lo
2776  << " (" << lp.lower(j)
2777  << ")" << std::endl;)
2778 
2779  redundantLower = true;
2780  }
2781  }
2782 
2783  if(redundantUpper)
2784  {
2785  // no lower bound on x_j OR redundant lower bound
2786  if((lp.lower(j) <= -infinity) || redundantLower || (!m_keepbounds))
2787  {
2788  ++lhsCnt;
2789  lhsBnd -= aij * lp.upper(j);
2790 
2791  lp.changeUpper(j, infinity);
2792  ++chgBnds;
2793  }
2794  else
2795  ++keptBnds;
2796  }
2797 
2798  if(redundantLower)
2799  {
2800  // no upper bound on x_j OR redundant upper bound
2801  if((lp.upper(j) >= infinity) || redundantUpper || (!m_keepbounds))
2802  {
2803  ++rhsCnt;
2804  rhsBnd -= aij * lp.lower(j);
2805 
2806  lp.changeLower(j, -infinity);
2807  ++chgBnds;
2808  }
2809  else
2810  ++keptBnds;
2811  }
2812  }
2813  }
2814  }
2815 
2816 #endif
2817 
2818 #if FREE_LHS_RHS
2819 
2820  redundantLhs = false;
2821  redundantRhs = false;
2822 
2823  // 2. detect implied free constraints
2824  if(lp.lhs(i) > -infinity && lhsCnt == 0 && GErel(lhsBnd, lp.lhs(i), feastol()))
2825  {
2826  MSG_DEBUG((*spxout) << "IMAISM17 row " << i
2827  << ": redundant lhs -> lhsBnd=" << lhsBnd
2828  << " lhs=" << lp.lhs(i)
2829  << std::endl;)
2830 
2831  redundantLhs = true;
2832  }
2833 
2834  if(lp.rhs(i) < infinity && rhsCnt == 0 && LErel(rhsBnd, lp.rhs(i), feastol()))
2835  {
2836  MSG_DEBUG((*spxout) << "IMAISM18 row " << i
2837  << ": redundant rhs -> rhsBnd=" << rhsBnd
2838  << " rhs=" << lp.rhs(i)
2839  << std::endl;)
2840 
2841  redundantRhs = true;
2842  }
2843 
2844  if(redundantLhs)
2845  {
2846  // no rhs for constraint i OR redundant rhs
2847  if((lp.rhs(i) >= infinity) || redundantRhs || (!m_keepbounds))
2848  {
2849  lp.changeLhs(i, -infinity);
2850  ++chgLRhs;
2851  }
2852  else
2853  ++keptLRhs;
2854  }
2855 
2856  if(redundantRhs)
2857  {
2858  // no lhs for constraint i OR redundant lhs
2859  if((lp.lhs(i) <= -infinity) || redundantLhs || (!m_keepbounds))
2860  {
2861  lp.changeRhs(i, infinity);
2862  ++chgLRhs;
2863  }
2864  else
2865  ++keptLRhs;
2866  }
2867 
2868 #endif
2869 
2870  // 3. infeasible constraint
2871  if(LTrel(lp.rhs(i), lp.lhs(i), feastol()) ||
2872  (LTrel(rhsBnd, lp.lhs(i), feastol()) && rhsCnt == 0) ||
2873  (GTrel(lhsBnd, lp.rhs(i), feastol()) && lhsCnt == 0))
2874  {
2875  MSG_DEBUG((*spxout) << "IMAISM19 row " << std::setprecision(20) << i
2876  << ": infeasible -> lhs=" << lp.lhs(i)
2877  << " rhs=" << lp.rhs(i)
2878  << " lhsBnd=" << lhsBnd
2879  << " rhsBnd=" << rhsBnd
2880  << std::endl;)
2881  return INFEASIBLE;
2882  }
2883 
2884 #if FREE_CONSTRAINT
2885 
2886  // 4. unconstrained constraint
2887  if(lp.lhs(i) <= -infinity && lp.rhs(i) >= infinity)
2888  {
2889  MSG_DEBUG((*spxout) << "IMAISM20 row " << i
2890  << ": unconstrained -> removed" << std::endl;)
2891 
2892  FreeConstraintPS* FreeConstraintPSptr = 0;
2893  spx_alloc(FreeConstraintPSptr);
2894  m_hist.append(new(FreeConstraintPSptr) FreeConstraintPS(lp, i));
2895 
2896  ++remRows;
2897  remNzos += row.size();
2898  removeRow(lp, i);
2899 
2900  ++m_stat[FREE_ROW];
2901 
2902  continue;
2903  }
2904 
2905 #endif
2906 
2907 #if EMPTY_CONSTRAINT
2908 
2909  // 5. empty constraint
2910  if(row.size() == 0)
2911  {
2912  MSG_DEBUG((*spxout) << "IMAISM21 row " << i
2913  << ": empty ->";)
2914 
2915  if(LT(lp.rhs(i), 0.0, feastol()) || GT(lp.lhs(i), 0.0, feastol()))
2916  {
2917  MSG_DEBUG((*spxout) << " infeasible lhs=" << lp.lhs(i)
2918  << " rhs=" << lp.rhs(i) << std::endl;)
2919  return INFEASIBLE;
2920  }
2921 
2922  MSG_DEBUG((*spxout) << " removed" << std::endl;)
2923 
2924  EmptyConstraintPS* EmptyConstraintPSptr = 0;
2925  spx_alloc(EmptyConstraintPSptr);
2926  m_hist.append(new(EmptyConstraintPSptr) EmptyConstraintPS(lp, i));
2927 
2928  ++remRows;
2929  removeRow(lp, i);
2930 
2931  ++m_stat[EMPTY_ROW];
2932 
2933  continue;
2934  }
2935 
2936 #endif
2937 
2938 #if ROW_SINGLETON
2939 
2940  // 6. row singleton
2941  if(row.size() == 1)
2942  {
2943  removeRowSingleton(lp, row, i);
2944  continue;
2945  }
2946 
2947 #endif
2948 
2949 #if AGGREGATE_VARS
2950 
2951  // 7. row doubleton, aka. simple aggregation of two variables in an equation
2952  if(row.size() == 2 && EQrel(lp.lhs(i), lp.rhs(i), feastol()))
2953  {
2954  aggregateVars(lp, row, i);
2955  continue;
2956  }
2957 
2958 #endif
2959 
2960 #if FORCE_CONSTRAINT
2961 
2962  // 8. forcing constraint (postsolving)
2963  // fix variables to obtain the upper bound on constraint value
2964  if(rhsCnt == 0 && EQrel(rhsBnd, lp.lhs(i), feastol()))
2965  {
2966  MSG_DEBUG((*spxout) << "IMAISM24 row " << i
2967  << ": forcing constraint fix on lhs ->"
2968  << " lhs=" << lp.lhs(i)
2969  << " rhsBnd=" << rhsBnd
2970  << std::endl;)
2971 
2972  DataArray<bool> fixedCol(row.size());
2973  DataArray<Real> lowers(row.size());
2974  DataArray<Real> uppers(row.size());
2975 
2976  for(int k = 0; k < row.size(); ++k)
2977  {
2978  Real aij = row.value(k);
2979  int j = row.index(k);
2980 
2981  fixedCol[k] = !(EQrel(lp.upper(j), lp.lower(j), m_epsilon));
2982 
2983  lowers[k] = lp.lower(j);
2984  uppers[k] = lp.upper(j);
2985 
2986  ASSERT_WARN("WMAISM25", isNotZero(aij, 1.0 / infinity));
2987 
2988  if(aij > 0.0)
2989  lp.changeLower(j, lp.upper(j));
2990  else
2991  lp.changeUpper(j, lp.lower(j));
2992  }
2993 
2994  ForceConstraintPS* ForceConstraintPSptr = 0;
2995  spx_alloc(ForceConstraintPSptr);
2996  m_hist.append(new(ForceConstraintPSptr) ForceConstraintPS(lp, i, true, fixedCol, lowers, uppers));
2997 
2998  ++remRows;
2999  remNzos += row.size();
3000  removeRow(lp, i);
3001 
3002  ++m_stat[FORCE_ROW];
3003 
3004  continue;
3005  }
3006 
3007  // fix variables to obtain the lower bound on constraint value
3008  if(lhsCnt == 0 && EQrel(lhsBnd, lp.rhs(i), feastol()))
3009  {
3010  MSG_DEBUG((*spxout) << "IMAISM26 row " << i
3011  << ": forcing constraint fix on rhs ->"
3012  << " rhs=" << lp.rhs(i)
3013  << " lhsBnd=" << lhsBnd
3014  << std::endl;)
3015 
3016  DataArray<bool> fixedCol(row.size());
3017  DataArray<Real> lowers(row.size());
3018  DataArray<Real> uppers(row.size());
3019 
3020  for(int k = 0; k < row.size(); ++k)
3021  {
3022  Real aij = row.value(k);
3023  int j = row.index(k);
3024 
3025  fixedCol[k] = !(EQrel(lp.upper(j), lp.lower(j), m_epsilon));
3026 
3027  lowers[k] = lp.lower(j);
3028  uppers[k] = lp.upper(j);
3029 
3030  ASSERT_WARN("WMAISM27", isNotZero(aij, 1.0 / infinity));
3031 
3032  if(aij > 0.0)
3033  lp.changeUpper(j, lp.lower(j));
3034  else
3035  lp.changeLower(j, lp.upper(j));
3036  }
3037 
3038  ForceConstraintPS* ForceConstraintPSptr = 0;
3039  spx_alloc(ForceConstraintPSptr);
3040  m_hist.append(new(ForceConstraintPSptr) ForceConstraintPS(lp, i, false, fixedCol, lowers, uppers));
3041 
3042  ++remRows;
3043  remNzos += row.size();
3044  removeRow(lp, i);
3045 
3046  ++m_stat[FORCE_ROW];
3047 
3048  continue;
3049  }
3050 
3051 #endif
3052  }
3053 
3054  assert(remRows > 0 || remNzos == 0);
3055 
3056  if(remRows + chgLRhs + chgBnds > 0)
3057  {
3058  m_remRows += remRows;
3059  m_remNzos += remNzos;
3060  m_chgLRhs += chgLRhs;
3061  m_chgBnds += chgBnds;
3062  m_keptBnds += keptBnds;
3063  m_keptLRhs += keptLRhs;
3064 
3065  MSG_INFO2((*spxout), (*spxout) << "Simplifier (rows) removed "
3066  << remRows << " rows, "
3067  << remNzos << " non-zeros, "
3068  << chgBnds << " col bounds, "
3069  << chgLRhs << " row bounds; kept "
3070  << keptBnds << " column bounds, "
3071  << keptLRhs << " row bounds"
3072  << std::endl;)
3073 
3074  if(remRows > m_minReduction * oldRows)
3075  again = true;
3076  }
3077 
3078  return OKAY;
3079 }
3080 
3082 {
3083 
3084  // This method simplifies the columns of the LP.
3085  //
3086  // The following operations are done:
3087  // 1. detect empty columns and fix corresponding variables
3088  // 2. detect variables that are unconstrained from below or above
3089  // and fix corresponding variables or remove involved constraints
3090  // 3. fix variables
3091  // 4. use column singleton variables with zero objective to adjust constraint bounds
3092  // 5. (not free) column singleton combined with doubleton equation are
3093  // used to make the column singleton variable free
3094  // 6. substitute (implied) free column singletons
3095 
3096  int remRows = 0;
3097  int remCols = 0;
3098  int remNzos = 0;
3099  int chgBnds = 0;
3100 
3101  int oldCols = lp.nCols();
3102  int oldRows = lp.nRows();
3103 
3104  for(int j = lp.nCols() - 1; j >= 0; --j)
3105  {
3106  const SVector& col = lp.colVector(j);
3107 
3108  // infeasible bounds
3109  if(GTrel(lp.lower(j), lp.upper(j), feastol()))
3110  {
3111  MSG_DEBUG((*spxout) << "IMAISM29 col " << j
3112  << ": infeasible bounds on x" << j
3113  << " -> lower=" << lp.lower(j)
3114  << " upper=" << lp.upper(j)
3115  << std::endl;)
3116  return INFEASIBLE;
3117  }
3118 
3119  // 1. empty column
3120  if(col.size() == 0)
3121  {
3122 #if EMPTY_COLUMN
3123  MSG_DEBUG((*spxout) << "IMAISM30 col " << j
3124  << ": empty -> maxObj=" << lp.maxObj(j)
3125  << " lower=" << lp.lower(j)
3126  << " upper=" << lp.upper(j);)
3127 
3128  Real val;
3129 
3130  if(GT(lp.maxObj(j), 0.0, epsZero()))
3131  {
3132  if(lp.upper(j) >= infinity)
3133  {
3134  MSG_DEBUG((*spxout) << " unbounded" << std::endl;)
3135  return UNBOUNDED;
3136  }
3137 
3138  val = lp.upper(j);
3139  }
3140  else if(LT(lp.maxObj(j), 0.0, epsZero()))
3141  {
3142  if(lp.lower(j) <= -infinity)
3143  {
3144  MSG_DEBUG((*spxout) << " unbounded" << std::endl;)
3145  return UNBOUNDED;
3146  }
3147 
3148  val = lp.lower(j);
3149  }
3150  else
3151  {
3152  assert(isZero(lp.maxObj(j), epsZero()));
3153 
3154  // any value within the bounds is ok
3155  if(lp.lower(j) > -infinity)
3156  val = lp.lower(j);
3157  else if(lp.upper(j) < infinity)
3158  val = lp.upper(j);
3159  else
3160  val = 0.0;
3161  }
3162 
3163  MSG_DEBUG((*spxout) << " removed" << std::endl;)
3164 
3165  FixBoundsPS* FixBoundsPSptr = 0;
3166  FixVariablePS* FixVariablePSptr = 0;
3167  spx_alloc(FixBoundsPSptr);
3168  spx_alloc(FixVariablePSptr);
3169  m_hist.append(new(FixBoundsPSptr) FixBoundsPS(lp, j, val));
3170  m_hist.append(new(FixVariablePSptr) FixVariablePS(lp, *this, j, val));
3171 
3172  ++remCols;
3173  removeCol(lp, j);
3174 
3175  ++m_stat[EMPTY_COL];
3176 
3177  continue;
3178 #endif
3179  }
3180 
3181  if(NErel(lp.lower(j), lp.upper(j), feastol()))
3182  {
3183  // will be set to false if any constraint implies a bound on the variable
3184  bool loFree = true;
3185  bool upFree = true;
3186 
3187  // 1. fix and remove variables
3188  for(int k = 0; k < col.size(); ++k)
3189  {
3190  if(!loFree && !upFree)
3191  break;
3192 
3193  int i = col.index(k);
3194 
3195  // warn since this unhandled case may slip through unnoticed otherwise
3196  ASSERT_WARN("WMAISM31", isNotZero(col.value(k), 1.0 / infinity));
3197 
3198  if(col.value(k) > 0.0)
3199  {
3200  if(lp.rhs(i) < infinity)
3201  upFree = false;
3202 
3203  if(lp.lhs(i) > -infinity)
3204  loFree = false;
3205  }
3206  else if(col.value(k) < 0.0)
3207  {
3208  if(lp.rhs(i) < infinity)
3209  loFree = false;
3210 
3211  if(lp.lhs(i) > -infinity)
3212  upFree = false;
3213  }
3214  }
3215 
3216  // 2. detect variables that are unconstrained from below or above
3217  // max 3 x
3218  // s.t. 5 x >= 8
3219  if(GT(lp.maxObj(j), 0.0, epsZero()) && upFree)
3220  {
3221 #if FIX_VARIABLE
3222  MSG_DEBUG((*spxout) << "IMAISM32 col " << j
3223  << ": x" << j
3224  << " unconstrained above ->";)
3225 
3226  if(lp.upper(j) >= infinity)
3227  {
3228  MSG_DEBUG((*spxout) << " unbounded" << std::endl;)
3229 
3230  return UNBOUNDED;
3231  }
3232 
3233  MSG_DEBUG((*spxout) << " fixed at upper=" << lp.upper(j) << std::endl;)
3234 
3235  FixBoundsPS* FixBoundsPSptr = 0;
3236  spx_alloc(FixBoundsPSptr);
3237  m_hist.append(new(FixBoundsPSptr) FixBoundsPS(lp, j, lp.upper(j)));
3238  lp.changeLower(j, lp.upper(j));
3239  }
3240  // max -3 x
3241  // s.t. 5 x <= 8
3242  else if(LT(lp.maxObj(j), 0.0, epsZero()) && loFree)
3243  {
3244  MSG_DEBUG((*spxout) << "IMAISM33 col " << j
3245  << ": x" << j
3246  << " unconstrained below ->";)
3247 
3248  if(lp.lower(j) <= -infinity)
3249  {
3250  MSG_DEBUG((*spxout) << " unbounded" << std::endl;)
3251 
3252  return UNBOUNDED;
3253  }
3254 
3255  MSG_DEBUG((*spxout) << " fixed at lower=" << lp.lower(j) << std::endl;)
3256 
3257  FixBoundsPS* FixBoundsPSptr = 0;
3258  spx_alloc(FixBoundsPSptr);
3259  m_hist.append(new(FixBoundsPSptr) FixBoundsPS(lp, j, lp.lower(j)));
3260  lp.changeUpper(j, lp.lower(j));
3261 #endif
3262  }
3263  else if(isZero(lp.maxObj(j), epsZero()))
3264  {
3265 #if FREE_ZERO_OBJ_VARIABLE
3266  bool unconstrained_below = loFree && lp.lower(j) <= -infinity;
3267  bool unconstrained_above = upFree && lp.upper(j) >= infinity;
3268 
3269  if(unconstrained_below || unconstrained_above)
3270  {
3271  MSG_DEBUG((*spxout) << "IMAISM34 col " << j
3272  << ": x" << j
3273  << " unconstrained "
3274  << (unconstrained_below ? "below" : "above")
3275  << " with zero objective (" << lp.maxObj(j)
3276  << ")" << std::endl;)
3277 
3278  SVector col_idx_sorted(col);
3279 
3280  // sort col elements by increasing idx
3281  IdxCompare compare;
3282  SPxQuicksort(col_idx_sorted.mem(), col_idx_sorted.size(), compare);
3283 
3284  FreeZeroObjVariablePS* FreeZeroObjVariablePSptr = 0;
3285  spx_alloc(FreeZeroObjVariablePSptr);
3286  m_hist.append(new(FreeZeroObjVariablePSptr) FreeZeroObjVariablePS(lp, j, unconstrained_below,
3287  col_idx_sorted));
3288 
3289  // we have to remove the rows with larger idx first, because otherwise the rows are reorder and indices
3290  // are out-of-date
3291  remRows += col.size();
3292 
3293  for(int k = col_idx_sorted.size() - 1; k >= 0; --k)
3294  removeRow(lp, col_idx_sorted.index(k));
3295 
3296  // remove column
3297  removeCol(lp, j);
3298 
3299  // statistics
3300  for(int k = 0; k < col.size(); ++k)
3301  {
3302  int l = col.index(k);
3303  remNzos += lp.rowVector(l).size();
3304  }
3305 
3306  ++m_stat[FREE_ZOBJ_COL];
3307  ++remCols;
3308 
3309  continue;
3310  }
3311 
3312 #endif
3313  }
3314  }
3315 
3316 #if FIX_VARIABLE
3317 
3318  // 3. fix variable
3319  if(EQrel(lp.lower(j), lp.upper(j), feastol()))
3320  {
3321  MSG_DEBUG((*spxout) << "IMAISM36 col " << j
3322  << ": x" << j
3323  << " fixed -> lower=" << lp.lower(j)
3324  << " upper=" << lp.upper(j) << std::endl;)
3325 
3326  fixColumn(lp, j);
3327 
3328  ++remCols;
3329  remNzos += col.size();
3330  removeCol(lp, j);
3331 
3332  ++m_stat[FIX_COL];
3333 
3334  continue;
3335  }
3336 
3337 #endif
3338 
3339  // handle column singletons
3340  if(col.size() == 1)
3341  {
3342  Real aij = col.value(0);
3343  int i = col.index(0);
3344 
3345  // 4. column singleton with zero objective
3346  if(isZero(lp.maxObj(j), epsZero()))
3347  {
3348 #if ZERO_OBJ_COL_SINGLETON
3349  MSG_DEBUG((*spxout) << "IMAISM37 col " << j
3350  << ": singleton in row " << i
3351  << " with zero objective";)
3352 
3353  Real lhs = -infinity;
3354  Real rhs = +infinity;
3355 
3356  if(GT(aij, 0.0, epsZero()))
3357  {
3358  if(lp.lhs(i) > -infinity && lp.upper(j) < infinity)
3359  lhs = lp.lhs(i) - aij * lp.upper(j);
3360 
3361  if(lp.rhs(i) < infinity && lp.lower(j) > -infinity)
3362  rhs = lp.rhs(i) - aij * lp.lower(j);
3363  }
3364  else if(LT(aij, 0.0, epsZero()))
3365  {
3366  if(lp.lhs(i) > -infinity && lp.lower(j) > -infinity)
3367  lhs = lp.lhs(i) - aij * lp.lower(j);
3368 
3369  if(lp.rhs(i) < infinity && lp.upper(j) < infinity)
3370  rhs = lp.rhs(i) - aij * lp.upper(j);
3371  }
3372  else
3373  {
3374  lhs = lp.lhs(i);
3375  rhs = lp.rhs(i);
3376  }
3377 
3378  if(isZero(lhs, epsZero()))
3379  lhs = 0.0;
3380 
3381  if(isZero(rhs, epsZero()))
3382  rhs = 0.0;
3383 
3384  MSG_DEBUG((*spxout) << " removed -> lhs=" << lhs
3385  << " (" << lp.lhs(i)
3386  << ") rhs=" << rhs
3387  << " (" << lp.rhs(i)
3388  << ")" << std::endl;)
3389 
3390  ZeroObjColSingletonPS* ZeroObjColSingletonPSptr = 0;
3391  spx_alloc(ZeroObjColSingletonPSptr);
3392  m_hist.append(new(ZeroObjColSingletonPSptr) ZeroObjColSingletonPS(lp, *this, j, i));
3393 
3394  lp.changeRange(i, lhs, rhs);
3395 
3396  ++remCols;
3397  ++remNzos;
3398  removeCol(lp, j);
3399 
3401 
3402  if(lp.lhs(i) <= -infinity && lp.rhs(i) >= infinity)
3403  {
3404  FreeConstraintPS* FreeConstraintPSptr = 0;
3405  spx_alloc(FreeConstraintPSptr);
3406  m_hist.append(new(FreeConstraintPSptr) FreeConstraintPS(lp, i));
3407 
3408  ++remRows;
3409  removeRow(lp, i);
3410 
3411  ++m_stat[FREE_ROW];
3412  }
3413 
3414  continue;
3415 #endif
3416  }
3417 
3418  // 5. not free column singleton combined with doubleton equation
3419  else if(EQrel(lp.lhs(i), lp.rhs(i), feastol()) &&
3420  lp.rowVector(i).size() == 2 &&
3421  (lp.lower(j) > -infinity || lp.upper(j) < infinity))
3422  {
3423 #if DOUBLETON_EQUATION
3424  MSG_DEBUG((*spxout) << "IMAISM38 col " << j
3425  << ": singleton in row " << i
3426  << " with doubleton equation ->";)
3427 
3428  Real lhs = lp.lhs(i);
3429 
3430  const SVector& row = lp.rowVector(i);
3431 
3432  Real aik;
3433  int k;
3434 
3435  if(row.index(0) == j)
3436  {
3437  aik = row.value(1);
3438  k = row.index(1);
3439  }
3440  else if(row.index(1) == j)
3441  {
3442  aik = row.value(0);
3443  k = row.index(0);
3444  }
3445  else
3446  throw SPxInternalCodeException("XMAISM11 This should never happen.");
3447 
3448  ASSERT_WARN("WMAISM39", isNotZero(aik, 1.0 / infinity));
3449 
3450  Real lo, up;
3451  Real oldLower = lp.lower(k);
3452  Real oldUpper = lp.upper(k);
3453 
3454  Real scale1 = maxAbs(lhs, aij * lp.upper(j));
3455  Real scale2 = maxAbs(lhs, aij * lp.lower(j));
3456 
3457  if(scale1 < 1.0)
3458  scale1 = 1.0;
3459 
3460  if(scale2 < 1.0)
3461  scale2 = 1.0;
3462 
3463  Real z1 = (lhs / scale1) - (aij * lp.upper(j) / scale1);
3464  Real z2 = (lhs / scale2) - (aij * lp.lower(j) / scale2);
3465 
3466  if(isZero(z1, epsZero()))
3467  z1 = 0.0;
3468 
3469  if(isZero(z2, epsZero()))
3470  z2 = 0.0;
3471 
3472  if(aij * aik > 0.0)
3473  {
3474  lo = (lp.upper(j) >= infinity) ? -infinity : z1 * scale1 / aik;
3475  up = (lp.lower(j) <= -infinity) ? infinity : z2 * scale2 / aik;
3476  }
3477  else if(aij * aik < 0.0)
3478  {
3479  lo = (lp.lower(j) <= -infinity) ? -infinity : z2 * scale2 / aik;
3480  up = (lp.upper(j) >= infinity) ? infinity : z1 * scale1 / aik;
3481  }
3482  else
3483  throw SPxInternalCodeException("XMAISM12 This should never happen.");
3484 
3485  if(GTrel(lo, lp.lower(k), epsZero()))
3486  lp.changeLower(k, lo);
3487 
3488  if(LTrel(up, lp.upper(k), epsZero()))
3489  lp.changeUpper(k, up);
3490 
3491  MSG_DEBUG((*spxout) << " made free, bounds on x" << k
3492  << ": lower=" << lp.lower(k)
3493  << " (" << oldLower
3494  << ") upper=" << lp.upper(k)
3495  << " (" << oldUpper
3496  << ")" << std::endl;)
3497 
3498  // infeasible bounds
3499  if(GTrel(lp.lower(k), lp.upper(k), feastol()))
3500  {
3501  MSG_DEBUG((*spxout) << "new bounds are infeasible"
3502  << std::endl;)
3503  return INFEASIBLE;
3504  }
3505 
3506  DoubletonEquationPS* DoubletonEquationPSptr = 0;
3507  spx_alloc(DoubletonEquationPSptr);
3508  m_hist.append(new(DoubletonEquationPSptr) DoubletonEquationPS(lp, j, k, i, oldLower, oldUpper));
3509 
3510  if(lp.lower(j) > -infinity && lp.upper(j) < infinity)
3511  chgBnds += 2;
3512  else
3513  ++chgBnds;
3514 
3515  lp.changeBounds(j, -infinity, infinity);
3516 
3517  ++m_stat[DOUBLETON_ROW];
3518 #endif
3519  }
3520 
3521  // 6. (implied) free column singleton
3522  if(lp.lower(j) <= -infinity && lp.upper(j) >= infinity)
3523  {
3524 #if FREE_COL_SINGLETON
3525  Real slackVal = lp.lhs(i);
3526 
3527  // constraint i is an inequality constraint -> transform into equation type
3528  if(NErel(lp.lhs(i), lp.rhs(i), feastol()))
3529  {
3530  MSG_DEBUG((*spxout) << "IMAISM40 col " << j
3531  << ": free singleton in inequality constraint" << std::endl;)
3532 
3533  // do nothing if constraint i is unconstrained
3534  if(lp.lhs(i) <= -infinity && lp.rhs(i) >= infinity)
3535  continue;
3536 
3537  // introduce slack variable to obtain equality constraint
3538  Real sMaxObj = lp.maxObj(j) / aij; // after substituting variable j in objective
3539  Real sLo = lp.lhs(i);
3540  Real sUp = lp.rhs(i);
3541 
3542  if(GT(sMaxObj, 0.0, epsZero()))
3543  {
3544  if(sUp >= infinity)
3545  {
3546  MSG_DEBUG((*spxout) << " -> problem unbounded" << std::endl;)
3547  return UNBOUNDED;
3548  }
3549 
3550  slackVal = sUp;
3551  }
3552  else if(LT(sMaxObj, 0.0, epsZero()))
3553  {
3554  if(sLo <= -infinity)
3555  {
3556  MSG_DEBUG((*spxout) << " -> problem unbounded" << std::endl;)
3557  return UNBOUNDED;
3558  }
3559 
3560  slackVal = sLo;
3561  }
3562  else
3563  {
3564  assert(isZero(sMaxObj, epsZero()));
3565 
3566  // any value within the bounds is ok
3567  if(sLo > -infinity)
3568  slackVal = sLo;
3569  else if(sUp < infinity)
3570  slackVal = sUp;
3571  else
3572  throw SPxInternalCodeException("XMAISM13 This should never happen.");
3573  }
3574  }
3575 
3576  FreeColSingletonPS* FreeColSingletonPSptr = 0;
3577  spx_alloc(FreeColSingletonPSptr);
3578  m_hist.append(new(FreeColSingletonPSptr) FreeColSingletonPS(lp, *this, j, i, slackVal));
3579 
3580  MSG_DEBUG((*spxout) << "IMAISM41 col " << j
3581  << ": free singleton removed" << std::endl;)
3582 
3583  const SVector& row = lp.rowVector(i);
3584 
3585  for(int h = 0; h < row.size(); ++h)
3586  {
3587  int k = row.index(h);
3588 
3589  if(k != j)
3590  {
3591  Real new_obj = lp.obj(k) - (lp.obj(j) * row.value(h) / aij);
3592  lp.changeObj(k, new_obj);
3593  }
3594  }
3595 
3596  ++remRows;
3597  ++remCols;
3598  remNzos += row.size();
3599  removeRow(lp, i);
3600  removeCol(lp, j);
3601 
3603 
3604  continue;
3605 #endif
3606  }
3607  }
3608  }
3609 
3610  if(remCols + remRows > 0)
3611  {
3612  m_remRows += remRows;
3613  m_remCols += remCols;
3614  m_remNzos += remNzos;
3615  m_chgBnds += chgBnds;
3616 
3617  MSG_INFO2((*spxout), (*spxout) << "Simplifier (columns) removed "
3618  << remRows << " rows, "
3619  << remCols << " cols, "
3620  << remNzos << " non-zeros, "
3621  << chgBnds << " col bounds"
3622  << std::endl;)
3623 
3624  if(remCols + remRows > m_minReduction * (oldCols + oldRows))
3625  again = true;
3626  }
3627 
3628  return OKAY;
3629 }
3630 
3632 {
3633 
3634  // This method simplifies LP using the following dual structures:
3635  //
3636  // 1. dominated columns
3637  // 2. weakly dominated columns
3638  //
3639  // For constructing the dual variables, it is assumed that the objective sense is max
3640 
3641  int remRows = 0;
3642  int remCols = 0;
3643  int remNzos = 0;
3644 
3645  int oldRows = lp.nRows();
3646  int oldCols = lp.nCols();
3647 
3648  DataArray<bool> colSingleton(lp.nCols());
3649  DVector dualVarLo(lp.nRows());
3650  DVector dualVarUp(lp.nRows());
3651  DVector dualConsLo(lp.nCols());
3652  DVector dualConsUp(lp.nCols());
3653 
3654  // init
3655  for(int i = lp.nRows() - 1; i >= 0; --i)
3656  {
3657  // check for unconstrained constraints
3658  if(lp.lhs(i) <= -infinity && lp.rhs(i) >= infinity)
3659  {
3660  MSG_DEBUG((*spxout) << "IMAISM43 row " << i
3661  << ": unconstrained" << std::endl;)
3662 
3663  FreeConstraintPS* FreeConstraintPSptr = 0;
3664  spx_alloc(FreeConstraintPSptr);
3665  m_hist.append(new(FreeConstraintPSptr) FreeConstraintPS(lp, i));
3666 
3667  ++remRows;
3668  remNzos += lp.rowVector(i).size();
3669  removeRow(lp, i);
3670 
3671  ++m_stat[FREE_ROW];
3672 
3673  continue;
3674  }
3675 
3676  // corresponds to maximization sense
3677  dualVarLo[i] = (lp.lhs(i) <= -infinity) ? 0.0 : -infinity;
3678  dualVarUp[i] = (lp.rhs(i) >= infinity) ? 0.0 : infinity;
3679  }
3680 
3681  // compute bounds on the dual variables using column singletons
3682  for(int j = 0; j < lp.nCols(); ++j)
3683  {
3684  if(lp.colVector(j).size() == 1)
3685  {
3686  int i = lp.colVector(j).index(0);
3687  Real aij = lp.colVector(j).value(0);
3688 
3689  ASSERT_WARN("WMAISM44", isNotZero(aij, 1.0 / infinity));
3690 
3691  Real bound = lp.maxObj(j) / aij;
3692 
3693  if(aij > 0)
3694  {
3695  if(lp.lower(j) <= -infinity && bound < dualVarUp[i])
3696  dualVarUp[i] = bound;
3697 
3698  if(lp.upper(j) >= infinity && bound > dualVarLo[i])
3699  dualVarLo[i] = bound;
3700  }
3701  else if(aij < 0)
3702  {
3703  if(lp.lower(j) <= -infinity && bound > dualVarLo[i])
3704  dualVarLo[i] = bound;
3705 
3706  if(lp.upper(j) >= infinity && bound < dualVarUp[i])
3707  dualVarUp[i] = bound;
3708  }
3709  }
3710 
3711  }
3712 
3713  // compute bounds on the dual constraints
3714  for(int j = 0; j < lp.nCols(); ++j)
3715  {
3716  dualConsLo[j] = dualConsUp[j] = 0.0;
3717 
3718  const SVector& col = lp.colVector(j);
3719 
3720  for(int k = 0; k < col.size(); ++k)
3721  {
3722  if(dualConsLo[j] <= -infinity && dualConsUp[j] >= infinity)
3723  break;
3724 
3725  Real aij = col.value(k);
3726  int i = col.index(k);
3727 
3728  ASSERT_WARN("WMAISM45", isNotZero(aij, 1.0 / infinity));
3729 
3730  if(aij > 0)
3731  {
3732  if(dualVarLo[i] <= -infinity)
3733  dualConsLo[j] = -infinity;
3734  else
3735  dualConsLo[j] += aij * dualVarLo[i];
3736 
3737  if(dualVarUp[i] >= infinity)
3738  dualConsUp[j] = infinity;
3739  else
3740  dualConsUp[j] += aij * dualVarUp[i];
3741  }
3742  else if(aij < 0)
3743  {
3744  if(dualVarLo[i] <= -infinity)
3745  dualConsUp[j] = infinity;
3746  else
3747  dualConsUp[j] += aij * dualVarLo[i];
3748 
3749  if(dualVarUp[i] >= infinity)
3750  dualConsLo[j] = -infinity;
3751  else
3752  dualConsLo[j] += aij * dualVarUp[i];
3753  }
3754  }
3755  }
3756 
3757  for(int j = lp.nCols() - 1; j >= 0; --j)
3758  {
3759  if(lp.colVector(j).size() <= 1)
3760  continue;
3761 
3762  // dual infeasibility checks
3763  if(LTrel(dualConsUp[j], dualConsLo[j], opttol()))
3764  {
3765  MSG_DEBUG((*spxout) << "IMAISM46 col " << j
3766  << ": dual infeasible -> dual lhs bound=" << dualConsLo[j]
3767  << " dual rhs bound=" << dualConsUp[j] << std::endl;)
3768  return DUAL_INFEASIBLE;
3769  }
3770 
3771  Real obj = lp.maxObj(j);
3772 
3773  // 1. dominated column
3774  // Is the problem really unbounded in the cases below ??? Or is only dual infeasibility be shown
3775  if(GTrel(obj, dualConsUp[j], opttol()))
3776  {
3777 #if DOMINATED_COLUMN
3778  MSG_DEBUG((*spxout) << "IMAISM47 col " << j
3779  << ": dominated -> maxObj=" << obj
3780  << " dual rhs bound=" << dualConsUp[j] << std::endl;)
3781 
3782  if(lp.upper(j) >= infinity)
3783  {
3784  MSG_INFO2((*spxout), (*spxout) << " unbounded" << std::endl;)
3785  return UNBOUNDED;
3786  }
3787 
3788  MSG_DEBUG((*spxout) << " fixed at upper=" << lp.upper(j) << std::endl;)
3789 
3790  FixBoundsPS* FixBoundsPSptr = 0;
3791  spx_alloc(FixBoundsPSptr);
3792  m_hist.append(new(FixBoundsPSptr) FixBoundsPS(lp, j, lp.upper(j)));
3793  lp.changeLower(j, lp.upper(j));
3794 
3795  ++m_stat[DOMINATED_COL];
3796 #endif
3797  }
3798  else if(LTrel(obj, dualConsLo[j], opttol()))
3799  {
3800 #if DOMINATED_COLUMN
3801  MSG_DEBUG((*spxout) << "IMAISM48 col " << j
3802  << ": dominated -> maxObj=" << obj
3803  << " dual lhs bound=" << dualConsLo[j] << std::endl;)
3804 
3805  if(lp.lower(j) <= -infinity)
3806  {
3807  MSG_INFO2((*spxout), (*spxout) << " unbounded" << std::endl;)
3808  return UNBOUNDED;
3809  }
3810 
3811  MSG_DEBUG((*spxout) << " fixed at lower=" << lp.lower(j) << std::endl;)
3812 
3813  FixBoundsPS* FixBoundsPSptr = 0;
3814  spx_alloc(FixBoundsPSptr);
3815  m_hist.append(new(FixBoundsPSptr) FixBoundsPS(lp, j, lp.lower(j)));
3816  lp.changeUpper(j, lp.lower(j));
3817 
3818  ++m_stat[DOMINATED_COL];
3819 #endif
3820  }
3821 
3822  // 2. weakly dominated column (no postsolving)
3823  else if(lp.upper(j) < infinity && EQrel(obj, dualConsUp[j], opttol()))
3824  {
3825 #if WEAKLY_DOMINATED_COLUMN
3826  MSG_DEBUG((*spxout) << "IMAISM49 col " << j
3827  << ": weakly dominated -> maxObj=" << obj
3828  << " dual rhs bound=" << dualConsUp[j] << std::endl;)
3829 
3830  FixBoundsPS* FixBoundsPSptr = 0;
3831  spx_alloc(FixBoundsPSptr);
3832  m_hist.append(new(FixBoundsPSptr) FixBoundsPS(lp, j, lp.upper(j)));
3833  lp.changeLower(j, lp.upper(j));
3834 
3836 #endif
3837  }
3838  else if(lp.lower(j) > -infinity && EQrel(obj, dualConsLo[j], opttol()))
3839  {
3840 #if WEAKLY_DOMINATED_COLUMN
3841  MSG_DEBUG((*spxout) << "IMAISM50 col " << j
3842  << ": weakly dominated -> maxObj=" << obj
3843  << " dual lhs bound=" << dualConsLo[j] << std::endl;)
3844 
3845  FixBoundsPS* FixBoundsPSptr = 0;
3846  spx_alloc(FixBoundsPSptr);
3847  m_hist.append(new(FixBoundsPSptr) FixBoundsPS(lp, j, lp.lower(j)));
3848  lp.changeUpper(j, lp.lower(j));
3849 
3851 #endif
3852  }
3853 
3854  // fix column
3855  if(EQrel(lp.lower(j), lp.upper(j), feastol()))
3856  {
3857 #if FIX_VARIABLE
3858  fixColumn(lp, j);
3859 
3860  ++remCols;
3861  remNzos += lp.colVector(j).size();
3862  removeCol(lp, j);
3863 
3864  ++m_stat[FIX_COL];
3865 #endif
3866  }
3867  }
3868 
3869 
3870  assert(remRows > 0 || remCols > 0 || remNzos == 0);
3871 
3872  if(remCols + remRows > 0)
3873  {
3874  m_remRows += remRows;
3875  m_remCols += remCols;
3876  m_remNzos += remNzos;
3877 
3878  MSG_INFO2((*spxout), (*spxout) << "Simplifier (dual) removed "
3879  << remRows << " rows, "
3880  << remCols << " cols, "
3881  << remNzos << " non-zeros"
3882  << std::endl;)
3883 
3884  if(remCols + remRows > m_minReduction * (oldCols + oldRows))
3885  again = true;
3886  }
3887 
3888  return OKAY;
3889 }
3890 
3891 
3892 
3894 {
3895  // this simplifier eliminates rows and columns by performing multi aggregations as identified by the constraint
3896  // activities.
3897  int remRows = 0;
3898  int remCols = 0;
3899  int remNzos = 0;
3900 
3901  int oldRows = lp.nRows();
3902  int oldCols = lp.nCols();
3903 
3904  DVector upLocks(lp.nCols());
3905  DVector downLocks(lp.nCols());
3906 
3907  for(int j = lp.nCols() - 1; j >= 0; --j)
3908  {
3909  // setting the locks on the variables
3910  upLocks[j] = 0;
3911  downLocks[j] = 0;
3912 
3913  if(lp.colVector(j).size() <= 1)
3914  continue;
3915 
3916  const SVector& col = lp.colVector(j);
3917 
3918  for(int k = 0; k < col.size(); ++k)
3919  {
3920  Real aij = col.value(k);
3921 
3922  ASSERT_WARN("WMAISM45", isNotZero(aij, 1.0 / infinity));
3923 
3924  if(GT(lp.lhs(col.index(k)), -infinity) && LT(lp.rhs(col.index(k)), infinity))
3925  {
3926  upLocks[j]++;
3927  downLocks[j]++;
3928  }
3929  else if(GT(lp.lhs(col.index(k)), -infinity))
3930  {
3931  if(aij > 0)
3932  downLocks[j]++;
3933  else if(aij < 0)
3934  upLocks[j]++;
3935  }
3936  else if(LT(lp.rhs(col.index(k)), infinity))
3937  {
3938  if(aij > 0)
3939  upLocks[j]++;
3940  else if(aij < 0)
3941  downLocks[j]++;
3942  }
3943  }
3944 
3945  // multi-aggregate column
3946  if(upLocks[j] == 1 || downLocks[j] == 1)
3947  {
3948  Real lower = lp.lower(j);
3949  Real upper = lp.upper(j);
3950  int maxOtherLocks;
3951  int bestpos = -1;
3952  bool bestislhs = true;
3953 
3954  for(int k = 0; k < col.size(); ++k)
3955  {
3956  int rowNumber;
3957  Real lhs;
3958  Real rhs;
3959  bool lhsExists;
3960  bool rhsExists;
3961  bool aggLhs;
3962  bool aggRhs;
3963 
3964  Real val = col.value(k);
3965 
3966  rowNumber = col.index(k);
3967  lhs = lp.lhs(rowNumber);
3968  rhs = lp.rhs(rowNumber);
3969 
3970  if(EQ(lhs, rhs, feastol()))
3971  continue;
3972 
3973  lhsExists = GT(lhs, -infinity);
3974  rhsExists = LT(rhs, infinity);
3975 
3976  if(lp.rowVector(rowNumber).size() <= 2)
3977  maxOtherLocks = INT_MAX;
3978  else if(lp.rowVector(rowNumber).size() == 3)
3979  maxOtherLocks = 3;
3980  else if(lp.rowVector(rowNumber).size() == 4)
3981  maxOtherLocks = 2;
3982  else
3983  maxOtherLocks = 1;
3984 
3985  aggLhs = lhsExists
3986  && ((col.value(k) > 0.0 && lp.maxObj(j) <= 0.0 && downLocks[j] == 1 && upLocks[j] <= maxOtherLocks)
3987  || (col.value(k) < 0.0 && lp.maxObj(j) >= 0.0 && upLocks[j] == 1 && downLocks[j] <= maxOtherLocks));
3988  aggRhs = rhsExists
3989  && ((col.value(k) > 0.0 && lp.maxObj(j) >= 0.0 && upLocks[j] == 1 && downLocks[j] <= maxOtherLocks)
3990  || (col.value(k) < 0.0 && lp.maxObj(j) <= 0.0 && downLocks[j] == 1 && upLocks[j] <= maxOtherLocks));
3991 
3992  if(aggLhs || aggRhs)
3993  {
3994  Real minRes = 0; // this is the minimum value that the aggregation can attain
3995  Real maxRes = 0; // this is the maximum value that the aggregation can attain
3996 
3997  // computing the minimum and maximum residuals if variable j is set to zero.
3998  computeMinMaxResidualActivity(lp, rowNumber, j, minRes, maxRes);
3999 
4000  // we will try to aggregate to the lhs
4001  if(aggLhs)
4002  {
4003  Real minVal;
4004  Real maxVal;
4005 
4006  // computing the values of the upper and lower bounds for the aggregated variables
4007  computeMinMaxValues(lp, lhs, val, minRes, maxRes, minVal, maxVal);
4008 
4009  assert(LE(minVal, maxVal));
4010 
4011  // if the bounds of the aggregation and the original variable are equivalent, then we can reduce
4012  if((minVal > -infinity && GT(minVal, lower, feastol()))
4013  && (maxVal < infinity && LT(maxVal, upper, feastol())))
4014  {
4015  bestpos = col.index(k);
4016  bestislhs = true;
4017  break;
4018  }
4019  }
4020 
4021  // we will try to aggregate to the rhs
4022  if(aggRhs)
4023  {
4024  Real minVal;
4025  Real maxVal;
4026 
4027  // computing the values of the upper and lower bounds for the aggregated variables
4028  computeMinMaxValues(lp, rhs, val, minRes, maxRes, minVal, maxVal);
4029 
4030  assert(LE(minVal, maxVal));
4031 
4032  if((minVal > -infinity && GT(minVal, lower, feastol()))
4033  && (maxVal < infinity && LT(maxVal, upper, feastol())))
4034  {
4035  bestpos = col.index(k);
4036  bestislhs = false;
4037  break;
4038  }
4039  }
4040  }
4041  }
4042 
4043  // it is only possible to aggregate if a best position has been found
4044  if(bestpos >= 0)
4045  {
4046  const SVector& bestRow = lp.rowVector(bestpos);
4047  // aggregating the variable and applying the fixings to the all other constraints
4048  Real aggConstant = (bestislhs ? lp.lhs(bestpos) : lp.rhs(
4049  bestpos)); // this is the lhs or rhs of the aggregated row
4050  Real aggAij =
4051  bestRow[j]; // this is the coefficient of the deleted col
4052 
4053  MSG_DEBUG(
4054  (*spxout) << "IMAISM51 col " << j
4055  << ": Aggregating row: " << bestpos
4056  << " Aggregation Constant=" << aggConstant
4057  << " Coefficient of aggregated col=" << aggAij << std::endl;
4058  )
4059 
4060  MultiAggregationPS* MultiAggregationPSptr = 0;
4061  spx_alloc(MultiAggregationPSptr);
4062  m_hist.append(new(MultiAggregationPSptr) MultiAggregationPS(lp, *this, bestpos, j, aggConstant));
4063 
4064  for(int k = 0; k < col.size(); ++k)
4065  {
4066  if(col.index(k) != bestpos)
4067  {
4068  int rowNumber = col.index(k);
4069  DVector updateRow(lp.nCols());
4070  Real updateRhs = lp.rhs(col.index(k));
4071  Real updateLhs = lp.lhs(col.index(k));
4072 
4073  updateRow = lp.rowVector(col.index(k));
4074 
4075  // updating the row with the best row
4076  for(int l = 0; l < bestRow.size(); l++)
4077  {
4078  if(bestRow.index(l) != j)
4079  {
4080  if(lp.rowVector(rowNumber).pos(bestRow.index(l)) >= 0)
4081  lp.changeElement(rowNumber, bestRow.index(l), updateRow[bestRow.index(l)]
4082  - updateRow[j]*bestRow.value(l) / aggAij);
4083  else
4084  lp.changeElement(rowNumber, bestRow.index(l), -1.0 * updateRow[j]*bestRow.value(l) / aggAij);
4085  }
4086  }
4087 
4088  // NOTE: I don't know whether we should change the LHS and RHS if they are currently at infinity
4089  if(LT(lp.rhs(rowNumber), infinity))
4090  lp.changeRhs(rowNumber, updateRhs - updateRow[j]*aggConstant / aggAij);
4091 
4092  if(GT(lp.lhs(rowNumber), -infinity))
4093  lp.changeLhs(rowNumber, updateLhs - updateRow[j]*aggConstant / aggAij);
4094 
4095  assert(LE(lp.lhs(rowNumber), lp.rhs(rowNumber)));
4096  }
4097  }
4098 
4099  for(int l = 0; l < bestRow.size(); l++)
4100  {
4101  if(bestRow.index(l) != j)
4102  lp.changeMaxObj(bestRow.index(l),
4103  lp.maxObj(bestRow.index(l)) - lp.maxObj(j)*bestRow.value(l) / aggAij);
4104  }
4105 
4106  ++remCols;
4107  remNzos += lp.colVector(j).size();
4108  removeCol(lp, j);
4109  ++remRows;
4110  remNzos += lp.rowVector(bestpos).size();
4111  removeRow(lp, bestpos);
4112 
4113  ++m_stat[MULTI_AGG];
4114  }
4115  }
4116  }
4117 
4118 
4119  assert(remRows > 0 || remCols > 0 || remNzos == 0);
4120 
4121  if(remCols + remRows > 0)
4122  {
4123  m_remRows += remRows;
4124  m_remCols += remCols;
4125  m_remNzos += remNzos;
4126 
4127  MSG_INFO2((*spxout), (*spxout) << "Simplifier (multi-aggregation) removed "
4128  << remRows << " rows, "
4129  << remCols << " cols, "
4130  << remNzos << " non-zeros"
4131  << std::endl;)
4132 
4133  if(remCols + remRows > m_minReduction * (oldCols + oldRows))
4134  again = true;
4135  }
4136 
4137  return OKAY;
4138 }
4139 
4140 
4141 
4143 {
4144 
4145  // This method simplifies the LP by removing duplicate rows
4146  // Duplicates are detected using the algorithm of Bixby and Wagner [1987]
4147 
4148  // Possible extension: use generalized definition of duplicate rows according to Andersen and Andersen
4149  // However: the resulting sparsification is often very small since the involved rows are usually very sparse
4150 
4151  int remRows = 0;
4152  int remNzos = 0;
4153 
4154  int oldRows = lp.nRows();
4155 
4156  // remove empty rows and columns
4158 
4159  if(ret != OKAY)
4160  return ret;
4161 
4162 #if ROW_SINGLETON
4163  int rs_remRows = 0;
4164 
4165  for(int i = 0; i < lp.nRows(); ++i)
4166  {
4167  const SVector& row = lp.rowVector(i);
4168 
4169  if(row.size() == 1)
4170  {
4171  removeRowSingleton(lp, row, i);
4172  rs_remRows++;
4173  }
4174  }
4175 
4176  if(rs_remRows > 0)
4177  {
4178  MSG_INFO2((*spxout), (*spxout) << "Simplifier duplicate rows (row singleton stage) removed "
4179  << rs_remRows << " rows, "
4180  << rs_remRows << " non-zeros"
4181  << std::endl;)
4182  }
4183 
4184 #endif
4185 
4186  if(lp.nRows() < 2)
4187  return OKAY;
4188 
4189  DataArray<int> pClass(lp.nRows()); // class of parallel rows
4190  DataArray<int> classSize(lp.nRows()); // size of each class
4191  DataArray<Real> scale(lp.nRows()); // scaling factor for each row
4192  int* idxMem = 0;
4193 
4194  try
4195  {
4196  spx_alloc(idxMem, lp.nRows());
4197  }
4198  catch(const SPxMemoryException& x)
4199  {
4200  spx_free(idxMem);
4201  throw x;
4202  }
4203 
4204  IdxSet idxSet(lp.nRows(), idxMem); // set of feasible indices for new pClass
4205 
4206  // init
4207  pClass[0] = 0;
4208  scale[0] = 0.0;
4209  classSize[0] = lp.nRows();
4210 
4211  for(int i = 1; i < lp.nRows(); ++i)
4212  {
4213  pClass[i] = 0;
4214  scale[i] = 0.0;
4215  classSize[i] = 0;
4216  idxSet.addIdx(i);
4217  }
4218 
4219  Real oldVal = 0.0;
4220 
4221  // main loop
4222  for(int j = 0; j < lp.nCols(); ++j)
4223  {
4224  const SVector& col = lp.colVector(j);
4225 
4226  for(int k = 0; k < col.size(); ++k)
4227  {
4228  Real aij = col.value(k);
4229  int i = col.index(k);
4230 
4231  if(scale[i] == 0.0)
4232  scale[i] = aij;
4233 
4234  m_classSetRows[pClass[i]].add(i, aij / scale[i]);
4235 
4236  if(--classSize[pClass[i]] == 0)
4237  idxSet.addIdx(pClass[i]);
4238  }
4239 
4240  // update each parallel class with non-zero column entry
4241  for(int m = 0; m < col.size(); ++m)
4242  {
4243  int k = pClass[col.index(m)];
4244 
4245  if(m_classSetRows[k].size() > 0)
4246  {
4247  // sort classSet[k] w.r.t. scaled column values
4248  ElementCompare compare;
4249 
4250  if(m_classSetRows[k].size() > 1)
4251  SPxQuicksort(m_classSetRows[k].mem(), m_classSetRows[k].size(), compare);
4252 
4253  // use new index first
4254  int classIdx = idxSet.index(0);
4255  idxSet.remove(0);
4256 
4257  for(int l = 0; l < m_classSetRows[k].size(); ++l)
4258  {
4259  if(l != 0 && NErel(m_classSetRows[k].value(l), oldVal, epsZero()))
4260  {
4261  classIdx = idxSet.index(0);
4262  idxSet.remove(0);
4263  }
4264 
4265  pClass[m_classSetRows[k].index(l)] = classIdx;
4266  ++classSize[classIdx];
4267 
4268  oldVal = m_classSetRows[k].value(l);
4269  }
4270 
4271  m_classSetRows[k].clear();
4272  }
4273  }
4274  }
4275 
4276  spx_free(idxMem);
4277 
4278  DataArray<bool> remRow(lp.nRows());
4279 
4280  for(int k = 0; k < lp.nRows(); ++k)
4281  m_dupRows[k].clear();
4282 
4283  for(int k = 0; k < lp.nRows(); ++k)
4284  {
4285  remRow[k] = false;
4286  m_dupRows[pClass[k]].add(k, 0.0);
4287  }
4288 
4289  const int nRowsOld_tmp = lp.nRows();
4290  int* perm_tmp = 0;
4291  spx_alloc(perm_tmp, nRowsOld_tmp);
4292 
4293  for(int j = 0; j < nRowsOld_tmp; ++j)
4294  {
4295  perm_tmp[j] = 0;
4296  }
4297 
4298  int idxFirstDupRows = -1;
4299  int idxLastDupRows = -1;
4300  int numDelRows = 0;
4301 
4302  for(int k = 0; k < lp.nRows(); ++k)
4303  {
4304  if(m_dupRows[k].size() > 1 && !(lp.rowVector(m_dupRows[k].index(0)).size() == 1))
4305  {
4306  idxLastDupRows = k;
4307 
4308  if(idxFirstDupRows < 0)
4309  {
4310  idxFirstDupRows = k;
4311  }
4312 
4313  for(int l = 1; l < m_dupRows[k].size(); ++l)
4314  {
4315  int i = m_dupRows[k].index(l);
4316  perm_tmp[i] = -1;
4317  }
4318 
4319  numDelRows += (m_dupRows[k].size() - 1);
4320  }
4321  }
4322 
4323  {
4324  int k_tmp, j_tmp = -1;
4325 
4326  for(k_tmp = j_tmp = 0; k_tmp < nRowsOld_tmp; ++k_tmp)
4327  {
4328  if(perm_tmp[k_tmp] >= 0)
4329  perm_tmp[k_tmp] = j_tmp++;
4330  }
4331  }
4332 
4333  // store rhs and lhs changes for combined update
4334  bool doChangeRanges = false;
4335  DVector newLhsVec(lp.lhs());
4336  DVector newRhsVec(lp.rhs());
4337 
4338  for(int k = 0; k < lp.nRows(); ++k)
4339  {
4340  if(m_dupRows[k].size() > 1 && !(lp.rowVector(m_dupRows[k].index(0)).size() == 1))
4341  {
4342  MSG_DEBUG((*spxout) << "IMAISM53 " << m_dupRows[k].size()
4343  << " duplicate rows found" << std::endl;)
4344 
4345  m_stat[DUPLICATE_ROW] += m_dupRows[k].size() - 1;
4346 
4347  // index of one non-column singleton row in dupRows[k]
4348  int rowIdx = -1;
4349  int maxLhsIdx = -1;
4350  int minRhsIdx = -1;
4351  Real maxLhs = -infinity;
4352  Real minRhs = +infinity;
4353 
4354  DataArray<bool> isLhsEqualRhs(m_dupRows[k].size());
4355 
4356  // determine strictest bounds on constraint
4357  for(int l = 0; l < m_dupRows[k].size(); ++l)
4358  {
4359  int i = m_dupRows[k].index(l);
4360  isLhsEqualRhs[l] = (lp.lhs(i) == lp.rhs(i));
4361 
4362  ASSERT_WARN("WMAISM54", isNotZero(scale[i], 1.0 / infinity));
4363 
4364  if(rowIdx == -1)
4365  {
4366  rowIdx = i;
4367  maxLhs = lp.lhs(rowIdx);
4368  minRhs = lp.rhs(rowIdx);
4369  }
4370  else
4371  {
4372  Real scaledLhs, scaledRhs;
4373  Real factor = scale[rowIdx] / scale[i];
4374 
4375  if(factor > 0)
4376  {
4377  scaledLhs = (lp.lhs(i) <= -infinity) ? -infinity : lp.lhs(i) * factor;
4378  scaledRhs = (lp.rhs(i) >= infinity) ? infinity : lp.rhs(i) * factor;
4379  }
4380  else
4381  {
4382  scaledLhs = (lp.rhs(i) >= infinity) ? -infinity : lp.rhs(i) * factor;
4383  scaledRhs = (lp.lhs(i) <= -infinity) ? infinity : lp.lhs(i) * factor;
4384  }
4385 
4386  if(scaledLhs > maxLhs)
4387  {
4388  maxLhs = scaledLhs;
4389  maxLhsIdx = i;
4390  }
4391 
4392  if(scaledRhs < minRhs)
4393  {
4394  minRhs = scaledRhs;
4395  minRhsIdx = i;
4396  }
4397 
4398  remRow[i] = true;
4399  }
4400  }
4401 
4402  if(rowIdx != -1)
4403  {
4404  Real newLhs = (maxLhs > lp.lhs(rowIdx)) ? maxLhs : lp.lhs(rowIdx);
4405  Real newRhs = (minRhs < lp.rhs(rowIdx)) ? minRhs : lp.rhs(rowIdx);
4406 
4407  if(k == idxLastDupRows)
4408  {
4409  DataArray<int> da_perm(nRowsOld_tmp);
4410 
4411  for(int j = 0; j < nRowsOld_tmp; ++j)
4412  {
4413  da_perm[j] = perm_tmp[j];
4414  }
4415 
4416  DuplicateRowsPS* DuplicateRowsPSptr = 0;
4417  spx_alloc(DuplicateRowsPSptr);
4418  m_hist.append(new(DuplicateRowsPSptr) DuplicateRowsPS(lp, rowIdx, maxLhsIdx, minRhsIdx,
4419  m_dupRows[k], scale, da_perm, isLhsEqualRhs, true, EQrel(newLhs, newRhs), k == idxFirstDupRows));
4420  }
4421  else
4422  {
4423  DataArray<int> da_perm_empty(0);
4424  DuplicateRowsPS* DuplicateRowsPSptr = 0;
4425  spx_alloc(DuplicateRowsPSptr);
4426  m_hist.append(new(DuplicateRowsPSptr) DuplicateRowsPS(lp, rowIdx, maxLhsIdx, minRhsIdx,
4427  m_dupRows[k], scale, da_perm_empty, isLhsEqualRhs, false, EQrel(newLhs, newRhs),
4428  k == idxFirstDupRows));
4429  }
4430 
4431  if(maxLhs > lp.lhs(rowIdx) || minRhs < lp.rhs(rowIdx))
4432  {
4433  // modify lhs and rhs of constraint rowIdx
4434  doChangeRanges = true;
4435 
4436  if(LTrel(newRhs, newLhs, feastol()))
4437  {
4438  MSG_DEBUG((*spxout) << "IMAISM55 duplicate rows yield infeasible bounds:"
4439  << " lhs=" << newLhs
4440  << " rhs=" << newRhs << std::endl;)
4441  spx_free(perm_tmp);
4442  return INFEASIBLE;
4443  }
4444 
4445  // if we accept the infeasibility we should clean up the values to avoid problems later
4446  if(newRhs < newLhs)
4447  newRhs = newLhs;
4448 
4449  newLhsVec[rowIdx] = newLhs;
4450  newRhsVec[rowIdx] = newRhs;
4451  }
4452  }
4453  }
4454  }
4455 
4456  // change ranges for all modified constraints by one single call (more efficient)
4457  if(doChangeRanges)
4458  {
4459  lp.changeRange(newLhsVec, newRhsVec);
4460  }
4461 
4462  // remove all rows by one single method call (more efficient)
4463  const int nRowsOld = lp.nRows();
4464  int* perm = 0;
4465  spx_alloc(perm, nRowsOld);
4466 
4467  for(int i = 0; i < nRowsOld; ++i)
4468  {
4469  if(remRow[i])
4470  {
4471  perm[i] = -1;
4472  ++remRows;
4473  remNzos += lp.rowVector(i).size();
4474  }
4475  else
4476  perm[i] = 0;
4477  }
4478 
4479  lp.removeRows(perm);
4480 
4481  for(int i = 0; i < nRowsOld; ++i)
4482  {
4483  // assert that the pre-computed permutation was correct
4484  assert(perm[i] == perm_tmp[i]);
4485 
4486  // update the global index mapping
4487  if(perm[i] >= 0)
4488  m_rIdx[perm[i]] = m_rIdx[i];
4489  }
4490 
4491  spx_free(perm);
4492  spx_free(perm_tmp);
4493 
4494  if(remRows + remNzos > 0)
4495  {
4496  m_remRows += remRows;
4497  m_remNzos += remNzos;
4498 
4499  MSG_INFO2((*spxout), (*spxout) << "Simplifier (duplicate rows) removed "
4500  << remRows << " rows, "
4501  << remNzos << " non-zeros"
4502  << std::endl;)
4503 
4504  if(remRows > m_minReduction * oldRows)
4505  again = true;
4506 
4507  }
4508 
4509  return OKAY;
4510 }
4511 
4513 {
4514 
4515  // This method simplifies the LP by removing duplicate columns
4516  // Duplicates are detected using the algorithm of Bixby and Wagner [1987]
4517 
4518  int remCols = 0;
4519  int remNzos = 0;
4520 
4521  // remove empty rows and columns
4523 
4524  if(ret != OKAY)
4525  return ret;
4526 
4527  if(lp.nCols() < 2)
4528  return OKAY;
4529 
4530  DataArray<int> pClass(lp.nCols()); // class of parallel columns
4531  DataArray<int> classSize(lp.nCols()); // size of each class
4532  DataArray<Real> scale(lp.nCols()); // scaling factor for each column
4533  int* idxMem = 0;
4534 
4535  try
4536  {
4537  spx_alloc(idxMem, lp.nCols());
4538  }
4539  catch(const SPxMemoryException& x)
4540  {
4541  spx_free(idxMem);
4542  throw x;
4543  }
4544 
4545  IdxSet idxSet(lp.nCols(), idxMem); // set of feasible indices for new pClass
4546 
4547  // init
4548  pClass[0] = 0;
4549  scale[0] = 0.0;
4550  classSize[0] = lp.nCols();
4551 
4552  for(int j = 1; j < lp.nCols(); ++j)
4553  {
4554  pClass[j] = 0;
4555  scale[j] = 0.0;
4556  classSize[j] = 0;
4557  idxSet.addIdx(j);
4558  }
4559 
4560  Real oldVal = 0.0;
4561 
4562  // main loop
4563  for(int i = 0; i < lp.nRows(); ++i)
4564  {
4565  const SVector& row = lp.rowVector(i);
4566 
4567  for(int k = 0; k < row.size(); ++k)
4568  {
4569  Real aij = row.value(k);
4570  int j = row.index(k);
4571 
4572  if(scale[j] == 0.0)
4573  scale[j] = aij;
4574 
4575  m_classSetCols[pClass[j]].add(j, aij / scale[j]);
4576 
4577  if(--classSize[pClass[j]] == 0)
4578  idxSet.addIdx(pClass[j]);
4579  }
4580 
4581  // update each parallel class with non-zero row entry
4582  for(int m = 0; m < row.size(); ++m)
4583  {
4584  int k = pClass[row.index(m)];
4585 
4586  if(m_classSetCols[k].size() > 0)
4587  {
4588  // sort classSet[k] w.r.t. scaled row values
4589  ElementCompare compare;
4590 
4591  if(m_classSetCols[k].size() > 1)
4592  SPxQuicksort(m_classSetCols[k].mem(), m_classSetCols[k].size(), compare);
4593 
4594  // use new index first
4595  int classIdx = idxSet.index(0);
4596  idxSet.remove(0);
4597 
4598  for(int l = 0; l < m_classSetCols[k].size(); ++l)
4599  {
4600  if(l != 0 && NErel(m_classSetCols[k].value(l), oldVal, epsZero()))
4601  {
4602  // start new parallel class
4603  classIdx = idxSet.index(0);
4604  idxSet.remove(0);
4605  }
4606 
4607  pClass[m_classSetCols[k].index(l)] = classIdx;
4608  ++classSize[classIdx];
4609 
4610  oldVal = m_classSetCols[k].value(l);
4611  }
4612 
4613  m_classSetCols[k].clear();
4614  }
4615  }
4616  }
4617 
4618  spx_free(idxMem);
4619 
4620  DataArray<bool> remCol(lp.nCols());
4621  DataArray<bool> fixAndRemCol(lp.nCols());
4622 
4623  for(int k = 0; k < lp.nCols(); ++k)
4624  m_dupCols[k].clear();
4625 
4626  for(int k = 0; k < lp.nCols(); ++k)
4627  {
4628  remCol[k] = false;
4629  fixAndRemCol[k] = false;
4630  m_dupCols[pClass[k]].add(k, 0.0);
4631  }
4632 
4633  bool hasDuplicateCol = false;
4634  DataArray<int> m_perm_empty(0);
4635 
4636  for(int k = 0; k < lp.nCols(); ++k)
4637  {
4638  if(m_dupCols[k].size() > 1 && !(lp.colVector(m_dupCols[k].index(0)).size() == 1))
4639  {
4640  MSG_DEBUG((*spxout) << "IMAISM58 " << m_dupCols[k].size()
4641  << " duplicate columns found" << std::endl;)
4642 
4643  if(!hasDuplicateCol)
4644  {
4645  DuplicateColsPS* DuplicateColsPSptr = 0;
4646  spx_alloc(DuplicateColsPSptr);
4647  m_hist.append(new(DuplicateColsPSptr) DuplicateColsPS(lp, 0, 0, 1.0, m_perm_empty, true));
4648  hasDuplicateCol = true;
4649  }
4650 
4651  for(int l = 0; l < m_dupCols[k].size(); ++l)
4652  {
4653  for(int m = 0; m < m_dupCols[k].size(); ++m)
4654  {
4655  int j1 = m_dupCols[k].index(l);
4656  int j2 = m_dupCols[k].index(m);
4657 
4658  if(l != m && !remCol[j1] && !remCol[j2])
4659  {
4660  Real cj1 = lp.maxObj(j1);
4661  Real cj2 = lp.maxObj(j2);
4662 
4663  // A.j1 = factor * A.j2
4664  Real factor = scale[j1] / scale[j2];
4665  Real objDif = cj1 - cj2 * scale[j1] / scale[j2];
4666 
4667  ASSERT_WARN("WMAISM59", isNotZero(factor, epsZero()));
4668 
4669  if(isZero(objDif, epsZero()))
4670  {
4671  // case 1: objectives also duplicate
4672 
4673  // if 0 is not within the column bounds, we are not able to postsolve if the aggregated column has
4674  // status ZERO, hence we skip this case
4675  if(LErel(lp.lower(j1), 0.0) && GErel(lp.upper(j1), 0.0)
4676  && LErel(lp.lower(j2), 0.0) && GErel(lp.upper(j2), 0.0))
4677  {
4678  DuplicateColsPS* DuplicateColsPSptr = 0;
4679  spx_alloc(DuplicateColsPSptr);
4680  // variable substitution xj2' := xj2 + factor * xj1 <=> xj2 = -factor * xj1 + xj2'
4681  m_hist.append(new(DuplicateColsPSptr) DuplicateColsPS(lp, j1, j2, factor, m_perm_empty));
4682 
4683  // update bounds of remaining column j2 (new column j2')
4684  if(factor > 0)
4685  {
4686  if(lp.lower(j2) <= -infinity || lp.lower(j1) <= -infinity)
4687  lp.changeLower(j2, -infinity);
4688  else
4689  lp.changeLower(j2, lp.lower(j2) + factor * lp.lower(j1));
4690 
4691  if(lp.upper(j2) >= infinity || lp.upper(j1) >= infinity)
4692  lp.changeUpper(j2, infinity);
4693  else
4694  lp.changeUpper(j2, lp.upper(j2) + factor * lp.upper(j1));
4695  }
4696  else if(factor < 0)
4697  {
4698  if(lp.lower(j2) <= -infinity || lp.upper(j1) >= infinity)
4699  lp.changeLower(j2, -infinity);
4700  else
4701  lp.changeLower(j2, lp.lower(j2) + factor * lp.upper(j1));
4702 
4703  if(lp.upper(j2) >= infinity || lp.lower(j1) <= -infinity)
4704  lp.changeUpper(j2, infinity);
4705  else
4706  lp.changeUpper(j2, lp.upper(j2) + factor * lp.lower(j1));
4707  }
4708 
4709  MSG_DEBUG((*spxout) << "IMAISM60 two duplicate columns " << j1
4710  << ", " << j2
4711  << " replaced by one" << std::endl;)
4712 
4713  remCol[j1] = true;
4714 
4716  }
4717  else
4718  {
4719  MSG_DEBUG((*spxout) << "IMAISM80 not removing two duplicate columns " << j1
4720  << ", " << j2
4721  << " because zero not contained in their bounds" << std::endl;)
4722  }
4723  }
4724  else
4725  {
4726  // case 2: objectives not duplicate
4727  // considered for maximization sense
4728  if(lp.lower(j2) <= -infinity)
4729  {
4730  if(factor > 0 && objDif > 0)
4731  {
4732  if(lp.upper(j1) >= infinity)
4733  {
4734  MSG_DEBUG((*spxout) << "IMAISM75 LP unbounded" << std::endl;)
4735  return UNBOUNDED;
4736  }
4737 
4738  // fix j1 at upper bound
4739  MSG_DEBUG((*spxout) << "IMAISM61 two duplicate columns " << j1
4740  << ", " << j2
4741  << " first one fixed at upper bound=" << lp.upper(j1) << std::endl;)
4742 
4743  FixBoundsPS* FixBoundsPSptr = 0;
4744  spx_alloc(FixBoundsPSptr);
4745  m_hist.append(new(FixBoundsPSptr) FixBoundsPS(lp, j1, lp.upper(j1)));
4746  lp.changeLower(j1, lp.upper(j1));
4747  }
4748  else if(factor < 0 && objDif < 0)
4749  {
4750  if(lp.lower(j1) <= -infinity)
4751  {
4752  MSG_DEBUG((*spxout) << "IMAISM76 LP unbounded" << std::endl;)
4753  return UNBOUNDED;
4754  }
4755 
4756  // fix j1 at lower bound
4757  MSG_DEBUG((*spxout) << "IMAISM62 two duplicate columns " << j1
4758  << ", " << j2
4759  << " first one fixed at lower bound=" << lp.lower(j1) << std::endl;)
4760 
4761  FixBoundsPS* FixBoundsPSptr = 0;
4762  spx_alloc(FixBoundsPSptr);
4763  m_hist.append(new(FixBoundsPSptr) FixBoundsPS(lp, j1, lp.lower(j1)));
4764  lp.changeUpper(j1, lp.lower(j1));
4765  }
4766  }
4767  else if(lp.upper(j2) >= infinity)
4768  {
4769  // fix j1 at upper bound
4770  if(factor < 0 && objDif > 0)
4771  {
4772  if(lp.upper(j1) >= infinity)
4773  {
4774  MSG_DEBUG((*spxout) << "IMAISM77 LP unbounded" << std::endl;)
4775  return UNBOUNDED;
4776  }
4777 
4778  // fix j1 at upper bound
4779  MSG_DEBUG((*spxout) << "IMAISM63 two duplicate columns " << j1
4780  << ", " << j2
4781  << " first one fixed at upper bound=" << lp.upper(j1) << std::endl;)
4782 
4783  FixBoundsPS* FixBoundsPSptr = 0;
4784  spx_alloc(FixBoundsPSptr);
4785  m_hist.append(new(FixBoundsPSptr) FixBoundsPS(lp, j1, lp.upper(j1)));
4786  lp.changeLower(j1, lp.upper(j1));
4787  }
4788 
4789  // fix j1 at lower bound
4790  else if(factor > 0 && objDif < 0)
4791  {
4792  if(lp.lower(j1) <= -infinity)
4793  {
4794  MSG_DEBUG((*spxout) << "IMAISM78 LP unbounded" << std::endl;)
4795  return UNBOUNDED;
4796  }
4797 
4798  // fix j1 at lower bound
4799  MSG_DEBUG((*spxout) << "IMAISM64 two duplicate columns " << j1
4800  << ", " << j2
4801  << " first one fixed at lower bound=" << lp.lower(j1) << std::endl;)
4802 
4803  FixBoundsPS* FixBoundsPSptr = 0;
4804  spx_alloc(FixBoundsPSptr);
4805  m_hist.append(new(FixBoundsPSptr) FixBoundsPS(lp, j1, lp.lower(j1)));
4806  lp.changeUpper(j1, lp.lower(j1));
4807  }
4808  }
4809 
4810  if(EQrel(lp.lower(j1), lp.upper(j1), feastol()))
4811  {
4812  remCol[j1] = true;
4813  fixAndRemCol[j1] = true;
4814 
4816  }
4817  }
4818  }
4819  }
4820  }
4821  }
4822  }
4823 
4824  for(int j = 0; j < lp.nCols(); ++j)
4825  {
4826  if(fixAndRemCol[j])
4827  {
4828  assert(remCol[j]);
4829 
4830  // correctIdx == false, because the index mapping will be handled by the postsolving in DuplicateColsPS
4831  fixColumn(lp, j, false);
4832  }
4833  }
4834 
4835  // remove all columns by one single method call (more efficient)
4836  const int nColsOld = lp.nCols();
4837  int* perm = 0;
4838  spx_alloc(perm, nColsOld);
4839 
4840  for(int j = 0; j < nColsOld; ++j)
4841  {
4842  if(remCol[j])
4843  {
4844  perm[j] = -1;
4845  ++remCols;
4846  remNzos += lp.colVector(j).size();
4847  }
4848  else
4849  perm[j] = 0;
4850  }
4851 
4852  lp.removeCols(perm);
4853 
4854  for(int j = 0; j < nColsOld; ++j)
4855  {
4856  if(perm[j] >= 0)
4857  m_cIdx[perm[j]] = m_cIdx[j];
4858  }
4859 
4860  DataArray<int> da_perm(nColsOld);
4861 
4862  for(int j = 0; j < nColsOld; ++j)
4863  {
4864  da_perm[j] = perm[j];
4865  }
4866 
4867  if(hasDuplicateCol)
4868  {
4869  DuplicateColsPS* DuplicateColsPSptr = 0;
4870  spx_alloc(DuplicateColsPSptr);
4871  m_hist.append(new(DuplicateColsPSptr) DuplicateColsPS(lp, 0, 0, 1.0, da_perm, false, true));
4872  }
4873 
4874  spx_free(perm);
4875 
4876  assert(remCols > 0 || remNzos == 0);
4877 
4878  if(remCols > 0)
4879  {
4880  m_remCols += remCols;
4881  m_remNzos += remNzos;
4882 
4883  MSG_INFO2((*spxout), (*spxout) << "Simplifier (duplicate columns) removed "
4884  << remCols << " cols, "
4885  << remNzos << " non-zeros"
4886  << std::endl;)
4887 
4888  if(remCols > m_minReduction * nColsOld)
4889  again = true;
4890  }
4891 
4892  return OKAY;
4893 }
4894 
4895 void SPxMainSM::fixColumn(SPxLP& lp, int j, bool correctIdx)
4896 {
4897 
4898  assert(EQrel(lp.lower(j), lp.upper(j), feastol()));
4899 
4900  Real lo = lp.lower(j);
4901  Real up = lp.upper(j);
4902  const SVector& col = lp.colVector(j);
4903  Real mid = lo;
4904 
4905  // use the center value between slightly different bounds to improve numerics
4906  if(NE(lo, up))
4907  mid = (up + lo) / 2.0;
4908 
4909  assert(LT(lo, infinity) && GT(lo, -infinity));
4910  assert(LT(up, infinity) && GT(up, -infinity));
4911 
4912  MSG_DEBUG((*spxout) << "IMAISM66 fix variable x" << j
4913  << ": lower=" << lo
4914  << " upper=" << up
4915  << "to new value: " << mid
4916  << std::endl;)
4917 
4918  if(isNotZero(lo, epsZero()))
4919  {
4920  for(int k = 0; k < col.size(); ++k)
4921  {
4922  int i = col.index(k);
4923 
4924  if(lp.rhs(i) < infinity)
4925  {
4926  Real y = mid * col.value(k);
4927  Real scale = maxAbs(lp.rhs(i), y);
4928 
4929  if(scale < 1.0)
4930  scale = 1.0;
4931 
4932  Real rhs = (lp.rhs(i) / scale) - (y / scale);
4933 
4934  if(isZero(rhs, epsZero()))
4935  rhs = 0.0;
4936  else
4937  rhs *= scale;
4938 
4939  MSG_DEBUG((*spxout) << "IMAISM67 row " << i
4940  << ": rhs=" << rhs
4941  << " (" << lp.rhs(i)
4942  << ") aij=" << col.value(k)
4943  << std::endl;)
4944 
4945  lp.changeRhs(i, rhs);
4946  }
4947 
4948  if(lp.lhs(i) > -infinity)
4949  {
4950  Real y = mid * col.value(k);
4951  Real scale = maxAbs(lp.lhs(i), y);
4952 
4953  if(scale < 1.0)
4954  scale = 1.0;
4955 
4956  Real lhs = (lp.lhs(i) / scale) - (y / scale);
4957 
4958  if(isZero(lhs, epsZero()))
4959  lhs = 0.0;
4960  else
4961  lhs *= scale;
4962 
4963  MSG_DEBUG((*spxout) << "IMAISM68 row " << i
4964  << ": lhs=" << lhs
4965  << " (" << lp.lhs(i)
4966  << ") aij=" << col.value(k)
4967  << std::endl;)
4968 
4969  lp.changeLhs(i, lhs);
4970  }
4971 
4972  assert(lp.lhs(i) <= lp.rhs(i) + feastol());
4973  }
4974  }
4975 
4976  FixVariablePS* FixVariablePSptr = 0;
4977  spx_alloc(FixVariablePSptr);
4978  m_hist.append(new(FixVariablePSptr) FixVariablePS(lp, *this, j, lp.lower(j), correctIdx));
4979 }
4980 
4982  bool keepbounds)
4983 {
4984  // transfer message handler
4985  spxout = lp.spxout;
4986  assert(spxout != 0);
4987 
4988  m_thesense = lp.spxSense();
4989  m_timeUsed->reset();
4990  m_timeUsed->start();
4991 
4992  m_objoffset = 0.0;
4994  m_pseudoobj = -infinity;
4995 
4996  m_remRows = 0;
4997  m_remCols = 0;
4998  m_remNzos = 0;
4999  m_chgBnds = 0;
5000  m_chgLRhs = 0;
5001  m_keptBnds = 0;
5002  m_keptLRhs = 0;
5003 
5004  m_result = OKAY;
5005  bool again = true;
5006  int nrounds = 0;
5007 
5008  if(m_hist.size() > 0)
5009  {
5010  // delete pointers in old m_hist
5011  for(int k = 0; k < m_hist.size(); ++k)
5012  {
5013  m_hist[k]->~PostStep();
5014  spx_free(m_hist[k]);
5015  }
5016 
5017  m_hist.clear();
5018  }
5019 
5020  m_hist.reSize(0);
5021  m_postsolved = false;
5022 
5023  if(eps < 0.0)
5024  throw SPxInterfaceException("XMAISM30 Cannot use negative epsilon in simplify().");
5025 
5026  if(ftol < 0.0)
5027  throw SPxInterfaceException("XMAISM31 Cannot use negative feastol in simplify().");
5028 
5029  if(otol < 0.0)
5030  throw SPxInterfaceException("XMAISM32 Cannot use negative opttol in simplify().");
5031 
5032  m_epsilon = eps;
5033  m_feastol = ftol;
5034  m_opttol = otol;
5035 
5036 
5037  MSG_INFO2((*spxout),
5038  int numRangedRows = 0;
5039  int numBoxedCols = 0;
5040  int numEqualities = 0;
5041 
5042  for(int i = 0; i < lp.nRows(); ++i)
5043 {
5044  if(lp.lhs(i) > -infinity && lp.rhs(i) < infinity)
5045  {
5046  if(EQ(lp.lhs(i), lp.rhs(i)))
5047  ++numEqualities;
5048  else
5049  ++numRangedRows;
5050  }
5051  }
5052  for(int j = 0; j < lp.nCols(); ++j)
5053  if(lp.lower(j) > -infinity && lp.upper(j) < infinity)
5054  ++numBoxedCols;
5055 
5056  (*spxout) << "LP has "
5057  << numEqualities << " equations, "
5058  << numRangedRows << " ranged rows, "
5059  << numBoxedCols << " boxed columns"
5060  << std::endl;
5061  )
5062 
5063  m_stat.reSize(17);
5064 
5065  for(int k = 0; k < m_stat.size(); ++k)
5066  m_stat[k] = 0;
5067 
5068  m_addedcols = 0;
5069  handleRowObjectives(lp);
5070 
5071  m_prim.reDim(lp.nCols());
5072  m_slack.reDim(lp.nRows());
5073  m_dual.reDim(lp.nRows());
5074  m_redCost.reDim(lp.nCols());
5075  m_cBasisStat.reSize(lp.nCols());
5076  m_rBasisStat.reSize(lp.nRows());
5077  m_cIdx.reSize(lp.nCols());
5078  m_rIdx.reSize(lp.nRows());
5079 
5080  m_classSetRows.reSize(lp.nRows());
5081  m_classSetCols.reSize(lp.nCols());
5082  m_dupRows.reSize(lp.nRows());
5083  m_dupCols.reSize(lp.nCols());
5084 
5085  m_keepbounds = keepbounds;
5086 
5087  for(int i = 0; i < lp.nRows(); ++i)
5088  m_rIdx[i] = i;
5089 
5090  for(int j = 0; j < lp.nCols(); ++j)
5091  m_cIdx[j] = j;
5092 
5093  // round extreme values (set all values smaller than eps to zero and all values bigger than infinity/5 to infinity)
5094 #if EXTREMES
5095  handleExtremes(lp);
5096 #endif
5097 
5098  // main presolving loop
5099  while(again && m_result == OKAY)
5100  {
5101  nrounds++;
5102  MSG_INFO3((*spxout), (*spxout) << "Round " << nrounds << ":" << std::endl;)
5103  again = false;
5104 
5105 #if ROWS
5106 
5107  if(m_result == OKAY)
5108  m_result = simplifyRows(lp, again);
5109 
5110 #endif
5111 
5112 #if COLS
5113 
5114  if(m_result == OKAY)
5115  m_result = simplifyCols(lp, again);
5116 
5117 #endif
5118 
5119 #if DUAL
5120 
5121  if(m_result == OKAY)
5122  m_result = simplifyDual(lp, again);
5123 
5124 #endif
5125 
5126 #if DUPLICATE_ROWS
5127 
5128  if(m_result == OKAY)
5129  m_result = duplicateRows(lp, again);
5130 
5131 #endif
5132 
5133 #if DUPLICATE_COLS
5134 
5135  if(m_result == OKAY)
5136  m_result = duplicateCols(lp, again);
5137 
5138 #endif
5139 
5140  if(!again)
5141  {
5142 #if TRIVIAL_HEURISTICS
5143  trivialHeuristic(lp);
5144 #endif
5145 
5146 #if PSEUDOOBJ
5147  propagatePseudoobj(lp);
5148 #endif
5149 
5150 #if MULTI_AGGREGATE
5151 
5152  if(m_result == OKAY)
5153  m_result = multiaggregation(lp, again);
5154 
5155 #endif
5156  }
5157  }
5158 
5159  MSG_INFO3((*spxout), (*spxout) << "Simplification finished" << std::endl;)
5160 
5161  // preprocessing detected infeasibility or unboundedness
5162  if(m_result != OKAY)
5163  {
5164  MSG_INFO1((*spxout), (*spxout) << "Simplifier result: " << m_result << std::endl;)
5165  return m_result;
5166  }
5167 
5170  MSG_INFO1((*spxout), (*spxout) << "Simplifier removed "
5171  << m_remRows << " rows, "
5172  << m_remCols << " columns, "
5173  << m_remNzos << " nonzeros, "
5174  << m_chgBnds << " col bounds, "
5175  << m_chgLRhs << " row bounds"
5176  << std::endl;)
5177 
5178  if(keepbounds)
5179  MSG_INFO2((*spxout), (*spxout) << "Simplifier kept "
5180  << m_keptBnds << " column bounds, "
5181  << m_keptLRhs << " row bounds"
5182  << std::endl;)
5183 
5184  MSG_INFO1((*spxout), (*spxout) << "Reduced LP has "
5185  << lp.nRows() << " rows "
5186  << lp.nCols() << " columns "
5187  << lp.nNzos() << " nonzeros"
5188  << std::endl;)
5189 
5190  MSG_INFO2((*spxout),
5191  int numRangedRows = 0;
5192  int numBoxedCols = 0;
5193  int numEqualities = 0;
5194 
5195  for(int i = 0; i < lp.nRows(); ++i)
5196  {
5197  if(lp.lhs(i) > -infinity && lp.rhs(i) < infinity)
5198  {
5199  if(EQ(lp.lhs(i), lp.rhs(i)))
5200  ++numEqualities;
5201  else
5202  ++numRangedRows;
5203  }
5204  }
5205  for(int j = 0; j < lp.nCols(); ++j)
5206  if(lp.lower(j) > -infinity && lp.upper(j) < infinity)
5207  ++numBoxedCols;
5208 
5209  (*spxout) << "Reduced LP has "
5210  << numEqualities << " equations, "
5211  << numRangedRows << " ranged rows, "
5212  << numBoxedCols << " boxed columns"
5213  << std::endl;
5214  )
5215 
5216  if(lp.nCols() == 0 && lp.nRows() == 0)
5217  {
5218  MSG_INFO1((*spxout), (*spxout) << "Simplifier removed all rows and columns" << std::endl;)
5219  m_result = VANISHED;
5220  }
5221 
5222  MSG_INFO2((*spxout), (*spxout) << "\nSimplifier performed:\n"
5223  << m_stat[EMPTY_ROW] << " empty rows\n"
5224  << m_stat[FREE_ROW] << " free rows\n"
5225  << m_stat[SINGLETON_ROW] << " singleton rows\n"
5226  << m_stat[FORCE_ROW] << " forcing rows\n"
5227  << m_stat[EMPTY_COL] << " empty columns\n"
5228  << m_stat[FIX_COL] << " fixed columns\n"
5229  << m_stat[FREE_ZOBJ_COL] << " free columns with zero objective\n"
5230  << m_stat[ZOBJ_SINGLETON_COL] << " singleton columns with zero objective\n"
5231  << m_stat[DOUBLETON_ROW] << " singleton columns combined with a doubleton equation\n"
5232  << m_stat[FREE_SINGLETON_COL] << " free singleton columns\n"
5233  << m_stat[DOMINATED_COL] << " dominated columns\n"
5234  << m_stat[WEAKLY_DOMINATED_COL] << " weakly dominated columns\n"
5235  << m_stat[DUPLICATE_ROW] << " duplicate rows\n"
5236  << m_stat[FIX_DUPLICATE_COL] << " duplicate columns (fixed)\n"
5237  << m_stat[SUB_DUPLICATE_COL] << " duplicate columns (substituted)\n"
5238  << m_stat[AGGREGATION] << " variable aggregations\n"
5239  << m_stat[MULTI_AGG] << " multi aggregations\n"
5240  << std::endl;);
5241 
5242  m_timeUsed->stop();
5243 
5244  return m_result;
5245 }
5246 
5247 void SPxMainSM::unsimplify(const Vector& x, const Vector& y, const Vector& s, const Vector& r,
5248  const SPxSolver::VarStatus rows[], const SPxSolver::VarStatus cols[], bool isOptimal)
5249 {
5250  MSG_INFO1((*spxout), (*spxout) << " --- unsimplifying solution and basis" << std::endl;)
5251  assert(x.dim() <= m_prim.dim());
5252  assert(y.dim() <= m_dual.dim());
5253  assert(x.dim() == r.dim());
5254  assert(y.dim() == s.dim());
5255 
5256  // assign values of variables in reduced LP
5257  // NOTE: for maximization problems, we have to switch signs of dual and reduced cost values,
5258  // since simplifier assumes minimization problem
5259  for(int j = 0; j < x.dim(); ++j)
5260  {
5261  m_prim[j] = isZero(x[j], epsZero()) ? 0.0 : x[j];
5262  m_redCost[j] = isZero(r[j], epsZero()) ? 0.0 : (m_thesense == SPxLP::MAXIMIZE ? -r[j] : r[j]);
5263  m_cBasisStat[j] = cols[j];
5264  }
5265 
5266  for(int i = 0; i < y.dim(); ++i)
5267  {
5268  m_dual[i] = isZero(y[i], epsZero()) ? 0.0 : (m_thesense == SPxLP::MAXIMIZE ? -y[i] : y[i]);
5269  m_slack[i] = isZero(s[i], epsZero()) ? 0.0 : s[i];
5270  m_rBasisStat[i] = rows[i];
5271  }
5272 
5273  // undo preprocessing
5274  for(int k = m_hist.size() - 1; k >= 0; --k)
5275  {
5276  MSG_DEBUG(std::cout << "unsimplifying " << m_hist[k]->getName() << "\n");
5277 
5278  try
5279  {
5280  m_hist[k]->execute(m_prim, m_dual, m_slack, m_redCost, m_cBasisStat, m_rBasisStat, isOptimal);
5281  }
5282  catch(const SPxException& ex)
5283  {
5284  MSG_INFO1((*spxout), (*spxout) << "Exception thrown while unsimplifying " << m_hist[k]->getName() <<
5285  ":\n" << ex.what() << "\n");
5286  throw SPxInternalCodeException("XMAISM00 Exception thrown during unsimply().");
5287  }
5288 
5289  m_hist[k]->~PostStep();
5290  spx_free(m_hist[k]);
5291  m_hist.reSize(k);
5292  }
5293 
5294  // for maximization problems, we have to switch signs of dual and reduced cost values back
5296  {
5297  for(int j = 0; j < m_redCost.dim(); ++j)
5298  m_redCost[j] = -m_redCost[j];
5299 
5300  for(int i = 0; i < m_dual.dim(); ++i)
5301  m_dual[i] = -m_dual[i];
5302  }
5303 
5304  if(m_addedcols > 0)
5305  {
5306  assert(m_prim.dim() >= m_addedcols);
5311  }
5312 
5313 #ifdef CHECK_BASIC_DIM
5314  int numBasis = 0;
5315 
5316  for(int rs = 0; rs < m_rBasisStat.size(); ++rs)
5317  {
5318  if(m_rBasisStat[rs] == SPxSolver::BASIC)
5319  numBasis ++;
5320  }
5321 
5322  for(int cs = 0; cs < m_cBasisStat.size(); ++cs)
5323  {
5324  if(m_cBasisStat[cs] == SPxSolver::BASIC)
5325  numBasis ++;
5326  }
5327 
5328  if(numBasis != m_rBasisStat.size())
5329  {
5330  throw SPxInternalCodeException("XMAISM26 Dimension doesn't match after this step.");
5331  }
5332 
5333 #endif
5334 
5335  m_hist.clear();
5336  m_postsolved = true;
5337 }
5338 
5339 // Pretty-printing of solver status.
5340 std::ostream& operator<<(std::ostream& os, const SPxSimplifier::Result& status)
5341 {
5342  switch(status)
5343  {
5344  case SPxSimplifier::OKAY:
5345  os << "SUCCESS";
5346  break;
5347 
5349  os << "INFEASIBLE";
5350  break;
5351 
5353  os << "DUAL_INFEASIBLE";
5354  break;
5355 
5357  os << "UNBOUNDED";
5358  break;
5359 
5361  os << "VANISHED";
5362  break;
5363 
5364  default:
5365  os << "UNKNOWN";
5366  break;
5367  }
5368 
5369  return os;
5370 }
5371 
5372 } //namespace soplex
const VectorBase< R > & rhs() const
Returns right hand side vector.
Definition: spxlpbase.h:221
DVector m_prim
unsimplified primal solution vector.
Definition: spxmainsm.h:1306
Rational spxAbs(const Rational &r)
Absolute.
Definition: rational.cpp:4102
bool isNotZero(Real a, Real eps=Param::epsilon())
returns true iff |a| > eps
Definition: spxdefines.h:418
Real m_opttol
dual feasibility tolerance.
Definition: spxmainsm.h:1325
DataArray< PostStep * > m_hist
vector of presolve history.
Definition: spxmainsm.h:1314
Postsolves multi aggregation.
Definition: spxmainsm.h:1140
Exception class for things that should NEVER happen.This class is derived from the SoPlex exception b...
Definition: exceptions.h:109
bool LTrel(Real a, Real b, Real eps=Param::epsilon())
returns true iff relDiff(a,b) <= -eps
Definition: spxdefines.h:436
free variable fixed to zero.
Definition: spxsolver.h:194
virtual void execute(DVector &x, DVector &y, DVector &s, DVector &r, DataArray< SPxSolver::VarStatus > &cBasis, DataArray< SPxSolver::VarStatus > &rBasis, bool isOptimal) const
Definition: spxmainsm.cpp:166
virtual void execute(DVector &x, DVector &y, DVector &s, DVector &r, DataArray< SPxSolver::VarStatus > &cBasis, DataArray< SPxSolver::VarStatus > &rBasis, bool isOptimal) const
Definition: spxmainsm.cpp:380
friend class FreeConstraintPS
Definition: spxmainsm.h:1261
Result removeRowSingleton(SPxLP &lp, const SVector &row, int &i)
remove row singletons.
Definition: spxmainsm.cpp:2197
DataArray< int > m_stat
preprocessing history.
Definition: spxmainsm.h:1326
bool GE(Real a, Real b, Real eps=Param::epsilon())
returns true iff a >= b + eps
Definition: spxdefines.h:406
void reDim(int newdim, const bool setZero=true)
Resets DVectorBase&#39;s dimension to newdim.
Definition: dvectorbase.h:253
virtual void execute(DVector &x, DVector &y, DVector &s, DVector &r, DataArray< SPxSolver::VarStatus > &cBasis, DataArray< SPxSolver::VarStatus > &rBasis, bool isOptimal) const
Definition: spxmainsm.cpp:932
int m_keptLRhs
number of kept left- and right-hand sides
Definition: spxsimplifier.h:66
UnitVectorBase< Real > UnitVector
Definition: unitvector.h:29
const VectorBase< R > & upper() const
Returns upper bound vector.
Definition: spxlpbase.h:461
Real m_epsilon
epsilon zero.
Definition: spxmainsm.h:1323
THREADLOCAL const Real infinity
Definition: spxdefines.cpp:26
Postsolves variable bound fixing.
Definition: spxmainsm.h:521
Result
Result of the simplification.
Definition: spxsimplifier.h:81
the problem was so much simplified that it vanished
Definition: spxsimplifier.h:87
Postsolves duplicate rows.
Definition: spxmainsm.h:897
int m_remNzos
number of removed nonzero coefficients
Definition: spxsimplifier.h:58
int size() const
Number of used indices.
Definition: svectorbase.h:153
void computeMinMaxResidualActivity(SPxLP &lp, int rowNumber, int colNumber, Real &minAct, Real &maxAct)
computes the minimum and maximum residual activity for a given row and column. If colNumber is set to...
Definition: spxmainsm.cpp:1782
Real m_feastol
primal feasibility tolerance.
Definition: spxmainsm.h:1324
DataArray< SPxSolver::VarStatus > m_rBasisStat
basis status of rows.
Definition: spxmainsm.h:1311
Real maxAbs(Real a, Real b)
returns max(|a|,|b|)
Definition: spxdefines.h:361
virtual void removeCols(int perm[])
Removes multiple columns.
Definition: spxlpbase.h:1052
bool LE(Real a, Real b, Real eps=Param::epsilon())
returns true iff a <= b + eps
Definition: spxdefines.h:394
Real opttol() const
Definition: spxmainsm.h:1430
bool LT(Real a, Real b, Real eps=Param::epsilon())
returns true iff a < b + eps
Definition: spxdefines.h:388
virtual void execute(DVector &x, DVector &y, DVector &s, DVector &r, DataArray< SPxSolver::VarStatus > &cBasis, DataArray< SPxSolver::VarStatus > &rBasis, bool isOptimal) const
Definition: spxmainsm.cpp:1442
SPxLP::SPxSense m_thesense
optimization sense.
Definition: spxmainsm.h:1327
bool NE(Real a, Real b, Real eps=Param::epsilon())
returns true iff |a-b| > eps
Definition: spxdefines.h:382
virtual Result simplify(SPxLP &lp, Real eps, Real delta)
simplify SPxLP lp with identical primal and dual feasibility tolerance.
Definition: spxmainsm.h:1560
friend class DuplicateRowsPS
Definition: spxmainsm.h:1271
virtual void execute(DVector &x, DVector &y, DVector &s, DVector &r, DataArray< SPxSolver::VarStatus > &cBasis, DataArray< SPxSolver::VarStatus > &rBasis, bool isOptimal) const
Definition: spxmainsm.cpp:194
virtual void execute(DVector &x, DVector &y, DVector &s, DVector &r, DataArray< SPxSolver::VarStatus > &cBasis, DataArray< SPxSolver::VarStatus > &rBasis, bool isOptimal) const
Definition: spxmainsm.cpp:488
int cIdx(int j) const
returns for a given column index of the (reduced) LP the corresponding column index in the unsimplifi...
Definition: spxmainsm.h:1411
variable fixed to identical bounds.
Definition: spxsolver.h:193
DVector m_dual
unsimplified dual solution vector.
Definition: spxmainsm.h:1308
R & value(int n)
Reference to value of n &#39;th nonzero.
Definition: svectorbase.h:253
General methods in LP preprocessing.
Postsolves empty constraints.
Definition: spxmainsm.h:232
virtual void execute(DVector &x, DVector &y, DVector &s, DVector &r, DataArray< SPxSolver::VarStatus > &cBasis, DataArray< SPxSolver::VarStatus > &rBasis, bool isOptimal) const
Definition: spxmainsm.cpp:870
int m_keptBnds
number of kept bounds
Definition: spxsimplifier.h:64
#define ASSERT_WARN(prefix, expr)
Macro to turn some assertions into warnings.
Definition: spxdefines.h:77
Real m_minReduction
minimal reduction (sum of removed rows/cols) to continue simplification
Definition: spxsimplifier.h:70
void remove(int n, int m)
Remove nonzeros n thru m.
Definition: svectorbase.h:394
Real feastol() const
Definition: spxmainsm.h:1425
void handleExtremes(SPxLP &lp)
handles extreme values by setting them to zero or infinity.
Definition: spxmainsm.cpp:1580
bool m_postsolved
status of postsolving.
Definition: spxmainsm.h:1322
int rIdx(int i) const
returns for a given row index of the (reduced) LP the corresponding row index in the unsimplified LP...
Definition: spxmainsm.h:1406
virtual void unsimplify(const Vector &x, const Vector &y, const Vector &s, const Vector &r, const SPxSolver::VarStatus rows[], const SPxSolver::VarStatus cols[], bool isOptimal=true)
reconstructs an optimal solution for the unsimplified LP.
Definition: spxmainsm.cpp:5247
SVectorBase< R > & rowVector_w(int i)
Definition: spxlpbase.h:2245
virtual void removeRows(int perm[])
Removes multiple rows.
Definition: spxlpbase.h:952
void fixColumn(SPxLP &lp, int i, bool correctIdx=true)
handles the fixing of a variable. correctIdx is true iff the index mapping has to be updated...
Definition: spxmainsm.cpp:4895
virtual const std::string what() const
returns exception message
Definition: exceptions.h:57
virtual void addObjoffset(const Real val)
add objective offset.
Wrapper for different output streams and verbosity levels.
int nRows() const
Returns number of rows in LP.
Definition: spxlpbase.h:152
Exception class for out of memory exceptions.This class is derived from the SoPlex exception base cla...
Definition: exceptions.h:70
virtual void start()=0
start timer, resume accounting user, system and real time.
virtual Real stop()=0
stop timer, return accounted user time.
void spx_alloc(T &p, int n=1)
Allocate memory.
Definition: spxalloc.h:48
simplification could be done
Definition: spxsimplifier.h:83
virtual void execute(DVector &x, DVector &y, DVector &s, DVector &r, DataArray< SPxSolver::VarStatus > &cBasis, DataArray< SPxSolver::VarStatus > &rBasis, bool isOptimal) const
Definition: spxmainsm.cpp:984
Postsolves the case when constraints are removed due to a variable with zero objective that is free i...
Definition: spxmainsm.h:580
int nNzos() const
Returns number of nonzeros in LP.
Definition: spxlpbase.h:164
virtual const char * getName() const
get name of simplifying step.
Definition: spxmainsm.h:107
friend class RowSingletonPS
Definition: spxmainsm.h:1263
Timer * m_timeUsed
user time used for simplification
Definition: spxsimplifier.h:51
nothing known about basis status (possibly due to a singular basis in transformed problem) ...
Definition: spxsolver.h:196
double Real
Definition: spxdefines.h:218
Array< DSVector > m_classSetCols
stores parallel classes with non-zero row entry
Definition: spxmainsm.h:1317
#define MAXIMUM(x, y)
Definition: spxdefines.h:246
Result duplicateCols(SPxLP &lp, bool &again)
removes duplicate columns
Definition: spxmainsm.cpp:4512
void removeCol(SPxLP &lp, int j)
removes a column in the LP.
Definition: spxmainsm.h:1400
#define MSG_DEBUG(x)
Definition: spxdefines.h:132
int nRows
number of rows
Definition: spxmainsm.h:81
bool GT(Real a, Real b, Real eps=Param::epsilon())
returns true iff a > b + eps
Definition: spxdefines.h:400
SPxSense spxSense() const
Returns the optimization sense.
Definition: spxlpbase.h:515
int & index(int n)
Reference to index of n &#39;th nonzero.
Definition: svectorbase.h:235
Postsolves row singletons.
Definition: spxmainsm.h:280
virtual void changeMaxObj(const VectorBase< R > &newObj, bool scale=false)
Changes objective vector to newObj. scale determines whether the new data should be scaled...
Definition: spxlpbase.h:1371
std::ostream & operator<<(std::ostream &s, const VectorBase< R > &vec)
Output operator.
Definition: basevectors.h:1136
Result simplifyRows(SPxLP &lp, bool &again)
performs simplification steps on the rows of the LP.
Definition: spxmainsm.cpp:2504
bool checkSolution(SPxLP &lp, DVector sol)
checks a solution for feasibility
Definition: spxmainsm.cpp:1997
#define MSG_INFO2(spxout, x)
Prints out message x if the verbosity level is at least SPxOut::INFO2.
Definition: spxdefines.h:120
R rowObj(int i) const
Definition: spxlpbase.h:282
#define MSG_ERROR(x)
Prints out message x if the verbosity level is at least SPxOut::ERROR.
Definition: spxdefines.h:114
friend class DoubletonEquationPS
Definition: spxmainsm.h:1270
Postsolves doubleton equations combined with a column singleton.
Definition: spxmainsm.h:800
Postsolves free column singletons.
Definition: spxmainsm.h:730
virtual void changeLower(const VectorBase< R > &newLower, bool scale=false)
Changes vector of lower bounds to newLower. scale determines whether the new data should be scaled...
Definition: spxlpbase.h:1409
virtual void changeRhs(const VectorBase< R > &newRhs, bool scale=false)
Changes right hand side vector for constraints to newRhs. scale determines whether the new data shoul...
Definition: spxlpbase.h:1555
comparator for class SVector::Element: compare nonzeros according to value
Definition: spxmainsm.h:1639
R obj(int i) const
Returns objective value of column i.
Definition: spxlpbase.h:407
const VectorBase< R > & lhs() const
Returns left hand side vector.
Definition: spxlpbase.h:255
friend class FixBoundsPS
Definition: spxmainsm.h:1266
DataArray< int > m_cIdx
column index vector in original LP.
Definition: spxmainsm.h:1312
Result m_result
result of the simplification.
Definition: spxmainsm.h:1330
#define MINIMUM(x, y)
Definition: spxdefines.h:247
variable set to its upper bound.
Definition: spxsolver.h:191
bool GTrel(Real a, Real b, Real eps=Param::epsilon())
returns true iff relDiff(a,b) > eps
Definition: spxdefines.h:448
void SPxQuicksort(T *keys, int end, COMPARATOR &compare, int start=0, bool type=true)
Generic QuickSort implementation.
Definition: sorter.h:74
virtual void execute(DVector &x, DVector &y, DVector &s, DVector &r, DataArray< SPxSolver::VarStatus > &cBasis, DataArray< SPxSolver::VarStatus > &rBasis, bool isOptimal) const
Definition: spxmainsm.cpp:88
virtual void changeBounds(const VectorBase< R > &newLower, const VectorBase< R > &newUpper, bool scale=false)
Changes variable bounds to newLower and newUpper. scale determines whether the new data should be sca...
Definition: spxlpbase.h:1485
primal infeasibility was detected
Definition: spxsimplifier.h:84
const VectorBase< R > & maxRowObj() const
Definition: spxlpbase.h:300
bool GErel(Real a, Real b, Real eps=Param::epsilon())
returns true iff relDiff(a,b) > -eps
Definition: spxdefines.h:454
variable set to its lower bound.
Definition: spxsolver.h:192
Generic QuickSort implementation.
Array< DSVector > m_dupCols
arrange duplicate columns w.r.t. their pClass values
Definition: spxmainsm.h:1321
int m_remRows
number of removed rows
Definition: spxsimplifier.h:54
#define MSG_INFO3(spxout, x)
Prints out message x if the verbosity level is at least SPxOut::INFO3.
Definition: spxdefines.h:122
void add(int i, const R &v)
Append one nonzero (i,v).
Definition: svectorbase.h:271
virtual void changeUpper(const VectorBase< R > &newUpper, bool scale=false)
Changes vector of upper bounds to newUpper. scale determines whether the new data should be scaled...
Definition: spxlpbase.h:1447
static Real epsilon()
Definition: spxdefines.cpp:45
Postsolves row objectives.
Definition: spxmainsm.h:136
bool EQ(Real a, Real b, Real eps=Param::epsilon())
returns true iff |a-b| <= eps
Definition: spxdefines.h:376
virtual void changeObj(const VectorBase< R > &newObj, bool scale=false)
Changes objective vector to newObj. scale determines whether the new data should be scaled...
Definition: spxlpbase.h:1335
DataArray< int > m_rIdx
row index vector in original LP.
Definition: spxmainsm.h:1313
Postsolves column singletons with zero objective.
Definition: spxmainsm.h:666
virtual void execute(DVector &x, DVector &y, DVector &s, DVector &r, DataArray< SPxSolver::VarStatus > &cBasis, DataArray< SPxSolver::VarStatus > &rBasis, bool isOptimal) const
Definition: spxmainsm.cpp:542
virtual void addCol(const LPColBase< R > &col, bool scale=false)
Definition: spxlpbase.h:757
int dim() const
Dimension of vector.
Definition: vectorbase.h:217
Exception base class.This class implements a base class for our SoPlex exceptions We provide a what()...
Definition: exceptions.h:32
bool m_keepbounds
keep some bounds (for boundflipping)
Definition: spxmainsm.h:1328
Everything should be within this namespace.
virtual void changeRange(const VectorBase< R > &newLhs, const VectorBase< R > &newRhs, bool scale=false)
Changes left and right hand side vectors. scale determines whether the new data should be scaled...
Definition: spxlpbase.h:1585
bool EQrel(Real a, Real b, Real eps=Param::epsilon())
returns true iff |relDiff(a,b)| <= eps
Definition: spxdefines.h:424
virtual bool checkBasisDim(DataArray< SPxSolver::VarStatus > rows, DataArray< SPxSolver::VarStatus > cols) const
Definition: spxmainsm.cpp:67
friend class ForceConstraintPS
Definition: spxmainsm.h:1264
void handleRowObjectives(SPxLP &lp)
handle row objectives
Definition: spxmainsm.cpp:1563
primal unboundedness was detected
Definition: spxsimplifier.h:86
Result aggregateVars(SPxLP &lp, const SVector &row, int &i)
aggregate two variables that appear in an equation.
Definition: spxmainsm.cpp:2273
#define MSG_WARNING(spxout, x)
Prints out message x if the verbosity level is at least SPxOut::WARNING.
Definition: spxdefines.h:116
Result duplicateRows(SPxLP &lp, bool &again)
removes duplicate rows.
Definition: spxmainsm.cpp:4142
Real m_cutoffbound
the cutoff bound that is found by heuristics
Definition: spxmainsm.h:1331
const VectorBase< R > & maxObj() const
Returns objective vector for maximization problem.
Definition: spxlpbase.h:434
friend class AggregationPS
Definition: spxmainsm.h:1273
Exception class for incorrect usage of interface methods.
Definition: exceptions.h:126
Result multiaggregation(SPxLP &lp, bool &again)
performs multi-aggregations of variable based upon constraint activitu.
Definition: spxmainsm.cpp:3893
Save arrays of arbitrary types.
Real m_objoffset
objective offset
Definition: spxsimplifier.h:68
friend class DuplicateColsPS
Definition: spxmainsm.h:1272
variable is basic.
Definition: spxsolver.h:195
bool NErel(Real a, Real b, Real eps=Param::epsilon())
returns true iff |relDiff(a,b)| > eps
Definition: spxdefines.h:430
const SVectorBase< R > & rowVector(int i) const
Gets row vector of row i.
Definition: spxlpbase.h:206
comparator for class SVector::Element: compare nonzeros according to index
Definition: spxmainsm.h:1656
virtual void changeRowObj(const VectorBase< R > &newRowObj, bool scale=false)
Changes row objective function vector to newRowObj. scale determines whether the new data should be s...
Definition: spxlpbase.h:1617
void trivialHeuristic(SPxLP &lp)
tries to find good lower bound solutions by applying some trivial heuristics
Definition: spxmainsm.cpp:1875
virtual void execute(DVector &x, DVector &y, DVector &s, DVector &r, DataArray< SPxSolver::VarStatus > &cBasis, DataArray< SPxSolver::VarStatus > &rBasis, bool isOptimal) const
Definition: spxmainsm.cpp:1520
int m_chgBnds
number of changed bounds
Definition: spxsimplifier.h:60
Postsolves duplicate columns.
Definition: spxmainsm.h:993
Result removeEmpty(SPxLP &lp)
removed empty rows and empty columns.
Definition: spxmainsm.cpp:2083
int size() const
return nr. of elements.
Definition: dataarray.h:214
Postsolves forcing constraints.
Definition: spxmainsm.h:364
Result simplifyDual(SPxLP &lp, bool &again)
performs simplification steps on the LP based on dual concepts.
Definition: spxmainsm.cpp:3631
Postsolves unconstraint constraints.
Definition: spxmainsm.h:180
int pos(int i) const
Position of index i.
Definition: svectorbase.h:186
SPxOut * spxout
Definition: spxlpbase.h:122
bool isConsistent() const
Consistency check.
Definition: spxlpbase.h:1938
Postsolves variable bound tightening from pseudo objective propagation.
Definition: spxmainsm.h:1220
#define MSG_INFO1(spxout, x)
Prints out message x if the verbosity level is at least SPxOut::INFO1.
Definition: spxdefines.h:118
int m_remCols
number of removed columns
Definition: spxsimplifier.h:56
virtual void execute(DVector &x, DVector &y, DVector &s, DVector &r, DataArray< SPxSolver::VarStatus > &cBasis, DataArray< SPxSolver::VarStatus > &rBasis, bool isOptimal) const
Definition: spxmainsm.cpp:1101
const SVectorBase< R > & colVector(int i) const
Returns column vector of column i.
Definition: spxlpbase.h:377
Postsolves variable fixing.
Definition: spxmainsm.h:456
int nCols() const
Returns number of columns in LP.
Definition: spxlpbase.h:158
virtual void execute(DVector &x, DVector &y, DVector &s, DVector &r, DataArray< SPxSolver::VarStatus > &cBasis, DataArray< SPxSolver::VarStatus > &rBasis, bool isOptimal) const
Definition: spxmainsm.cpp:550
virtual void changeElement(int i, int j, const R &val, bool scale=false)
Changes LP element (i, j) to val. scale determines whether the new data should be scaled...
Definition: spxlpbase.h:1750
friend class FreeColSingletonPS
Definition: spxmainsm.h:1269
bool LErel(Real a, Real b, Real eps=Param::epsilon())
returns true iff relDiff(a,b) <= eps
Definition: spxdefines.h:442
virtual void execute(DVector &x, DVector &y, DVector &s, DVector &r, DataArray< SPxSolver::VarStatus > &cBasis, DataArray< SPxSolver::VarStatus > &rBasis, bool isOptimal) const
Definition: spxmainsm.cpp:1340
virtual void changeLhs(const VectorBase< R > &newLhs, bool scale=false)
Changes left hand side vector for constraints to newLhs. scale determines whether the new data should...
Definition: spxlpbase.h:1517
Real m_pseudoobj
the pseudo objective function value
Definition: spxmainsm.h:1332
Postsolves aggregation.
Definition: spxmainsm.h:1061
friend class FreeZeroObjVariablePS
Definition: spxmainsm.h:1267
void computeMinMaxValues(SPxLP &lp, Real side, Real val, Real minRes, Real maxRes, Real &minVal, Real &maxVal)
calculate min/max value for the multi aggregated variables
Definition: spxmainsm.cpp:1841
int m_addedcols
columns added by handleRowObjectives()
Definition: spxmainsm.h:1329
friend class ZeroObjColSingletonPS
Definition: spxmainsm.h:1268
bool isZero(Real a, Real eps=Param::epsilon())
returns true iff |a| <= eps
Definition: spxdefines.h:412
void removeRow(SPxLP &lp, int i)
removes a row in the LP.
Definition: spxmainsm.h:1394
friend class EmptyConstraintPS
Definition: spxmainsm.h:1262
virtual void reset()=0
initialize timer, set timing accounts to zero.
int nCols
number of cols
Definition: spxmainsm.h:79
SPxOut * spxout
message handler
Definition: spxsimplifier.h:72
Save arrays of data objects.
SVectorBase< R > & colVector_w(int i)
Returns the LP as an LPRowSet.
Definition: spxlpbase.h:2239
int m_chgLRhs
number of change right-hand sides
Definition: spxsimplifier.h:62
Result simplifyCols(SPxLP &lp, bool &again)
performs simplification steps on the columns of the LP.
Definition: spxmainsm.cpp:3081
Array< DSVector > m_dupRows
arrange duplicate rows using bucket sort w.r.t. their pClass values
Definition: spxmainsm.h:1319
void reSize(int newsize)
reset size to newsize.
Definition: dataarray.h:226
DVector m_slack
unsimplified slack vector.
Definition: spxmainsm.h:1307
virtual void execute(DVector &x, DVector &y, DVector &s, DVector &r, DataArray< SPxSolver::VarStatus > &cBasis, DataArray< SPxSolver::VarStatus > &rBasis, bool isOptimal) const
Definition: spxmainsm.cpp:133
const VectorBase< R > & lower() const
Returns (internal and possibly scaled) lower bound vector.
Definition: spxlpbase.h:488
virtual void execute(DVector &x, DVector &y, DVector &s, DVector &r, DataArray< SPxSolver::VarStatus > &cBasis, DataArray< SPxSolver::VarStatus > &rBasis, bool isOptimal) const
Definition: spxmainsm.cpp:708
Set of indices.Class IdxSet provides a set of indices. At construction it must be given an array of i...
Definition: idxset.h:56
void spx_free(T &p)
Release memory.
Definition: spxalloc.h:110
DataArray< SPxSolver::VarStatus > m_cBasisStat
basis status of columns.
Definition: spxmainsm.h:1310
void propagatePseudoobj(SPxLP &lp)
tightens variable bounds by propagating the pseudo objective function value.
Definition: spxmainsm.cpp:2017
dual infeasibility was detected
Definition: spxsimplifier.h:85
Array< DSVector > m_classSetRows
stores parallel classes with non-zero colum entry
Definition: spxmainsm.h:1316
friend class FixVariablePS
Definition: spxmainsm.h:1265
Real epsZero() const
Definition: spxmainsm.h:1420
DVector m_redCost
unsimplified reduced cost vector.
Definition: spxmainsm.h:1309