Scippy

SoPlex

Sequential object-oriented simPlex

spxboundflippingrt.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-2015 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 <assert.h>
17 #include "spxdefines.h"
18 #include "spxboundflippingrt.h"
19 #include "sorter.h"
20 #include "spxsolver.h"
21 #include "spxout.h"
22 #include "spxid.h"
23 
24 namespace soplex
25 {
26 
27 #define LOWSTAB 1e-10
28 #define MAX_RELAX_COUNT 2
29 #define LONGSTEP_FREQ 100
30 
31 
32 /** perform necessary bound flips to restore dual feasibility */
34  int& nflips /**< number of bounds that should be flipped */
35  )
36 {
37  assert(nflips > 0);
38 
39  // number of bound flips that are not performed
40  int skipped;
41 
42  updPrimRhs.setup();
45  updPrimRhs.clear();
46  updPrimVec.clear();
47 
48  skipped = 0;
49  for( int i = 0; i < nflips; ++i )
50  {
51  int idx;
52  idx = breakpoints[i].idx;
53  if( idx < 0 )
54  {
55  ++skipped;
56  continue;
57  }
58  Real range;
59  Real upper;
60  Real lower;
61  Real objChange = 0.0;
64 
65  range = 0;
66  if( breakpoints[i].src == PVEC )
67  {
68  assert(thesolver->rep() == SPxSolver::COLUMN);
69  stat = ds.status(idx);
70  upper = thesolver->upper(idx);
71  lower = thesolver->lower(idx);
72  switch( stat )
73  {
76  range = lower - upper;
77  assert((*thesolver->theLbound)[idx] == -infinity);
78  (*thesolver->theLbound)[idx] = (*thesolver->theUbound)[idx];
79  (*thesolver->theUbound)[idx] = infinity;
80  objChange = range * (*thesolver->theLbound)[idx];
81  break;
84  range = upper - lower;
85  assert((*thesolver->theUbound)[idx] == infinity);
86  (*thesolver->theUbound)[idx] = (*thesolver->theLbound)[idx];
87  (*thesolver->theLbound)[idx] = -infinity;
88  objChange = range * (*thesolver->theUbound)[idx];
89  break;
90  default :
91  ++skipped;
92  MSG_WARNING( (*thesolver->spxout), (*thesolver->spxout) << "PVEC unexpected status: " << stat
93  << " index: " << idx
94  << " val: " << thesolver->pVec()[idx]
95  << " upd: " << thesolver->pVec().delta()[idx]
96  << " lower: " << lower
97  << " upper: " << upper
98  << " bp.val: " << breakpoints[i].val
99  << std::endl; )
100  }
101  MSG_DEBUG( std::cout << "PVEC flipped from: " << stat
102  << " index: " << idx
103  << " val: " << thesolver->pVec()[idx]
104  << " upd: " << thesolver->pVec().delta()[idx]
105  << " lower: " << lower
106  << " upper: " << upper
107  << " bp.val: " << breakpoints[i].val
108  << " UCbound: " << thesolver->theUCbound[idx]
109  << " LCbound: " << thesolver->theLCbound[idx]
110  << std::endl; )
111  assert(spxAbs(range) < 1e20);
112  updPrimRhs.multAdd(range, thesolver->vector(idx));
113  if( objChange != 0.0 )
114  thesolver->updateNonbasicValue(objChange);
115  }
116  else if( breakpoints[i].src == COPVEC )
117  {
118  assert(thesolver->rep() == SPxSolver::COLUMN);
119  stat = ds.coStatus(idx);
120  upper = thesolver->rhs(idx);
121  lower = thesolver->lhs(idx);
122  switch( stat )
123  {
126  range = lower - upper;
127  assert((*thesolver->theCoUbound)[idx] == infinity);
128  (*thesolver->theCoUbound)[idx] = -(*thesolver->theCoLbound)[idx];
129  (*thesolver->theCoLbound)[idx] = -infinity;
130  objChange = range * (*thesolver->theCoUbound)[idx];
131  break;
134  range = upper - lower;
135  assert((*thesolver->theCoLbound)[idx] == -infinity);
136  (*thesolver->theCoLbound)[idx] = -(*thesolver->theCoUbound)[idx];
137  (*thesolver->theCoUbound)[idx] = infinity;
138  objChange = range * (*thesolver->theCoLbound)[idx];
139  break;
140  default :
141  ++skipped;
142  MSG_WARNING( (*thesolver->spxout), (*thesolver->spxout) << "COPVEC unexpected status: " << stat
143  << " index: " << idx
144  << " val: " << thesolver->coPvec()[idx]
145  << " upd: " << thesolver->coPvec().delta()[idx]
146  << " lower: " << lower
147  << " upper: " << upper
148  << " bp.val: " << breakpoints[i].val
149  << std::endl; )
150  }
151  MSG_DEBUG( std::cout << "COPVEC flipped from: " << stat
152  << " index: " << idx
153  << " val: " << thesolver->coPvec()[idx]
154  << " upd: " << thesolver->coPvec().delta()[idx]
155  << " lower: " << lower
156  << " upper: " << upper
157  << " bp.val: " << breakpoints[i].val
158  << " URbound: " << thesolver->theURbound[idx]
159  << " LRbound: " << thesolver->theLRbound[idx]
160  << std::endl; )
161  assert(spxAbs(range) < 1e20);
162  updPrimRhs.setValue(idx, updPrimRhs[idx] - range);
163  if( objChange != 0.0 )
164  thesolver->updateNonbasicValue(objChange);
165  }
166  else if( breakpoints[i].src == FVEC )
167  {
168  assert(thesolver->rep() == SPxSolver::ROW);
169  SPxId baseId = thesolver->basis().baseId(idx);
170  int IdNumber;
171 
172  if( baseId.isSPxRowId() )
173  {
174  IdNumber = thesolver->number(SPxRowId(baseId));
175  stat = ds.rowStatus(IdNumber);
176  upper = thesolver->rhs(IdNumber);
177  lower = thesolver->lhs(IdNumber);
178  switch( stat )
179  {
181  ds.rowStatus(IdNumber) = SPxBasis::Desc::P_ON_LOWER;
182  range = upper - lower;
183  assert(thesolver->theUBbound[idx] == infinity);
184  thesolver->theUBbound[idx] = -thesolver->theLBbound[idx];
185  thesolver->theLBbound[idx] = -infinity;
186  break;
188  ds.rowStatus(IdNumber) = SPxBasis::Desc::P_ON_UPPER;
189  range = lower - upper;
190  assert(thesolver->theLBbound[idx] == -infinity);
191  thesolver->theLBbound[idx] = -thesolver->theUBbound[idx];
192  thesolver->theUBbound[idx] = infinity;
193  break;
194  default :
195  ++skipped;
196  MSG_WARNING( (*thesolver->spxout), (*thesolver->spxout) << "unexpected basis status: " << stat
197  << " index: " << idx
198  << " val: " << thesolver->fVec()[idx]
199  << " upd: " << thesolver->fVec().delta()[idx]
200  << " lower: " << lower
201  << " upper: " << upper
202  << " bp.val: " << breakpoints[i].val
203  << std::endl; )
204  }
205  }
206  else
207  {
208  assert(baseId.isSPxColId());
209  IdNumber = thesolver->number(SPxColId(baseId));
210  stat = ds.colStatus(IdNumber);
211  upper = thesolver->upper(IdNumber);
212  lower = thesolver->lower(IdNumber);
213 
214  switch( stat )
215  {
217  ds.colStatus(IdNumber) = SPxBasis::Desc::P_ON_LOWER;
218  range = upper - lower;
219  assert(thesolver->theUBbound[idx] == infinity);
220  thesolver->theUBbound[idx] = -thesolver->theLBbound[idx];
221  thesolver->theLBbound[idx] = -infinity;
222  break;
224  ds.colStatus(IdNumber) = SPxBasis::Desc::P_ON_UPPER;
225  range = lower - upper;
226  assert(thesolver->theLBbound[idx] == -infinity);
227  thesolver->theLBbound[idx] = -thesolver->theUBbound[idx];
228  thesolver->theUBbound[idx] = infinity;
229  break;
230  default :
231  ++skipped;
232  MSG_WARNING( (*thesolver->spxout), (*thesolver->spxout) << "FVEC unexpected status: " << stat
233  << " index: " << idx
234  << " val: " << thesolver->fVec()[idx]
235  << " upd: " << thesolver->fVec().delta()[idx]
236  << " lower: " << lower
237  << " upper: " << upper
238  << " bp.val: " << breakpoints[i].val
239  << std::endl; )
240  }
241  }
242  MSG_DEBUG( std::cout << "basic row/col flipped from: " << stat
243  << " index: " << idx
244  << " val: " << thesolver->fVec()[idx]
245  << " upd: " << thesolver->fVec().delta()[idx]
246  << " lower: " << lower
247  << " upper: " << upper
248  << " bp.val: " << breakpoints[i].val
249  << std::endl; )
250  assert(spxAbs(range) < 1e20);
251  assert(updPrimRhs[idx] == 0);
252  updPrimRhs.add(idx, range);
253  }
254  }
255  nflips -= skipped;
256  if( nflips > 0 )
257  {
258  if(thesolver->rep() == SPxSolver::ROW)
259  {
260  assert(m_type == SPxSolver::ENTER);
263  }
264  else
265  {
266  assert(thesolver->rep() == SPxSolver::COLUMN);
267  assert(m_type == SPxSolver::LEAVE);
270  }
271  }
272 
273  return;
274 }
275 
276 /** store all available pivots/breakpoints in an array (positive pivot search direction) */
278  int& nBp, /**< number of found breakpoints so far */
279  int& minIdx, /**< index to current minimal breakpoint */
280  const int* idx, /**< pointer to indices of current vector */
281  int nnz, /**< number of nonzeros in current vector */
282  const Real* upd, /**< pointer to update values of current vector */
283  const Real* vec, /**< pointer to values of current vector */
284  const Real* upp, /**< pointer to upper bound/rhs of current vector */
285  const Real* low, /**< pointer to lower bound/lhs of current vector */
286  BreakpointSource src /**< type of vector (pVec, coPvec or fVec)*/
287  )
288 {
289  Real minVal;
290  Real curVal;
291  const int* last;
292 
293  minVal = ( nBp == 0 ) ? infinity : breakpoints[minIdx].val;
294 
295  last = idx + nnz;
296  for( ; idx < last; ++idx )
297  {
298  int i = *idx;
299  Real x = upd[i];
300  if( x > epsilon )
301  {
302  if( upp[i] < infinity )
303  {
304  Real y = upp[i] - vec[i];
305  curVal = (y <= 0) ? fastDelta / x : (y + fastDelta) / x;
306  assert(curVal > 0);
307 
308  breakpoints[nBp].idx = i;
309  breakpoints[nBp].src = src;
310  breakpoints[nBp].val = curVal;
311 
312  if( curVal < minVal )
313  {
314  minVal = curVal;
315  minIdx = nBp;
316  }
317 
318  nBp++;
319  }
320  }
321  else if( x < -epsilon )
322  {
323  if (low[i] > -infinity)
324  {
325  Real y = low[i] - vec[i];
326  curVal = (y >= 0) ? -fastDelta / x : (y - fastDelta) / x;
327  assert(curVal > 0);
328 
329  breakpoints[nBp].idx = i;
330  breakpoints[nBp].src = src;
331  breakpoints[nBp].val = curVal;
332 
333  if( curVal < minVal )
334  {
335  minVal = curVal;
336  minIdx = nBp;
337  }
338 
339  nBp++;
340  }
341  }
342  if( nBp >= breakpoints.size() )
343  breakpoints.reSize(nBp * 2);
344  }
345 
346  return;
347 }
348 
349 /** store all available pivots/breakpoints in an array (negative pivot search direction) */
351  int& nBp, /**< number of found breakpoints so far */
352  int& minIdx, /**< index to current minimal breakpoint */
353  const int* idx, /**< pointer to indices of current vector */
354  int nnz, /**< number of nonzeros in current vector */
355  const Real* upd, /**< pointer to update values of current vector */
356  const Real* vec, /**< pointer to values of current vector */
357  const Real* upp, /**< pointer to upper bound/rhs of current vector */
358  const Real* low, /**< pointer to lower bound/lhs of current vector */
359  BreakpointSource src /**< type of vector (pVec, coPvec or fVec)*/
360  )
361 {
362  Real minVal;
363  Real curVal;
364  const int* last;
365 
366  minVal = ( nBp == 0 ) ? infinity : breakpoints[minIdx].val;
367 
368  last = idx + nnz;
369 
370  for( ; idx < last; ++idx )
371  {
372  int i = *idx;
373  Real x = upd[i];
374  if( x > epsilon )
375  {
376  if( low[i] > -infinity )
377  {
378  Real y = low[i] - vec[i];
379 
380  curVal = (y >= 0) ? fastDelta / x : (fastDelta - y) / x;
381  assert(curVal > 0);
382 
383  breakpoints[nBp].idx = i;
384  breakpoints[nBp].src = src;
385  breakpoints[nBp].val = curVal;
386 
387  if( curVal < minVal )
388  {
389  minVal = curVal;
390  minIdx = nBp;
391  }
392 
393  nBp++;
394  }
395  }
396  else if( x < -epsilon )
397  {
398  if (upp[i] < infinity)
399  {
400  Real y = upp[i] - vec[i];
401  curVal = (y <= 0) ? -fastDelta / x : -(y + fastDelta) / x;
402  assert(curVal > 0);
403 
404  breakpoints[nBp].idx = i;
405  breakpoints[nBp].src = src;
406  breakpoints[nBp].val = curVal;
407 
408  if( curVal < minVal )
409  {
410  minVal = curVal;
411  minIdx = nBp;
412  }
413 
414  nBp++;
415  }
416  }
417  if( nBp >= breakpoints.size() )
418  breakpoints.reSize(nBp * 2);
419  }
420  return;
421 }
422 
423 /** get values for entering index and perform shifts if necessary */
425  Real& val,
426  SPxId& enterId,
427  int idx,
428  Real stab,
429  Real degeneps,
430  const Real* upd,
431  const Real* vec,
432  const Real* low,
433  const Real* upp,
434  BreakpointSource src,
435  Real max
436  )
437 {
438  if( src == PVEC )
439  {
440  thesolver->pVec()[idx] = thesolver->vector(idx) * thesolver->coPvec();
441  Real x = upd[idx];
442  // skip breakpoint if it is too small
443  if( spxAbs(x) < stab )
444  {
445  return false;
446  }
447  enterId = thesolver->id(idx);
448  val = (max * x > 0) ? upp[idx] : low[idx];
449  val = (val - vec[idx]) / x;
450  if( upp[idx] == low[idx] )
451  {
452  val = 0.0;
453  if( vec[idx] > upp[idx] )
454  thesolver->theShift += vec[idx] - upp[idx];
455  else
456  thesolver->theShift += low[idx] - vec[idx];
457  thesolver->upBound()[idx] = thesolver->lpBound()[idx] = vec[idx];
458  }
459  else if( (max > 0 && val < -degeneps) || (max < 0 && val > degeneps) )
460  {
461  val = 0.0;
462  if( max * x > 0 )
463  thesolver->shiftUPbound(idx, vec[idx]);
464  else
465  thesolver->shiftLPbound(idx, vec[idx]);
466  }
467  }
468  else // src == COPVEC
469  {
470  Real x = upd[idx];
471  if( spxAbs(x) < stab )
472  {
473  return false;
474  }
475  enterId = thesolver->coId(idx);
476  val = (max * x > 0.0) ? upp[idx] : low[idx];
477  val = (val - vec[idx]) / x;
478  if( upp[idx] == low[idx] )
479  {
480  val = 0.0;
481  if( vec[idx] > upp[idx] )
482  thesolver->theShift += vec[idx] - upp[idx];
483  else
484  thesolver->theShift += low[idx] - vec[idx];
485  thesolver->ucBound()[idx] = thesolver->lcBound()[idx] = vec[idx];
486  }
487  else if( (max > 0 && val < -degeneps) || (max < 0 && val > degeneps) )
488  {
489  val = 0.0;
490  if( max * x > 0 )
491  thesolver->shiftUCbound(idx, vec[idx]);
492  else
493  thesolver->shiftLCbound(idx, vec[idx]);
494  }
495  }
496  return true;
497 }
498 
499 /** get values for leaving index and perform shifts if necessary */
501  Real& val,
502  int& leaveIdx,
503  int idx,
504  Real stab,
505  Real degeneps,
506  const Real* upd,
507  const Real* vec,
508  const Real* low,
509  const Real* upp,
510  BreakpointSource src,
511  Real max
512  )
513 {
514  assert( src == FVEC );
515 
516  Real x = upd[idx];
517  // skip breakpoint if it is too small
518  if( spxAbs(x) < stab )
519  {
520  return false;
521  }
522  leaveIdx = idx;
523  val = (max * x > 0) ? upp[idx] : low[idx];
524  val = (val - vec[idx]) / x;
525  if( upp[idx] == low[idx] )
526  {
527  val = 0.0;
528  thesolver->shiftLBbound(idx, vec[idx]);
529  thesolver->shiftUBbound(idx, vec[idx]);
530  }
531  else if( (max > 0 && val < -degeneps) || (max < 0 && val > degeneps) )
532  {
533  val = 0.0;
535  {
536  if( max * x > 0 )
537  thesolver->shiftUBbound(idx, vec[idx]);
538  else
539  thesolver->shiftLBbound(idx, vec[idx]);
540  }
541  }
542  return true;
543 }
544 
545 /** determine entering row/column */
547  Real& val,
548  int leaveIdx
549  )
550 {
551  assert( m_type == SPxSolver::LEAVE );
552  assert(thesolver->boundflips == 0);
553 
554  // reset the history and try again to do some long steps
555  if( thesolver->leaveCount % LONGSTEP_FREQ == 0 )
556  {
557  MSG_DEBUG( std::cout << "DLBFRT06 resetting long step history" << std::endl; )
558  flipPotential = 1;
559  }
561  {
562  MSG_DEBUG( std::cout << "DLBFRT07 switching to fast ratio test" << std::endl; )
563  return SPxFastRT::selectEnter(val, leaveIdx);
564  }
565  const Real* pvec = thesolver->pVec().get_const_ptr();
566  const Real* pupd = thesolver->pVec().delta().values();
567  const int* pidx = thesolver->pVec().delta().indexMem();
568  int pupdnnz = thesolver->pVec().delta().size();
569  const Real* lpb = thesolver->lpBound().get_const_ptr();
570  const Real* upb = thesolver->upBound().get_const_ptr();
571 
572  const Real* cvec = thesolver->coPvec().get_const_ptr();
573  const Real* cupd = thesolver->coPvec().delta().values();
574  const int* cidx = thesolver->coPvec().delta().indexMem();
575  int cupdnnz = thesolver->coPvec().delta().size();
576  const Real* lcb = thesolver->lcBound().get_const_ptr();
577  const Real* ucb = thesolver->ucBound().get_const_ptr();
578 
579  resetTols();
580 
581  Real max;
582 
583  // index in breakpoint array of minimal value (i.e. choice of normal RT)
584  int minIdx;
585 
586  // temporary breakpoint data structure to make swaps possible
587  Breakpoint tmp;
588 
589  // most stable pivot value in candidate set
590  Real moststable;
591 
592  // initialize invalid enterId
593  SPxId enterId;
594 
595  // slope of objective function improvement
596  Real slope;
597 
598  // number of found breakpoints
599  int nBp;
600 
601  // number of passed breakpoints
602  int npassedBp;
603 
604  Real degeneps;
605  Real stab;
606  bool instable;
607 
608  max = val;
609  val = 0.0;
610  moststable = 0.0;
611  nBp = 0;
612  minIdx = -1;
613 
614  // get breakpoints and and determine the index of the minimal value
615  if( max > 0 )
616  {
617  collectBreakpointsMax(nBp, minIdx, pidx, pupdnnz, pupd, pvec, upb, lpb, PVEC);
618  collectBreakpointsMax(nBp, minIdx, cidx, cupdnnz, cupd, cvec, ucb, lcb, COPVEC);
619  }
620  else
621  {
622  collectBreakpointsMin(nBp, minIdx, pidx, pupdnnz, pupd, pvec, upb, lpb, PVEC);
623  collectBreakpointsMin(nBp, minIdx, cidx, cupdnnz, cupd, cvec, ucb, lcb, COPVEC);
624  }
625 
626  if( nBp == 0 )
627  {
628  val = max;
629  return enterId;
630  }
631 
632  assert(minIdx >= 0);
633 
634  // swap smallest breakpoint to the front to skip the sorting phase if no bound flip is possible
635  tmp = breakpoints[minIdx];
636  breakpoints[minIdx] = breakpoints[0];
637  breakpoints[0] = tmp;
638 
639  // get initial slope
640  slope = spxAbs(thesolver->fTest()[leaveIdx]);
641  if( slope == 0 )
642  {
643  // this may only happen if SoPlex decides to make an instable pivot
644  assert(thesolver->instableLeaveNum >= 0);
645  // restore original slope
647  }
648 
649  // set up structures for the quicksort implementation
650  BreakpointCompare compare;
651  compare.entry = breakpoints.get_const_ptr();
652 
653  // pointer to end of sorted part of breakpoints
654  int sorted = 0;
655  // minimum number of entries that are supposed to be sorted by partial sort
656  int sortsize = 4;
657 
658  // get all skipable breakpoints
659  for( npassedBp = 0; npassedBp < nBp && slope > 0; ++npassedBp)
660  {
661  // sort breakpoints only partially to save time
662  if( npassedBp > sorted )
663  {
664  sorted = SPxQuicksortPart(breakpoints.get_ptr(), compare, sorted + 1, nBp, sortsize);
665  }
666  int i = breakpoints[npassedBp].idx;
667  // compute new slope
668  if( breakpoints[npassedBp].src == PVEC )
669  {
670  if( thesolver->isBasic(i) )
671  {
672  // mark basic indices
673  breakpoints[npassedBp].idx = -1;
674  thesolver->pVec().delta().clearIdx(i);
675  }
676  else
677  {
678  Real absupd = spxAbs(pupd[i]);
679  slope -= (thesolver->upper(i) * absupd) - (thesolver->lower(i) * absupd);
680  // get most stable pivot
681  if( absupd > moststable )
682  moststable = absupd;
683  }
684  }
685  else
686  {
687  assert(breakpoints[npassedBp].src == COPVEC);
688  if( thesolver->isCoBasic(i) )
689  {
690  // mark basic indices
691  breakpoints[npassedBp].idx = -1;
692  thesolver->coPvec().delta().clearIdx(i);
693  }
694  else
695  {
696  Real absupd = spxAbs(cupd[i]);
697  slope -= (thesolver->rhs(i) * absupd) - (thesolver->lhs(i) * absupd);
698  if( absupd > moststable )
699  moststable = absupd;
700  }
701  }
702  }
703  --npassedBp;
704  assert(npassedBp >= 0);
705 
706  // check for unboundedness/infeasibility
707  if( slope > delta && npassedBp >= nBp - 1 )
708  {
709  MSG_DEBUG( std::cout << "DLBFRT02 " << thesolver->basis().iteration()
710  << ": unboundedness in ratio test" << std::endl; )
711  flipPotential -= 0.5;
712  val = max;
713  return SPxFastRT::selectEnter(val, leaveIdx);
714  }
715 
716  MSG_DEBUG( std::cout << "DLBFRT01 "
717  << thesolver->basis().iteration()
718  << ": number of flip candidates: "
719  << npassedBp
720  << std::endl; )
721 
722  // try to get a more stable pivot by looking at those with similar step length
723  int stableBp; // index to walk over additional breakpoints (after slope change)
724  int bestBp = -1; // breakpoints index with best possible stability
725  Real bestDelta = breakpoints[npassedBp].val; // best step length (after bound flips)
726 
727  for( stableBp = npassedBp + 1; stableBp < nBp; ++stableBp )
728  {
729  Real stableDelta = 0;
730  // get next breakpoints in increasing order
731  if( stableBp > sorted )
732  {
733  sorted = SPxQuicksortPart(breakpoints.get_ptr(), compare, sorted + 1, nBp, sortsize);
734  }
735  int idx = breakpoints[stableBp].idx;
736  if( breakpoints[stableBp].src == PVEC )
737  {
738  if( thesolver->isBasic(idx) )
739  {
740  // mark basic indices
741  breakpoints[stableBp].idx = -1;
742  thesolver->pVec().delta().clearIdx(idx);
743  continue;
744  }
745  Real x = pupd[idx];
746  if( spxAbs(x) > moststable )
747  {
748  thesolver->pVec()[idx] = thesolver->vector(idx) * thesolver->coPvec();
749  stableDelta = (x > 0.0) ? upb[idx] : lpb[idx];
750  stableDelta = (stableDelta - pvec[idx]) / x;
751 
752  if( stableDelta <= bestDelta)
753  {
754  moststable = spxAbs(x);
755  bestBp = stableBp;
756  }
757  }
758  }
759  else
760  {
761  if( thesolver->isCoBasic(idx) )
762  {
763  // mark basic indices
764  breakpoints[stableBp].idx = -1;
765  thesolver->coPvec().delta().clearIdx(idx);
766  continue;
767  }
768  Real x = cupd[idx];
769  if( spxAbs(x) > moststable )
770  {
771  stableDelta = (x > 0.0) ? ucb[idx] : lcb[idx];
772  stableDelta = (stableDelta - cvec[idx]) / x;
773 
774  if( stableDelta <= bestDelta )
775  {
776  moststable = spxAbs(x);
777  bestBp = stableBp;
778  }
779  }
780  }
781 
782  // stop searching if the step length is too big
783  if( stableDelta > delta + bestDelta )
784  break;
785  }
786 
787  degeneps = fastDelta / moststable; /* as in SPxFastRT */
788  // get stability requirements
789  instable = thesolver->instableLeave;
790  assert(!instable || thesolver->instableLeaveNum >= 0);
791  stab = instable ? LOWSTAB : SPxFastRT::minStability(moststable);
792 
793  bool foundStable = false;
794 
795  if( bestBp >= 0 )
796  {
797  // found a more stable pivot
798  if( moststable > stab )
799  {
800  // stability requirements are satisfied
801  int idx = breakpoints[bestBp].idx;
802  assert(idx >= 0);
803  if( breakpoints[bestBp].src == PVEC )
804  foundStable = getData(val, enterId, idx, stab, degeneps, pupd, pvec, lpb, upb, PVEC, max);
805  else
806  foundStable = getData(val, enterId, idx, stab, degeneps, cupd, cvec, lcb, ucb, COPVEC, max);
807  }
808  }
809 
810  else
811  {
812  // scan passed breakpoints from back to front and stop as soon as a good one is found
813  while( !foundStable && npassedBp >= 0 )
814  {
815  int idx = breakpoints[npassedBp].idx;
816 
817  // only look for non-basic variables
818  if( idx >= 0 )
819  {
820  if( breakpoints[npassedBp].src == PVEC )
821  foundStable = getData(val, enterId, idx, stab, degeneps, pupd, pvec, lpb, upb, PVEC, max);
822  else
823  foundStable = getData(val, enterId, idx, stab, degeneps, cupd, cvec, lcb, ucb, COPVEC, max);
824  }
825  --npassedBp;
826  }
827  ++npassedBp;
828  }
829 
830  if( !foundStable )
831  {
832  assert(!enterId.isValid());
834  {
835  MSG_DEBUG( std::cout << "DLBFRT04 "
836  << thesolver->basis().iteration()
837  << ": no valid enterId found - relaxing..."
838  << std::endl; )
839  relax();
840  ++relax_count;
841  // restore original value
842  val = max;
843  // try again with relaxed delta
844  return SPxBoundFlippingRT::selectEnter(val, leaveIdx);
845  }
846  else
847  {
848  MSG_DEBUG( std::cout << "DLBFRT05 "
849  << thesolver->basis().iteration()
850  << " no valid enterId found - breaking..."
851  << std::endl; )
852  return enterId;
853  }
854  }
855  else
856  {
857  relax_count = 0;
858  tighten();
859  }
860 
861  // flip bounds of skipped breakpoints only if a nondegenerate step is to be performed
862  if( npassedBp > 0 && spxAbs(breakpoints[npassedBp].val) > fastDelta )
863  {
864  flipAndUpdate(npassedBp);
865  thesolver->boundflips = npassedBp;
866  if( npassedBp >= 10 )
867  flipPotential = 1;
868  else
869  flipPotential -= 0.05;
870  }
871  else
872  {
873  thesolver->boundflips = 0;
874  flipPotential -= 0.1;
875  }
876 
877  MSG_DEBUG( std::cout << "DLBFRT06 "
878  << thesolver->basis().iteration()
879  << ": selected Id: "
880  << enterId
881  << " number of candidates: "
882  << nBp
883  << std::endl; )
884  return enterId;
885 }
886 
887 /** determine leaving row/column */
889  Real& val,
890  Real enterTest
891  )
892 {
893  assert( m_type == SPxSolver::ENTER );
894  assert(thesolver->boundflips == 0);
895 
896  // reset the history and try again to do some long steps
897  if( thesolver->enterCount % LONGSTEP_FREQ == 0 )
898  {
899  MSG_DEBUG( std::cout << "DEBFRT06 resetting long step history" << std::endl; )
900  flipPotential = 1;
901  }
902 
904  {
905  MSG_DEBUG( std::cout << "DEBFRT07 switching to fast ratio test" << std::endl; )
906  return SPxFastRT::selectLeave(val, enterTest);
907  }
908 
909  const Real* vec = thesolver->fVec().get_const_ptr(); /**< pointer to values of current vector */
910  const Real* upd = thesolver->fVec().delta().values(); /**< pointer to update values of current vector */
911  const int* idx = thesolver->fVec().delta().indexMem(); /**< pointer to indices of current vector */
912  int updnnz = thesolver->fVec().delta().size(); /**< number of nonzeros in update vector */
913  const Real* lb = thesolver->lbBound().get_const_ptr(); /**< pointer to lower bound/lhs of current vector */
914  const Real* ub = thesolver->ubBound().get_const_ptr(); /**< pointer to upper bound/rhs of current vector */
915 
916  resetTols();
917 
918  Real max;
919 
920  // index in breakpoint array of minimal value (i.e. choice of normal RT)
921  int minIdx;
922 
923  // temporary breakpoint data structure to make swaps possible
924  Breakpoint tmp;
925 
926  // most stable pivot value in candidate set
927  Real moststable;
928 
929  // initialize invalid leaving index
930  int leaveIdx = -1;
931 
932  // slope of objective function improvement
933  Real slope;
934 
935  // number of found breakpoints
936  int nBp;
937 
938  // number of passed breakpoints
939  int npassedBp;
940 
941  Real degeneps;
942  Real stab;
943  bool instable;
944 
945  max = val;
946  val = 0.0;
947  moststable = 0.0;
948  nBp = 0;
949  minIdx = -1;
950 
951  assert(thesolver->fVec().delta().isSetup());
952 
953  // get breakpoints and and determine the index of the minimal value
954  if( max > 0 )
955  {
956  collectBreakpointsMax(nBp, minIdx, idx, updnnz, upd, vec, ub, lb, FVEC);
957  }
958  else
959  {
960  collectBreakpointsMin(nBp, minIdx, idx, updnnz, upd, vec, ub, lb, FVEC);
961  }
962 
963  // return -1 if no BP was found
964  if( nBp == 0 )
965  {
966  val = max;
967  return leaveIdx;
968  }
969 
970  assert(minIdx >= 0);
971 
972  // swap smallest breakpoint to the front to skip the sorting phase if no bound flip is possible
973  tmp = breakpoints[minIdx];
974  breakpoints[minIdx] = breakpoints[0];
975  breakpoints[0] = tmp;
976 
977  // get initial slope
978  slope = spxAbs(enterTest);
979  if( slope == 0 )
980  {
981  // this may only happen if SoPlex decides to make an instable pivot
982  assert(thesolver->instableEnterId.isValid());
983  // restore original slope
984  slope = thesolver->instableEnterVal;
985  }
986 
987  // set up structures for the quicksort implementation
988  BreakpointCompare compare;
989  compare.entry = breakpoints.get_const_ptr();
990 
991  // pointer to end of sorted part of breakpoints
992  int sorted = 0;
993  // minimum number of entries that are supposed to be sorted by partial sort
994  int sortsize = 4;
995 
996  // get all skipable breakpoints
997  for( npassedBp = 0; npassedBp < nBp && slope > 0; ++npassedBp)
998  {
999  // sort breakpoints only partially to save time
1000  if( npassedBp > sorted )
1001  {
1002  sorted = SPxQuicksortPart(breakpoints.get_ptr(), compare, sorted + 1, nBp, sortsize);
1003  }
1004  assert( breakpoints[npassedBp].src == FVEC );
1005  int breakpointidx = breakpoints[npassedBp].idx;
1006  // compute new slope
1007  Real upper;
1008  Real lower;
1009  Real absupd = spxAbs(upd[breakpointidx]);
1010  SPxId baseId = thesolver->baseId(breakpointidx);
1011  int i = thesolver->number(baseId);
1012  if( baseId.isSPxColId() )
1013  {
1014  upper = thesolver->upper(i);
1015  lower = thesolver->lower(i);
1016  }
1017  else
1018  {
1019  assert(baseId.isSPxRowId());
1020  upper = thesolver->rhs(i);
1021  lower = thesolver->lhs(i);
1022  }
1023 
1024  slope -= (upper * absupd) - (lower * absupd);
1025  // get most stable pivot
1026  if( absupd > moststable )
1027  moststable = absupd;
1028  }
1029  --npassedBp;
1030  assert(npassedBp >= 0);
1031 
1032  // check for unboundedness/infeasibility
1033  if( slope > delta && npassedBp >= nBp - 1 )
1034  {
1035  MSG_DEBUG( std::cout << "DEBFRT02 " << thesolver->basis().iteration()
1036  << ": unboundedness in ratio test" << std::endl; )
1037  flipPotential -= 0.5;
1038  val = max;
1039  return SPxFastRT::selectLeave(val, enterTest);
1040  }
1041 
1042  MSG_DEBUG( std::cout << "DEBFRT01 "
1043  << thesolver->basis().iteration()
1044  << ": number of flip candidates: "
1045  << npassedBp
1046  << std::endl; )
1047 
1048  // try to get a more stable pivot by looking at those with similar step length
1049  int stableBp; // index to walk over additional breakpoints (after slope change)
1050  int bestBp = -1; // breakpoints index with best possible stability
1051  Real bestDelta = breakpoints[npassedBp].val; // best step length (after bound flips)
1052 
1053  for( stableBp = npassedBp + 1; stableBp < nBp; ++stableBp )
1054  {
1055  Real stableDelta = 0;
1056  // get next breakpoints in increasing order
1057  if( stableBp > sorted )
1058  {
1059  sorted = SPxQuicksortPart(breakpoints.get_ptr(), compare, sorted + 1, nBp, sortsize);
1060  }
1061  int breakpointidx = breakpoints[stableBp].idx;
1062  assert( breakpoints[stableBp].src == FVEC );
1063  Real x = upd[breakpointidx];
1064  if( spxAbs(x) > moststable )
1065  {
1066  stableDelta = (x > 0.0) ? ub[breakpointidx] : lb[breakpointidx];
1067  stableDelta = (stableDelta - vec[breakpointidx]) / x;
1068 
1069  if( stableDelta <= bestDelta)
1070  {
1071  moststable = spxAbs(x);
1072  bestBp = stableBp;
1073  }
1074  }
1075  // stop searching if the step length is too big
1076  else if( stableDelta > delta + bestDelta )
1077  break;
1078  }
1079 
1080  degeneps = fastDelta / moststable; /* as in SPxFastRT */
1081  // get stability requirements
1082  instable = thesolver->instableEnter;
1083  assert(!instable || thesolver->instableEnterId.isValid());
1084  stab = instable ? LOWSTAB : SPxFastRT::minStability(moststable);
1085 
1086  bool foundStable = false;
1087 
1088  if( bestBp >= 0 )
1089  {
1090  // found a more stable pivot
1091  if( moststable > stab )
1092  {
1093  // stability requirements are satisfied
1094  int breakpointidx = breakpoints[bestBp].idx;
1095  assert(breakpointidx >= 0);
1096  foundStable = getData(val, leaveIdx, breakpointidx, moststable, degeneps, upd, vec, lb, ub, FVEC, max);
1097  }
1098  }
1099 
1100  else
1101  {
1102  // scan passed breakpoints from back to front and stop as soon as a good one is found
1103  while( !foundStable && npassedBp >= 0 )
1104  {
1105  int breakpointidx = breakpoints[npassedBp].idx;
1106 
1107  // only look for non-basic variables
1108  if( breakpointidx >= 0 )
1109  {
1110  foundStable = getData(val, leaveIdx, breakpointidx, moststable, degeneps, upd, vec, lb, ub, FVEC, max);
1111  }
1112  --npassedBp;
1113  }
1114  ++npassedBp;
1115  }
1116 
1117  if( !foundStable )
1118  {
1119  assert(leaveIdx < 0);
1121  {
1122  MSG_DEBUG( std::cout << "DEBFRT04 "
1123  << thesolver->basis().iteration()
1124  << ": no valid leaveIdx found - relaxing..."
1125  << std::endl; )
1126  relax();
1127  ++relax_count;
1128  // restore original value
1129  val = max;
1130  // try again with relaxed delta
1131  return SPxBoundFlippingRT::selectLeave(val, enterTest);
1132  }
1133  else
1134  {
1135  MSG_DEBUG( std::cout << "DEBFRT05 "
1136  << thesolver->basis().iteration()
1137  << " no valid leaveIdx found - breaking..."
1138  << std::endl; )
1139  return leaveIdx;
1140  }
1141  }
1142  else
1143  {
1144  relax_count = 0;
1145  tighten();
1146  }
1147 
1148  // flip bounds of skipped breakpoints only if a nondegenerate step is to be performed
1149  if( npassedBp > 0 && spxAbs(breakpoints[npassedBp].val) > fastDelta )
1150  {
1151  flipAndUpdate(npassedBp);
1152  thesolver->boundflips = npassedBp;
1153  if( npassedBp >= 10 )
1154  flipPotential = 1;
1155  else
1156  flipPotential -= 0.05;
1157  }
1158  else
1159  {
1160  thesolver->boundflips = 0;
1161  flipPotential -= 0.1;
1162  }
1163 
1164  MSG_DEBUG( std::cout << "DEBFRT06 "
1165  << thesolver->basis().iteration()
1166  << ": selected Index: "
1167  << leaveIdx
1168  << " number of candidates: "
1169  << nBp
1170  << std::endl; )
1171 
1172  return leaveIdx;
1173 }
1174 
1175 
1176 } // namespace soplex