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-2017 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  bool polish
550  )
551 {
552  assert( m_type == SPxSolver::LEAVE );
553  assert(thesolver->boundflips == 0);
554 
555  // reset the history and try again to do some long steps
556  if( thesolver->leaveCount % LONGSTEP_FREQ == 0 )
557  {
558  MSG_DEBUG( std::cout << "DLBFRT06 resetting long step history" << std::endl; )
559  flipPotential = 1;
560  }
561  if( !enableBoundFlips || polish || thesolver->rep() == SPxSolver::ROW || flipPotential <= 0 )
562  {
563  MSG_DEBUG( std::cout << "DLBFRT07 switching to fast ratio test" << std::endl; )
564  return SPxFastRT::selectEnter(val, leaveIdx, polish);
565  }
566  const Real* pvec = thesolver->pVec().get_const_ptr();
567  const Real* pupd = thesolver->pVec().delta().values();
568  const int* pidx = thesolver->pVec().delta().indexMem();
569  int pupdnnz = thesolver->pVec().delta().size();
570  const Real* lpb = thesolver->lpBound().get_const_ptr();
571  const Real* upb = thesolver->upBound().get_const_ptr();
572 
573  const Real* cvec = thesolver->coPvec().get_const_ptr();
574  const Real* cupd = thesolver->coPvec().delta().values();
575  const int* cidx = thesolver->coPvec().delta().indexMem();
576  int cupdnnz = thesolver->coPvec().delta().size();
577  const Real* lcb = thesolver->lcBound().get_const_ptr();
578  const Real* ucb = thesolver->ucBound().get_const_ptr();
579 
580  resetTols();
581 
582  Real max;
583 
584  // index in breakpoint array of minimal value (i.e. choice of normal RT)
585  int minIdx;
586 
587  // temporary breakpoint data structure to make swaps possible
588  Breakpoint tmp;
589 
590  // most stable pivot value in candidate set
591  Real moststable;
592 
593  // initialize invalid enterId
594  SPxId enterId;
595 
596  // slope of objective function improvement
597  Real slope;
598 
599  // number of found breakpoints
600  int nBp;
601 
602  // number of passed breakpoints
603  int npassedBp;
604 
605  Real degeneps;
606  Real stab;
607  bool instable;
608 
609  max = val;
610  val = 0.0;
611  moststable = 0.0;
612  nBp = 0;
613  minIdx = -1;
614 
615  // get breakpoints and and determine the index of the minimal value
616  if( max > 0 )
617  {
618  collectBreakpointsMax(nBp, minIdx, pidx, pupdnnz, pupd, pvec, upb, lpb, PVEC);
619  collectBreakpointsMax(nBp, minIdx, cidx, cupdnnz, cupd, cvec, ucb, lcb, COPVEC);
620  }
621  else
622  {
623  collectBreakpointsMin(nBp, minIdx, pidx, pupdnnz, pupd, pvec, upb, lpb, PVEC);
624  collectBreakpointsMin(nBp, minIdx, cidx, cupdnnz, cupd, cvec, ucb, lcb, COPVEC);
625  }
626 
627  if( nBp == 0 )
628  {
629  val = max;
630  return enterId;
631  }
632 
633  assert(minIdx >= 0);
634 
635  // swap smallest breakpoint to the front to skip the sorting phase if no bound flip is possible
636  tmp = breakpoints[minIdx];
637  breakpoints[minIdx] = breakpoints[0];
638  breakpoints[0] = tmp;
639 
640  // get initial slope
641  slope = spxAbs(thesolver->fTest()[leaveIdx]);
642  if( slope == 0 )
643  {
644  // this may only happen if SoPlex decides to make an instable pivot
645  assert(thesolver->instableLeaveNum >= 0);
646  // restore original slope
648  }
649 
650  // set up structures for the quicksort implementation
651  BreakpointCompare compare;
652  compare.entry = breakpoints.get_const_ptr();
653 
654  // pointer to end of sorted part of breakpoints
655  int sorted = 0;
656  // minimum number of entries that are supposed to be sorted by partial sort
657  int sortsize = 4;
658 
659  // get all skipable breakpoints
660  for( npassedBp = 0; npassedBp < nBp && slope > 0; ++npassedBp)
661  {
662  // sort breakpoints only partially to save time
663  if( npassedBp > sorted )
664  {
665  sorted = SPxQuicksortPart(breakpoints.get_ptr(), compare, sorted + 1, nBp, sortsize);
666  }
667  int i = breakpoints[npassedBp].idx;
668  // compute new slope
669  if( breakpoints[npassedBp].src == PVEC )
670  {
671  if( thesolver->isBasic(i) )
672  {
673  // mark basic indices
674  breakpoints[npassedBp].idx = -1;
675  thesolver->pVec().delta().clearIdx(i);
676  }
677  else
678  {
679  Real absupd = spxAbs(pupd[i]);
680  slope -= (thesolver->upper(i) * absupd) - (thesolver->lower(i) * absupd);
681  // get most stable pivot
682  if( absupd > moststable )
683  moststable = absupd;
684  }
685  }
686  else
687  {
688  assert(breakpoints[npassedBp].src == COPVEC);
689  if( thesolver->isCoBasic(i) )
690  {
691  // mark basic indices
692  breakpoints[npassedBp].idx = -1;
693  thesolver->coPvec().delta().clearIdx(i);
694  }
695  else
696  {
697  Real absupd = spxAbs(cupd[i]);
698  slope -= (thesolver->rhs(i) * absupd) - (thesolver->lhs(i) * absupd);
699  if( absupd > moststable )
700  moststable = absupd;
701  }
702  }
703  }
704  --npassedBp;
705  assert(npassedBp >= 0);
706 
707  // check for unboundedness/infeasibility
708  if( slope > delta && npassedBp >= nBp - 1 )
709  {
710  MSG_DEBUG( std::cout << "DLBFRT02 " << thesolver->basis().iteration()
711  << ": unboundedness in ratio test" << std::endl; )
712  flipPotential -= 0.5;
713  val = max;
714  return SPxFastRT::selectEnter(val, leaveIdx);
715  }
716 
717  MSG_DEBUG( std::cout << "DLBFRT01 "
718  << thesolver->basis().iteration()
719  << ": number of flip candidates: "
720  << npassedBp
721  << std::endl; )
722 
723  // try to get a more stable pivot by looking at those with similar step length
724  int stableBp; // index to walk over additional breakpoints (after slope change)
725  int bestBp = -1; // breakpoints index with best possible stability
726  Real bestDelta = breakpoints[npassedBp].val; // best step length (after bound flips)
727 
728  for( stableBp = npassedBp + 1; stableBp < nBp; ++stableBp )
729  {
730  Real stableDelta = 0;
731  // get next breakpoints in increasing order
732  if( stableBp > sorted )
733  {
734  sorted = SPxQuicksortPart(breakpoints.get_ptr(), compare, sorted + 1, nBp, sortsize);
735  }
736  int idx = breakpoints[stableBp].idx;
737  if( breakpoints[stableBp].src == PVEC )
738  {
739  if( thesolver->isBasic(idx) )
740  {
741  // mark basic indices
742  breakpoints[stableBp].idx = -1;
743  thesolver->pVec().delta().clearIdx(idx);
744  continue;
745  }
746  Real x = pupd[idx];
747  if( spxAbs(x) > moststable )
748  {
749  thesolver->pVec()[idx] = thesolver->vector(idx) * thesolver->coPvec();
750  stableDelta = (x > 0.0) ? upb[idx] : lpb[idx];
751  stableDelta = (stableDelta - pvec[idx]) / x;
752 
753  if( stableDelta <= bestDelta)
754  {
755  moststable = spxAbs(x);
756  bestBp = stableBp;
757  }
758  }
759  }
760  else
761  {
762  if( thesolver->isCoBasic(idx) )
763  {
764  // mark basic indices
765  breakpoints[stableBp].idx = -1;
766  thesolver->coPvec().delta().clearIdx(idx);
767  continue;
768  }
769  Real x = cupd[idx];
770  if( spxAbs(x) > moststable )
771  {
772  stableDelta = (x > 0.0) ? ucb[idx] : lcb[idx];
773  stableDelta = (stableDelta - cvec[idx]) / x;
774 
775  if( stableDelta <= bestDelta )
776  {
777  moststable = spxAbs(x);
778  bestBp = stableBp;
779  }
780  }
781  }
782 
783  // stop searching if the step length is too big
784  if( stableDelta > delta + bestDelta )
785  break;
786  }
787 
788  degeneps = fastDelta / moststable; /* as in SPxFastRT */
789  // get stability requirements
790  instable = thesolver->instableLeave;
791  assert(!instable || thesolver->instableLeaveNum >= 0);
792  stab = instable ? LOWSTAB : SPxFastRT::minStability(moststable);
793 
794  bool foundStable = false;
795 
796  if( bestBp >= 0 )
797  {
798  // found a more stable pivot
799  if( moststable > stab )
800  {
801  // stability requirements are satisfied
802  int idx = breakpoints[bestBp].idx;
803  assert(idx >= 0);
804  if( breakpoints[bestBp].src == PVEC )
805  foundStable = getData(val, enterId, idx, stab, degeneps, pupd, pvec, lpb, upb, PVEC, max);
806  else
807  foundStable = getData(val, enterId, idx, stab, degeneps, cupd, cvec, lcb, ucb, COPVEC, max);
808  }
809  }
810 
811  else
812  {
813  // scan passed breakpoints from back to front and stop as soon as a good one is found
814  while( !foundStable && npassedBp >= 0 )
815  {
816  int idx = breakpoints[npassedBp].idx;
817 
818  // only look for non-basic variables
819  if( idx >= 0 )
820  {
821  if( breakpoints[npassedBp].src == PVEC )
822  foundStable = getData(val, enterId, idx, stab, degeneps, pupd, pvec, lpb, upb, PVEC, max);
823  else
824  foundStable = getData(val, enterId, idx, stab, degeneps, cupd, cvec, lcb, ucb, COPVEC, max);
825  }
826  --npassedBp;
827  }
828  ++npassedBp;
829  }
830 
831  if( !foundStable )
832  {
833  assert(!enterId.isValid());
835  {
836  MSG_DEBUG( std::cout << "DLBFRT04 "
837  << thesolver->basis().iteration()
838  << ": no valid enterId found - relaxing..."
839  << std::endl; )
840  relax();
841  ++relax_count;
842  // restore original value
843  val = max;
844  // try again with relaxed delta
845  return SPxBoundFlippingRT::selectEnter(val, leaveIdx);
846  }
847  else
848  {
849  MSG_DEBUG( std::cout << "DLBFRT05 "
850  << thesolver->basis().iteration()
851  << " no valid enterId found - breaking..."
852  << std::endl; )
853  return enterId;
854  }
855  }
856  else
857  {
858  relax_count = 0;
859  tighten();
860  }
861 
862  // flip bounds of skipped breakpoints only if a nondegenerate step is to be performed
863  if( npassedBp > 0 && spxAbs(breakpoints[npassedBp].val) > fastDelta )
864  {
865  flipAndUpdate(npassedBp);
866  thesolver->boundflips = npassedBp;
867  if( npassedBp >= 10 )
868  flipPotential = 1;
869  else
870  flipPotential -= 0.05;
871  }
872  else
873  {
874  thesolver->boundflips = 0;
875  flipPotential -= 0.1;
876  }
877 
878  MSG_DEBUG( std::cout << "DLBFRT06 "
879  << thesolver->basis().iteration()
880  << ": selected Id: "
881  << enterId
882  << " number of candidates: "
883  << nBp
884  << std::endl; )
885  return enterId;
886 }
887 
888 /** determine leaving row/column */
890  Real& val,
891  Real enterTest,
892  bool polish
893  )
894 {
895  assert( m_type == SPxSolver::ENTER );
896  assert(thesolver->boundflips == 0);
897 
898  // reset the history and try again to do some long steps
899  if( thesolver->enterCount % LONGSTEP_FREQ == 0 )
900  {
901  MSG_DEBUG( std::cout << "DEBFRT06 resetting long step history" << std::endl; )
902  flipPotential = 1;
903  }
904 
906  {
907  MSG_DEBUG( std::cout << "DEBFRT07 switching to fast ratio test" << std::endl; )
908  return SPxFastRT::selectLeave(val, enterTest, polish);
909  }
910 
911  const Real* vec = thesolver->fVec().get_const_ptr(); /**< pointer to values of current vector */
912  const Real* upd = thesolver->fVec().delta().values(); /**< pointer to update values of current vector */
913  const int* idx = thesolver->fVec().delta().indexMem(); /**< pointer to indices of current vector */
914  int updnnz = thesolver->fVec().delta().size(); /**< number of nonzeros in update vector */
915  const Real* lb = thesolver->lbBound().get_const_ptr(); /**< pointer to lower bound/lhs of current vector */
916  const Real* ub = thesolver->ubBound().get_const_ptr(); /**< pointer to upper bound/rhs of current vector */
917 
918  resetTols();
919 
920  Real max;
921 
922  // index in breakpoint array of minimal value (i.e. choice of normal RT)
923  int minIdx;
924 
925  // temporary breakpoint data structure to make swaps possible
926  Breakpoint tmp;
927 
928  // most stable pivot value in candidate set
929  Real moststable;
930 
931  // initialize invalid leaving index
932  int leaveIdx = -1;
933 
934  // slope of objective function improvement
935  Real slope;
936 
937  // number of found breakpoints
938  int nBp;
939 
940  // number of passed breakpoints
941  int npassedBp;
942 
943  Real degeneps;
944  Real stab;
945  bool instable;
946 
947  max = val;
948  val = 0.0;
949  moststable = 0.0;
950  nBp = 0;
951  minIdx = -1;
952 
953  assert(thesolver->fVec().delta().isSetup());
954 
955  // get breakpoints and and determine the index of the minimal value
956  if( max > 0 )
957  {
958  collectBreakpointsMax(nBp, minIdx, idx, updnnz, upd, vec, ub, lb, FVEC);
959  }
960  else
961  {
962  collectBreakpointsMin(nBp, minIdx, idx, updnnz, upd, vec, ub, lb, FVEC);
963  }
964 
965  // return -1 if no BP was found
966  if( nBp == 0 )
967  {
968  val = max;
969  return leaveIdx;
970  }
971 
972  assert(minIdx >= 0);
973 
974  // swap smallest breakpoint to the front to skip the sorting phase if no bound flip is possible
975  tmp = breakpoints[minIdx];
976  breakpoints[minIdx] = breakpoints[0];
977  breakpoints[0] = tmp;
978 
979  // get initial slope
980  slope = spxAbs(enterTest);
981  if( slope == 0 )
982  {
983  // this may only happen if SoPlex decides to make an instable pivot
984  assert(thesolver->instableEnterId.isValid());
985  // restore original slope
986  slope = thesolver->instableEnterVal;
987  }
988 
989  // set up structures for the quicksort implementation
990  BreakpointCompare compare;
991  compare.entry = breakpoints.get_const_ptr();
992 
993  // pointer to end of sorted part of breakpoints
994  int sorted = 0;
995  // minimum number of entries that are supposed to be sorted by partial sort
996  int sortsize = 4;
997 
998  // get all skipable breakpoints
999  for( npassedBp = 0; npassedBp < nBp && slope > 0; ++npassedBp)
1000  {
1001  // sort breakpoints only partially to save time
1002  if( npassedBp > sorted )
1003  {
1004  sorted = SPxQuicksortPart(breakpoints.get_ptr(), compare, sorted + 1, nBp, sortsize);
1005  }
1006  assert( breakpoints[npassedBp].src == FVEC );
1007  int breakpointidx = breakpoints[npassedBp].idx;
1008  // compute new slope
1009  Real upper;
1010  Real lower;
1011  Real absupd = spxAbs(upd[breakpointidx]);
1012  SPxId baseId = thesolver->baseId(breakpointidx);
1013  int i = thesolver->number(baseId);
1014  if( baseId.isSPxColId() )
1015  {
1016  upper = thesolver->upper(i);
1017  lower = thesolver->lower(i);
1018  }
1019  else
1020  {
1021  assert(baseId.isSPxRowId());
1022  upper = thesolver->rhs(i);
1023  lower = thesolver->lhs(i);
1024  }
1025 
1026  slope -= (upper * absupd) - (lower * absupd);
1027  // get most stable pivot
1028  if( absupd > moststable )
1029  moststable = absupd;
1030  }
1031  --npassedBp;
1032  assert(npassedBp >= 0);
1033 
1034  // check for unboundedness/infeasibility
1035  if( slope > delta && npassedBp >= nBp - 1 )
1036  {
1037  MSG_DEBUG( std::cout << "DEBFRT02 " << thesolver->basis().iteration()
1038  << ": unboundedness in ratio test" << std::endl; )
1039  flipPotential -= 0.5;
1040  val = max;
1041  return SPxFastRT::selectLeave(val, enterTest);
1042  }
1043 
1044  MSG_DEBUG( std::cout << "DEBFRT01 "
1045  << thesolver->basis().iteration()
1046  << ": number of flip candidates: "
1047  << npassedBp
1048  << std::endl; )
1049 
1050  // try to get a more stable pivot by looking at those with similar step length
1051  int stableBp; // index to walk over additional breakpoints (after slope change)
1052  int bestBp = -1; // breakpoints index with best possible stability
1053  Real bestDelta = breakpoints[npassedBp].val; // best step length (after bound flips)
1054 
1055  for( stableBp = npassedBp + 1; stableBp < nBp; ++stableBp )
1056  {
1057  Real stableDelta = 0;
1058  // get next breakpoints in increasing order
1059  if( stableBp > sorted )
1060  {
1061  sorted = SPxQuicksortPart(breakpoints.get_ptr(), compare, sorted + 1, nBp, sortsize);
1062  }
1063  int breakpointidx = breakpoints[stableBp].idx;
1064  assert( breakpoints[stableBp].src == FVEC );
1065  Real x = upd[breakpointidx];
1066  if( spxAbs(x) > moststable )
1067  {
1068  stableDelta = (x > 0.0) ? ub[breakpointidx] : lb[breakpointidx];
1069  stableDelta = (stableDelta - vec[breakpointidx]) / x;
1070 
1071  if( stableDelta <= bestDelta)
1072  {
1073  moststable = spxAbs(x);
1074  bestBp = stableBp;
1075  }
1076  }
1077  // stop searching if the step length is too big
1078  else if( stableDelta > delta + bestDelta )
1079  break;
1080  }
1081 
1082  degeneps = fastDelta / moststable; /* as in SPxFastRT */
1083  // get stability requirements
1084  instable = thesolver->instableEnter;
1085  assert(!instable || thesolver->instableEnterId.isValid());
1086  stab = instable ? LOWSTAB : SPxFastRT::minStability(moststable);
1087 
1088  bool foundStable = false;
1089 
1090  if( bestBp >= 0 )
1091  {
1092  // found a more stable pivot
1093  if( moststable > stab )
1094  {
1095  // stability requirements are satisfied
1096  int breakpointidx = breakpoints[bestBp].idx;
1097  assert(breakpointidx >= 0);
1098  foundStable = getData(val, leaveIdx, breakpointidx, moststable, degeneps, upd, vec, lb, ub, FVEC, max);
1099  }
1100  }
1101 
1102  else
1103  {
1104  // scan passed breakpoints from back to front and stop as soon as a good one is found
1105  while( !foundStable && npassedBp >= 0 )
1106  {
1107  int breakpointidx = breakpoints[npassedBp].idx;
1108 
1109  // only look for non-basic variables
1110  if( breakpointidx >= 0 )
1111  {
1112  foundStable = getData(val, leaveIdx, breakpointidx, moststable, degeneps, upd, vec, lb, ub, FVEC, max);
1113  }
1114  --npassedBp;
1115  }
1116  ++npassedBp;
1117  }
1118 
1119  if( !foundStable )
1120  {
1121  assert(leaveIdx < 0);
1123  {
1124  MSG_DEBUG( std::cout << "DEBFRT04 "
1125  << thesolver->basis().iteration()
1126  << ": no valid leaveIdx found - relaxing..."
1127  << std::endl; )
1128  relax();
1129  ++relax_count;
1130  // restore original value
1131  val = max;
1132  // try again with relaxed delta
1133  return SPxBoundFlippingRT::selectLeave(val, enterTest);
1134  }
1135  else
1136  {
1137  MSG_DEBUG( std::cout << "DEBFRT05 "
1138  << thesolver->basis().iteration()
1139  << " no valid leaveIdx found - breaking..."
1140  << std::endl; )
1141  return leaveIdx;
1142  }
1143  }
1144  else
1145  {
1146  relax_count = 0;
1147  tighten();
1148  }
1149 
1150  // flip bounds of skipped breakpoints only if a nondegenerate step is to be performed
1151  if( npassedBp > 0 && spxAbs(breakpoints[npassedBp].val) > fastDelta )
1152  {
1153  flipAndUpdate(npassedBp);
1154  thesolver->boundflips = npassedBp;
1155  if( npassedBp >= 10 )
1156  flipPotential = 1;
1157  else
1158  flipPotential -= 0.05;
1159  }
1160  else
1161  {
1162  thesolver->boundflips = 0;
1163  flipPotential -= 0.1;
1164  }
1165 
1166  MSG_DEBUG( std::cout << "DEBFRT06 "
1167  << thesolver->basis().iteration()
1168  << ": selected Index: "
1169  << leaveIdx
1170  << " number of candidates: "
1171  << nBp
1172  << std::endl; )
1173 
1174  return leaveIdx;
1175 }
1176 
1177 
1178 } // namespace soplex
const VectorBase< R > & rhs() const
Returns right hand side vector.
Definition: spxlpbase.h:219
Rational spxAbs(const Rational &r)
Absolute.
Definition: rational.cpp:3909
SPxId coId(int i) const
id of i &#39;th covector.
Definition: spxsolver.h:1098
const Vector & ucBound() const
Definition: spxsolver.h:1398
int iteration() const
returns number of basis changes since last load().
Definition: spxbasis.h:545
Status & coStatus(int i)
Definition: spxbasis.h:284
void collectBreakpointsMax(int &nBp, int &minIdx, const int *idx, int nnz, const Real *upd, const Real *vec, const Real *upp, const Real *low, BreakpointSource src)
bool isSetup() const
Returns setup status.
Definition: ssvectorbase.h:120
int boundflips
number of performed bound flips
Definition: spxsolver.h:374
const VectorBase< R > & upper() const
Returns upper bound vector.
Definition: spxlpbase.h:456
const Vector & fTest() const
Violations of fVec.
Definition: spxsolver.h:1366
SPxOut * spxout
message handler
Definition: spxsolver.h:436
THREADLOCAL const Real infinity
Definition: spxdefines.cpp:26
DVector * theUbound
Upper bound for vars.
Definition: spxsolver.h:357
DVector * theCoUbound
Upper bound for covars.
Definition: spxsolver.h:359
Real delta
allowed bound violation
#define LOWSTAB
Status & rowStatus(int i)
Definition: spxbasis.h:239
virtual int selectLeave(Real &val, Real enterTest, bool polish=false)
Real fastDelta
currently allowed infeasibility.
Definition: spxfastrt.h:52
void setValue(int i, R x)
Sets i &#39;th element to x.
Definition: ssvectorbase.h:218
int number(const SPxRowId &id) const
Returns the row number of the row with identifier id.
Definition: spxlpbase.h:522
virtual int selectLeave(Real &val, Real, bool polish=false)
Definition: spxfastrt.cpp:855
const Vector & lcBound() const
Definition: spxsolver.h:1419
int dim() const
dimension of basis matrix.
Definition: spxsolver.h:1056
void shiftLBbound(int i, Real to)
shift i &#39;th lbBound to to.
Definition: spxsolver.h:1564
Real epsilon
|value| < epsilon is considered 0.
Definition: spxfastrt.h:50
Ids for LP columns.Class SPxColId provides DataKeys for the column indices of an SPxLP.
Definition: spxid.h:36
void relax()
relaxes stability requirements.
Definition: spxfastrt.cpp:80
Desc::Status dualStatus(const SPxColId &id) const
dual Status for the column variable with ID id of the loaded LP.
Definition: spxbasis.cpp:34
rowwise representation.
Definition: spxsolver.h:107
void collectBreakpointsMin(int &nBp, int &minIdx, const int *idx, int nnz, const Real *upd, const Real *vec, const Real *upp, const Real *low, BreakpointSource src)
const R * get_const_ptr() const
Conversion to C-style pointer.
Definition: vectorbase.h:453
Wrapper for different output streams and verbosity levels.
const Vector & ubBound() const
upper bound for fVec.
Definition: spxsolver.h:1322
Entering Simplex.
Definition: spxsolver.h:134
Real minStability(Real maxabs)
Compute stability requirement.
Definition: spxfastrt.cpp:87
primal variable is set to its upper bound
Definition: spxbasis.h:188
Generic Ids for LP rows or columns.Both SPxColIds and SPxRowIds may be treated uniformly as SPxIds: ...
Definition: spxid.h:85
UpdateVector & coPvec() const
copricing vector.
Definition: spxsolver.h:1379
void resetTols()
resets tolerances (epsilon).
Definition: spxfastrt.cpp:48
Leaving Simplex.
Definition: spxsolver.h:143
double Real
Definition: spxdefines.h:218
const R * values() const
Returns array values.
Definition: ssvectorbase.h:299
DVector * theFrhs
Definition: spxsolver.h:342
#define MSG_DEBUG(x)
Definition: spxdefines.h:132
void shiftLPbound(int i, Real to)
shift i &#39;th lpBound to to.
Definition: spxsolver.h:1578
Row and columns Id&#39;s SPxLP.
DVector * theLbound
Lower bound for vars.
Definition: spxsolver.h:358
const Vector & lbBound() const
lower bound for fVec.
Definition: spxsolver.h:1340
SPxId id(int i) const
id of i &#39;th vector.
Definition: spxsolver.h:1079
UpdateVector & fVec() const
feasibility vector.
Definition: spxsolver.h:1304
SPxId instableEnterId
Definition: spxsolver.h:295
bool isSPxColId() const
is id a column id?
Definition: spxid.h:165
DVector theLBbound
Lower Basic Feasibility bound.
Definition: spxsolver.h:339
main LP solver class
bool isBasic(SPxBasis::Desc::Status stat) const
does stat describe a basic index ?
Definition: spxsolver.h:1244
const VectorBase< R > & lhs() const
Returns left hand side vector.
Definition: spxlpbase.h:253
void clear()
Clears vector.
Definition: ssvectorbase.h:600
void shiftUCbound(int i, Real to)
shift i &#39;th ucBound to to.
Definition: spxsolver.h:1585
bool updateNonbasicValue(Real objChange)
Definition: spxsolver.cpp:911
Basis descriptor.
Definition: spxbasis.h:104
DVector theURbound
Upper Row Feasibility bound.
Definition: spxsolver.h:328
virtual SPxId selectEnter(Real &val, int leaveIdx, bool polish=false)
SSVectorBase< R > & multAdd(S xx, const SVectorBase< T > &vec)
Addition of a scaled vector.
Definition: basevectors.h:445
void shiftUBbound(int i, Real to)
shift i &#39;th ubBound to to.
Definition: spxsolver.h:1557
Status & colStatus(int i)
Definition: spxbasis.h:254
SPxId & baseId(int i)
Definition: spxbasis.h:503
Generic QuickSort implementation.
const int * indexMem() const
Returns array indices.
Definition: ssvectorbase.h:293
DVector theUBbound
Upper Basic Feasibility bound.
Definition: spxsolver.h:338
Bound flipping ratio test (long step dual) for SoPlex.
DVector * theCoLbound
Lower bound for covars.
Definition: spxsolver.h:360
void reDim(int newdim)
Resets dimension to newdim.
Definition: ssvectorbase.h:566
Debugging, floating point type and parameter definitions.
void clearIdx(int i)
Clears element i.
Definition: ssvectorbase.h:253
UpdateVector & pVec() const
pricing vector.
Definition: spxsolver.h:1459
SPxSolver * thesolver
the solver
const Vector & lpBound() const
Definition: spxsolver.h:1485
DVector theLRbound
Lower Row Feasibility bound.
Definition: spxsolver.h:329
DVector theUCbound
Upper Column Feasibility bound.
Definition: spxsolver.h:330
int size() const
Returns the number of nonzeros.
Definition: ssvectorbase.h:199
Everything should be within this namespace.
void shiftUPbound(int i, Real to)
shift i &#39;th upBound to to.
Definition: spxsolver.h:1571
void shiftLCbound(int i, Real to)
shift i &#39;th lcBound to to.
Definition: spxsolver.h:1592
void tighten()
tightens stability requirements.
Definition: spxfastrt.cpp:58
#define LONGSTEP_FREQ
#define MSG_WARNING(spxout, x)
Prints out message x if the verbosity level is at least SPxOut::WARNING.
Definition: spxdefines.h:116
primal variable is set to its lower bound
Definition: spxbasis.h:187
bool getData(Real &val, SPxId &enterId, int idx, Real stab, Real degeneps, const Real *upd, const Real *vec, const Real *low, const Real *upp, BreakpointSource src, Real max)
void setup()
Initializes nonzero indices for elements with absolute values above epsilon and sets all other elemen...
Definition: ssvectorbase.h:132
DVector theLCbound
Lower Column Feasibility bound.
Definition: spxsolver.h:331
int leaveCount
number of LEAVE iterations
Definition: spxsolver.h:369
int SPxQuicksortPart(T *keys, COMPARATOR &compare, int start, int end, int size, int start2=0, int end2=0, bool type=true)
Generic implementation of Partial QuickSort.
Definition: sorter.h:219
const Vector & upBound() const
Definition: spxsolver.h:1464
virtual SPxId selectEnter(Real &val, int, bool polish=false)
Definition: spxfastrt.cpp:1229
bool isSPxRowId() const
is id a row id?
Definition: spxid.h:160
DVector * theCoPrhs
Definition: spxsolver.h:347
bool isValid() const
returns TRUE iff the id is a valid column or row identifier.
Definition: spxid.h:150
Real theShift
sum of all shifts applied to any bound.
Definition: spxsolver.h:266
#define MAX_RELAX_COUNT
DataArray< Breakpoint > breakpoints
int enterCount
number of ENTER iterations
Definition: spxsolver.h:370
bool isCoBasic(int i) const
is the i &#39;th covector basic ?
Definition: spxsolver.h:1289
dual variable has two bounds
Definition: spxbasis.h:194
Ids for LP rows.Class SPxRowId provides DataKeys for the row indices of an SPxLP. ...
Definition: spxid.h:55
const SVector & vector(int i) const
i &#39;th vector.
Definition: spxsolver.h:1138
SSVector & delta()
update vector , writeable
Definition: updatevector.h:122
Status & status(int i)
Definition: spxbasis.h:269
const SPxBasis & basis() const
Return current basis.
Definition: spxsolver.h:1736
void setup4solve2(SSVector *p_y2, SSVector *p_rhs2)
Setup vectors to be solved within Simplex loop.
Definition: spxsolver.h:1683
Status
Status of a variable.
Definition: spxbasis.h:185
void add(int i, R x)
Adds nonzero (i, x) to SSVectorBase.
Definition: ssvectorbase.h:208
const VectorBase< R > & lower() const
Returns (internal and possibly scaled) lower bound vector.
Definition: spxlpbase.h:483
SPxSolver::Type m_type
internal storage of type
const Desc & desc() const
Definition: spxbasis.h:463
Representation rep() const
return the current basis representation.
Definition: spxsolver.h:478
columnwise representation.
Definition: spxsolver.h:108
void setup4coSolve2(SSVector *p_z, SSVector *p_rhs)
Setup vectors to be cosolved within Simplex loop.
Definition: spxsolver.h:1709