Scippy

SoPlex

Sequential object-oriented simPlex

spxbasis.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 <cstdio>
18 #include <iostream>
19 #include <iomanip>
20 #include <sstream>
21 
22 #include "spxdefines.h"
23 #include "spxbasis.h"
24 #include "didxset.h"
25 #include "dvector.h"
26 #include "spxsolver.h"
27 #include "mpsinput.h"
28 #include "spxout.h"
29 #include "exceptions.h"
30 
31 namespace soplex
32 {
35 {
36  return dualColStatus(static_cast<SPxLP*>(theLP)->number(id));
37 }
38 
41 {
42  return dualRowStatus((static_cast<SPxLP*>(theLP))->number(id));
43 }
44 
47 {
48  assert(theLP != 0);
49 
50  if (theLP->rhs(i) < infinity)
51  {
52  if (theLP->lhs(i) > -infinity)
53  {
54  if (theLP->lhs(i) == theLP->rhs(i))
55  return Desc::D_FREE;
56  else
57  return Desc::D_ON_BOTH;
58  }
59  else
60  return Desc::D_ON_LOWER;
61  }
62  else if (theLP->lhs(i) > -infinity)
63  return Desc::D_ON_UPPER;
64  else
65  return Desc::D_UNDEFINED;
66 }
67 
70 {
71  assert(theLP != 0);
72 
73  if (theLP->SPxLP::upper(i) < infinity)
74  {
75  if (theLP->SPxLP::lower(i) > -infinity)
76  {
77  if (theLP->SPxLP::lower(i) == theLP->SPxLP::upper(i))
78  return Desc::D_FREE;
79  else
80  return Desc::D_ON_BOTH;
81  }
82  else
83  return Desc::D_ON_LOWER;
84  }
85  else if (theLP->SPxLP::lower(i) > -infinity)
86  return Desc::D_ON_UPPER;
87  else
88  return Desc::D_UNDEFINED;
89 }
90 
92 {
93  assert(theLP != 0);
94  assert(theLP->dim() == matrix.size());
95 
96  MSG_INFO3( (*spxout), (*spxout) << "IBASIS01 loadMatrixVecs() invalidates factorization" << std::endl; )
97 
98  int i;
99  nzCount = 0;
100  for (i = theLP->dim() - 1; i >= 0; --i)
101  {
102  matrix[i] = &theLP->vector(baseId(i));
103  nzCount += matrix[i]->size();
104  }
105  matrixIsSetup = true;
106  factorized = false;
107  if (factor != 0)
108  factor->clear();
109 }
110 
112 {
113 
114  assert(status() > NO_PROBLEM);
115  assert(theLP != 0);
116 
117  int basisdim;
118 
119  if ( ds.nRows() != theLP->nRows() || ds.nCols() != theLP->nCols() )
120  {
121  MSG_DEBUG( std::cout << "IBASIS20 Dimension mismatch\n" );
122  return false;
123  }
124 
125  basisdim = 0;
126  for ( int row = ds.nRows()-1; row >= 0; --row )
127  {
128  if ( ds.rowstat[row] >= 0 )
129  {
130  if ( ds.rowstat[row] != dualRowStatus(row) )
131  {
132  MSG_DEBUG( std::cout << "IBASIS21 Basic row " << row << " with incorrect dual status " << dualRowStatus(row) << "\n");
133  return false;
134  }
135  }
136  else
137  {
138  basisdim++;
139  if ( (ds.rowstat[row] == Desc::P_FIXED && theLP->SPxLP::lhs(row) != theLP->SPxLP::rhs(row))
140  || (ds.rowstat[row] == Desc::P_ON_UPPER && theLP->SPxLP::rhs(row) >= infinity)
141  || (ds.rowstat[row] == Desc::P_ON_LOWER && theLP->SPxLP::lhs(row) <= -infinity) )
142  {
143  MSG_DEBUG( std::cout << "IBASIS22 Nonbasic row with incorrect status: lhs=" << theLP->SPxLP::lhs(row) << ", rhs=" << theLP->SPxLP::rhs(row) << ", stat=" << ds.rowstat[row] << "\n");
144  return false;
145  }
146  }
147  }
148 
149  for ( int col = ds.nCols()-1; col >= 0; --col )
150  {
151  if ( ds.colstat[col] >= 0 )
152  {
153  if ( ds.colstat[col] != dualColStatus(col) )
154  {
155  MSG_DEBUG( std::cout << "IBASIS23 Basic column " << col << " with incorrect dual status " << ds.colstat[col] << " != " << dualColStatus(col) << "\n");
156  return false;
157  }
158  }
159  else
160  {
161  basisdim++;
162  if ( (ds.colstat[col] == Desc::P_FIXED && theLP->SPxLP::lower(col) != theLP->SPxLP::upper(col))
163  || (ds.colstat[col] == Desc::P_ON_UPPER && theLP->SPxLP::upper(col) >= infinity)
164  || (ds.colstat[col] == Desc::P_ON_LOWER && theLP->SPxLP::lower(col) <= -infinity) )
165  {
166  MSG_DEBUG( std::cout << "IBASIS24 Nonbasic column with incorrect status: lower=" << theLP->SPxLP::lower(col) << ", upper=" << theLP->SPxLP::upper(col) << ", stat=" << ds.colstat[col] << "\n");
167  return false;
168  }
169  }
170  }
171 
172  if ( basisdim != theLP->nCols() )
173  {
174  MSG_DEBUG( std::cout << "IBASIS25 Incorrect basis dimension " << basisdim << " != " << theLP->nCols() << "\n" );
175  return false;
176  }
177 
178  // basis descriptor valid
179  return true;
180 }
181 
182 /*
183  Loading a #Desc# into the basis can be done more efficiently, by
184  explicitely programming both cases, for the rowwise and for the columnwise
185  representation. This implementation hides this distingtion in the use of
186  methods #isBasic()# and #vector()#.
187  */
188 void SPxBasis::loadDesc(const Desc& ds)
189 {
190  assert(status() > NO_PROBLEM);
191  assert(theLP != 0);
192  assert(ds.nRows() == theLP->nRows());
193  assert(ds.nCols() == theLP->nCols());
194 
195  SPxId none;
196  int i;
197  int j;
198 
199  MSG_INFO3( (*spxout), (*spxout) << "IBASIS02 loading of Basis invalidates factorization" << std::endl; )
200 
201  lastin = none;
202  lastout = none;
203  lastidx = -1;
204  iterCount = 0;
205  updateCount = 0;
206 
207  if (&ds != &thedesc)
208  {
209  thedesc = ds;
210  setRep();
211  }
212 
213  assert(theLP->dim() == matrix.size());
214 
215  // MSG_DEBUG( dump(); )
216 
217  nzCount = 0;
218  for (j = i = 0; i < theLP->nRows(); ++i)
219  {
220  /* for columns and rows with D_... status, the correct D_... status depends on bounds and sides; if a basis
221  * descriptor is loaded after changing bounds or sides, e.g. in the refine() method, we have to correct them
222  */
223  if (thedesc.rowStatus(i) >= 0)
225  else if (thedesc.rowStatus(i) == SPxBasis::Desc::P_FIXED && theLP->SPxLP::lhs(i) != theLP->SPxLP::rhs(i))
226  {
227  if (theLP->SPxLP::lhs(i) > -infinity && theLP->SPxLP::maxRowObj(i) < 0.0)
229  else if (theLP->SPxLP::rhs(i) < infinity)
231  else
233  }
234 
235  if (theLP->isBasic(thedesc.rowStatus(i)))
236  {
237  assert(theLP->dim() == matrix.size());
238  assert(j < matrix.size());
239 
240  SPxRowId id = theLP->SPxLP::rId(i);
241  theBaseId[j] = id;
242  matrix[j] = &theLP->vector(id);
243  nzCount += matrix[j++]->size();
244  }
245  }
246 
247  for (i = 0; i < theLP->nCols(); ++i)
248  {
249  /* for columns and rows with D_... status, the correct D_... status depends on bounds and sides; if a basis
250  * descriptor is loaded after changing bounds or sides, e.g. in the refine() method, we have to correct them
251  */
252  if (thedesc.colStatus(i) >= 0)
254  else if (thedesc.colStatus(i) == SPxBasis::Desc::P_FIXED && theLP->SPxLP::lower(i) != theLP->SPxLP::upper(i))
255  {
256  if (theLP->SPxLP::lower(i) <= -infinity && theLP->SPxLP::upper(i) >= infinity)
258  else if (theLP->SPxLP::upper(i) >= infinity || (theLP->SPxLP::lower(i) > -infinity && theLP->SPxLP::maxObj(i) < 0.0))
260  else
262  }
263 
264  if (theLP->isBasic(thedesc.colStatus(i)))
265  {
266  assert(theLP->dim() == matrix.size());
267  assert(j < matrix.size());
268 
269  SPxColId id = theLP->SPxLP::cId(i);
270  theBaseId[j] = id;
271  matrix[j] = &theLP->vector(id);
272  nzCount += matrix[j++]->size();
273  }
274  }
275 
276  /* if dimensions are inconsistent, restore slack basis */
277  if( j != matrix.size() )
279 
280  assert(isDescValid(thedesc));
281 
282  matrixIsSetup = true;
283  factorized = false;
284  if (factor != 0)
285  factor->clear();
286 }
287 
289 {
290  assert(theLP != 0);
291 
292  reDim();
293  minStab = 0.0;
294 
295  if (theLP->rep() == SPxSolver::ROW)
296  {
299  }
300  else
301  {
304  }
305 }
306 
308 {
309  assert(lp != 0);
310  theLP = lp;
311 
313 
314  setRep();
315 
316  addedRows(lp->nRows());
317  addedCols(lp->nCols());
318 
320 
321  loadDesc(thedesc);
322 }
323 
324 void SPxBasis::loadSolver(SLinSolver* p_solver, const bool destroy)
325 {
326 
327  assert(!freeSlinSolver || factor != 0);
328 
329  setOutstream(*p_solver->spxout);
330 
331  MSG_INFO3( (*spxout), (*spxout) << "IBASIS03 loading of Solver invalidates factorization"
332  << std::endl; )
333 
334 
335  if(freeSlinSolver)
336  {
337  delete factor;
338  factor = 0;
339  }
340 
341  factor = p_solver;
342  factorized = false;
343  factor->clear();
344  freeSlinSolver = destroy;
345 }
346 
347 
348 
349 
350 /**
351  * The specification is taken from the
352  *
353  * ILOG CPLEX 7.0 Reference Manual, Appendix E, Page 543.
354  *
355  * This routine should read valid BAS format files.
356  *
357  * @return true if the file was read correctly.
358  *
359  * Here is a very brief outline of the format:
360  *
361  * The format is in a form similar to an MPS file. The basic assumption is that all (column)
362  * variables are nonbasic at their lower bound and all row (variables) are basic; only the
363  * differences to this rule are given. Each data line contains an indicator, a variable name and
364  * possibly a row/constraint name. The following meaning applies with respect to the indicators:
365  *
366  * - XU: the variable is basic, the row is nonbasic at its upper bound
367  * - XL: the variable is basic, the row is nonbasic at its lower bound
368  * - UL: the variable is nonbasic and at its upper bound
369  * - LL: the variable is nonbasic and at its lower bound
370  *
371  * The CPLEX format contains an additional indicator 'BS', but this is unsupported here.
372  *
373  * Nonbasic variables without lower bound have the following default status for SoPlex:
374  * - at their upper bound if finite,
375  * - at zero if free.
376  */
378  std::istream& is,
379  const NameSet* rowNames,
380  const NameSet* colNames)
381 {
382  assert(theLP != 0);
383 
384  /* prepare names */
385  const NameSet* rNames = rowNames;
386  const NameSet* cNames = colNames;
387 
388  NameSet* p_colNames = 0;
389  NameSet* p_rowNames = 0;
390 
391  if ( colNames == 0 )
392  {
393  int nCols = theLP->nCols();
394  std::stringstream name;
395 
396  spx_alloc(p_colNames);
397  p_colNames = new (p_colNames) NameSet();
398  p_colNames->reMax(nCols);
399  for (int j = 0; j < nCols; ++j)
400  {
401  name << "x" << j;
402  DataKey key = theLP->colId(j);
403  p_colNames->add(key, name.str().c_str());
404  }
405  cNames = p_colNames;
406  }
407 
408  if ( rNames == 0 )
409  {
410  int nRows = theLP->nRows();
411  std::stringstream name;
412 
413  spx_alloc(p_rowNames);
414  p_rowNames = new (p_rowNames) NameSet();
415  p_rowNames->reMax(nRows);
416  for (int i = 0; i < nRows; ++i)
417  {
418  name << "C" << i;
419  DataKey key = theLP->rowId(i);
420  p_rowNames->add(key, name.str().c_str());
421  }
422  rNames = p_rowNames;
423  }
424 
425  /* load default basis if necessary */
426  if (status() == NO_PROBLEM)
427  load(theLP);
428 
429  /* initialize with standard settings */
430  Desc l_desc(thedesc);
431 
432  for (int i = 0; i < theLP->nRows(); i++)
433  l_desc.rowstat[i] = dualRowStatus(i);
434 
435  for (int i = 0; i < theLP->nCols(); i++)
436  {
437  if (theLP->SPxLP::lower(i) == theLP->SPxLP::upper(i))
438  l_desc.colstat[i] = Desc::P_FIXED;
439  else if (theLP->SPxLP::lower(i) <= -infinity && theLP->SPxLP::upper(i) >= infinity)
440  l_desc.colstat[i] = Desc::P_FREE;
441  else if (theLP->SPxLP::lower(i) <= -infinity)
442  l_desc.colstat[i] = Desc::P_ON_UPPER;
443  else
444  l_desc.colstat[i] = Desc::P_ON_LOWER;
445  }
446 
447  MPSInput mps(is);
448 
449  if (mps.readLine() && (mps.field0() != 0) && !strcmp(mps.field0(), "NAME"))
450  {
451  while (mps.readLine())
452  {
453  int c = -1;
454  int r = -1;
455 
456  if ((mps.field0() != 0) && !strcmp(mps.field0(), "ENDATA"))
457  {
459  break;
460  }
461  if ((mps.field1() == 0) || (mps.field2() == 0))
462  break;
463 
464  if ((c = cNames->number(mps.field2())) < 0)
465  break;
466 
467  if (*mps.field1() == 'X')
468  if (mps.field3() == 0 || (r = rNames->number(mps.field3())) < 0)
469  break;
470 
471  if (!strcmp(mps.field1(), "XU"))
472  {
473  l_desc.colstat[c] = dualColStatus(c);
474  if( theLP->LPRowSet::type(r) == LPRow::GREATER_EQUAL )
475  l_desc.rowstat[r] = Desc::P_ON_LOWER;
476  else if( theLP->LPRowSet::type(r) == LPRow::EQUAL )
477  l_desc.rowstat[r] = Desc::P_FIXED;
478  else
479  l_desc.rowstat[r] = Desc::P_ON_UPPER;
480  }
481  else if (!strcmp(mps.field1(), "XL"))
482  {
483  l_desc.colstat[c] = dualColStatus(c);
484  if( theLP->LPRowSet::type(r) == LPRow::LESS_EQUAL )
485  l_desc.rowstat[r] = Desc::P_ON_UPPER;
486  else if( theLP->LPRowSet::type(r) == LPRow::EQUAL )
487  l_desc.rowstat[r] = Desc::P_FIXED;
488  else
489  l_desc.rowstat[r] = Desc::P_ON_LOWER;
490  }
491  else if (!strcmp(mps.field1(), "UL"))
492  {
493  l_desc.colstat[c] = Desc::P_ON_UPPER;
494  }
495  else if (!strcmp(mps.field1(), "LL"))
496  {
497  l_desc.colstat[c] = Desc::P_ON_LOWER;
498  }
499  else
500  {
501  mps.syntaxError();
502  break;
503  }
504  }
505  }
506  if (!mps.hasError())
507  {
508  if (mps.section() == MPSInput::ENDATA)
509  {
510  // force basis to be different from NO_PROBLEM
511  // otherwise the basis will be overwritten at later stages.
513  loadDesc(l_desc);
514  }
515  else
516  mps.syntaxError();
517  }
518 
519  if ( rowNames == 0 )
520  {
521  p_rowNames->~NameSet();
522  spx_free(p_rowNames);
523  }
524  if ( colNames == 0 )
525  {
526  p_colNames->~NameSet();
527  spx_free(p_colNames);
528  }
529 
530 #ifndef NDEBUG
531  MSG_DEBUG( thedesc.dump() );
532 #endif
533 
534  return !mps.hasError();
535 }
536 
537 
538 /* Get row name - copied from spxmpswrite.cpp
539  *
540  * @todo put this in a common file and unify accross different formats (mps, lp, basis).
541  */
542 static const char* getRowName(
543  const SPxLP* lp,
544  int idx,
545  const NameSet* rnames,
546  char* buf)
547 {
548  assert(buf != 0);
549  assert(idx >= 0);
550  assert(idx < lp->nRows());
551 
552  if (rnames != 0)
553  {
554  DataKey key = lp->rId(idx);
555 
556  if (rnames->has(key))
557  return (*rnames)[key];
558  }
559  std::sprintf(buf, "C%d", idx);
560 
561  return buf;
562 }
563 
564 /* Get column name - copied from spxmpswrite.cpp
565  *
566  * @todo put this in a common file and unify accross different formats (mps, lp, basis).
567  */
568 static const char* getColName(
569  const SPxLP* lp,
570  int idx,
571  const NameSet* cnames,
572  char* buf)
573 {
574  assert(buf != 0);
575  assert(idx >= 0);
576  assert(idx < lp->nCols());
577 
578  if (cnames != 0)
579  {
580  DataKey key = lp->cId(idx);
581 
582  if (cnames->has(key))
583  return (*cnames)[key];
584  }
585  std::sprintf(buf, "x%d", idx);
586 
587  return buf;
588 }
589 
590 /* writes a file in MPS basis format to \p os.
591  *
592  * See SPxBasis::readBasis() for a short description of the format.
593  */
595  std::ostream& os,
596  const NameSet* rowNames,
597  const NameSet* colNames,
598  const bool cpxFormat
599  ) const
600 {
601  assert(theLP != 0);
602 
603  os.setf(std::ios::left);
604  os << "NAME soplex.bas\n";
605 
606  /* do not write basis if there is none */
607  if (status() == NO_PROBLEM)
608  {
609  os << "ENDATA" << std::endl;
610  return;
611  }
612 
613  /* start writing */
614  char buf[255];
615  int row = 0;
616  for (int col = 0; col < theLP->nCols(); col++)
617  {
618  if ( thedesc.colStatus(col) > 0 )
619  {
620  /* Find non basic row */
621  for (; row < theLP->nRows(); row++)
622  {
623  if ( thedesc.rowStatus(row) < 0 )
624  break;
625  }
626 
627  assert( row != theLP->nRows() );
628 
629  if( thedesc.rowStatus( row ) == Desc::P_ON_UPPER && (!cpxFormat || theLP->LPRowSet::type(row) == LPRow::RANGE) )
630  os << " XU ";
631  else
632  os << " XL ";
633 
634  os << std::setw(8) << getColName(theLP, col, colNames, buf);
635 
636  /* break in two parts since buf is reused */
637  os << " "
638  << getRowName(theLP, row, rowNames, buf)
639  << std::endl;
640 
641  row++;
642  }
643  else
644  {
645  if ( thedesc.colStatus( col ) == Desc::P_ON_UPPER )
646  {
647  os << " UL "
648  << getColName(theLP, col, colNames, buf)
649  << std::endl;
650  }
651  else
652  {
653  /* Default is all non-basic variables on lower bound (if finite) or at zero (if free).
654  * nothing to do in this case.
655  */
656  assert(theLP->lower(col) <= -infinity || thedesc.colStatus(col) == Desc::P_ON_LOWER || thedesc.colStatus(col) == Desc::P_FIXED);
657  assert(theLP->lower(col) > -infinity || theLP->upper(col) < infinity || thedesc.colStatus(col) == Desc::P_FREE);
658  }
659  }
660  }
661 
662 #ifndef NDEBUG
663  MSG_DEBUG( thedesc.dump() );
664 
665  // Check that we covered all nonbasic rows - the remaining should be basic.
666  for (; row < theLP->nRows(); row++)
667  {
668  if ( thedesc.rowStatus(row) < 0 )
669  break;
670  }
671  assert( row == theLP->nRows() );
672 
673 #endif // NDEBUG
674 
675  os << "ENDATA" << std::endl;
676 }
677 
679 {
680 
681  assert(matrixIsSetup);
682 
683  for( int i = 0; i < matrix.size(); i++ )
684  {
685  std::cout << "C" << i << "=" << *matrix[i] << std::endl;
686  }
687 }
688 
689 void SPxBasis::printMatrixMTX(int number)
690 {
691  int dim;
692  int nnz;
693  char filename[30];
694 
695  dim = matrix.size();
696  nnz = nzCount;
697  sprintf(filename, "basis/basis%d.mtx",number);
698  std::cout << "printing basis matrix to file " << filename << "\n";
699  FILE * basisfile;
700  basisfile = fopen (filename,"w");
701  // print marker necessary for reading the file in Matlab
702  fprintf(basisfile, "%%%%MatrixMarket matrix coordinate real general\n");
703  // print matrix information
704  fprintf(basisfile, "%d %d %d\n", dim, dim, nnz );
705  // print matrix data
706  for( int i = 0; i < matrix.size(); ++i )
707  {
708  for( int j = 0; j < baseVec(i).size(); ++j )
709  {
710  int idx = baseVec(i).index(j);
711  Real val = baseVec(i).value(j);
712  fprintf(basisfile, "%d %d %.13" REAL_FORMAT "\n",i+1,idx+1,val);
713  }
714  }
715  fclose (basisfile);
716 
717  return;
718 }
719 
721  int i,
722  SPxId& id,
723  const SVector* enterVec,
724  const SSVector* eta)
725 {
726 
727  assert(matrixIsSetup);
728  assert(!id.isValid() || (enterVec != 0));
729  assert(factor != 0);
730 
731  lastidx = i;
732  lastin = id;
733 
734  if (id.isValid() && i >= 0)
735  {
736  assert(enterVec != 0);
737 
738  nzCount = nzCount - matrix[i]->size() + enterVec->size();
739  matrix[i] = enterVec;
740  lastout = theBaseId[i];
741  theBaseId[i] = id;
742 
743  ++iterCount;
744  ++updateCount;
745 
746  // never factorize? Just do it !
747  if (!factorized)
748  factorize();
749  // relative fill too high ?
750  else if (Real(factor->memory()) > lastFill * Real(nzCount))
751  {
752  MSG_INFO3( (*spxout), (*spxout) << "IBASIS04 fill factor triggers refactorization"
753  << " memory= " << factor->memory()
754  << " nzCount= " << nzCount
755  << " lastFill= " << lastFill
756  << std::endl; )
757 
758  factorize();
759  }
760  // absolute fill too high ?
761  else if (nzCount > lastNzCount)
762  {
763  MSG_INFO3( (*spxout), (*spxout) << "IBASIS05 nonzero factor triggers refactorization"
764  << " nzCount= " << nzCount
765  << " lastNzCount= " << lastNzCount
766  << " nonzeroFactor= " << nonzeroFactor
767  << std::endl; )
768  factorize();
769  }
770  // too many updates ?
771  else if (updateCount >= maxUpdates)
772  {
773  MSG_INFO3( (*spxout), (*spxout) << "IBASIS06 update count triggers refactorization"
774  << " updateCount= " << updateCount
775  << " maxUpdates= " << maxUpdates
776  << std::endl; )
777  factorize();
778  }
779  else
780  {
781  try
782  {
783 #ifdef MEASUREUPDATETIME
784  theTime.start();
785 #endif
786  factor->change(i, *enterVec, eta);
788 #ifdef MEASUREUPDATETIME
789  theTime.stop();
790 #endif
791  }
792  catch( ... )
793  {
794  MSG_INFO3( (*spxout), (*spxout) << "IBASIS13 problems updating factorization; refactorizing basis"
795  << std::endl; )
796 
797 #ifdef MEASUREUPDATETIME
798  theTime.stop();
799 #endif
800 
801  // singularity was detected in update; we refactorize
802  factorize();
803 
804  // if factorize() detects singularity, an exception is thrown, hence at this point we have a regular basis
805  // and can try the update again
806  assert(status() >= SPxBasis::REGULAR);
807  try
808  {
809 #ifdef MEASUREUPDATETIME
810  theTime.start();
811 #endif
812  factor->change(i, *enterVec, eta);
814 #ifdef MEASUREUPDATETIME
815  theTime.stop();
816 #endif
817  }
818  // with a freshly factorized, regular basis, the update is unlikely to fail; if this happens nevertheless,
819  // we have to invalidate the basis to have the statuses correct
820  catch( const SPxException& F )
821  {
822  MSG_INFO3( (*spxout), (*spxout) << "IBASIS14 problems updating factorization; invalidating factorization"
823  << std::endl; )
824 
825 #ifdef MEASUREUPDATETIME
826  theTime.stop();
827 #endif
828 
829  factorized = false;
830  throw F;
831  }
832  }
833 
834  assert(minStab > 0.0);
835 
837  {
838  MSG_INFO3( (*spxout), (*spxout) << "IBASIS07 stability triggers refactorization"
839  << " stability= " << factor->stability()
840  << " minStab= " << minStab
841  << std::endl; )
842  factorize();
843  }
844  }
845  }
846  else
847  lastout = id;
848 }
849 
851 {
852 
853  assert(factor != 0);
854 
855  if (!matrixIsSetup)
856  loadDesc(thedesc);
857 
858  assert(matrixIsSetup);
859 
860  updateCount = 0;
861 
862  switch(factor->load(matrix.get_ptr(), matrix.size()))
863  {
864  case SLinSolver::OK :
865  if (status() == SINGULAR)
867 
868  minStab = factor->stability();
869 
870  // This seems allways be about 1e-7
871  if (minStab > 1e-4)
872  minStab *= 0.001;
873  if (minStab > 1e-5)
874  minStab *= 0.01;
875  if (minStab > 1e-6)
876  minStab *= 0.1;
877  break;
878  case SLinSolver::SINGULAR :
880  break;
881  default :
882  MSG_ERROR( std::cerr << "EBASIS08 error: unknown status of factorization.\n"; )
883  throw SPxInternalCodeException("XBASIS01 This should never happen.");
884  // factorized = false;
885  }
886 
887  lastMem = factor->memory();
888  lastFill = fillFactor * Real(factor->memory()) / Real(nzCount > 0 ? nzCount : 1);
889  lastNzCount = int(nonzeroFactor * Real(nzCount > 0 ? nzCount : 1));
890  factorized = true;
891 
892  if (status() == SINGULAR)
893  throw SPxStatusException();
894 }
895 
897 {
898  assert(status() > SINGULAR);
899  assert(theLP->dim() == x.dim());
900 
901  int i;
902  DVector tmp(x);
903 
904  if (!matrixIsSetup)
905  (const_cast<SPxBasis*>(this))->loadDesc(thedesc);
906 
907  assert( matrixIsSetup );
908 
909  for (i = x.dim() - 1; i >= 0; --i)
910  x[i] = *(matrix[i]) * tmp;
911 
912  return x;
913 }
914 
915 void SPxBasis::multWithBase(SSVector& x, SSVector& result) const
916 {
917  assert(status() > SINGULAR);
918  assert(theLP->dim() == x.dim());
919  assert(x.dim() == result.dim());
920 
921  if (!matrixIsSetup)
922  (const_cast<SPxBasis*>(this))->loadDesc(thedesc);
923 
924  assert(matrixIsSetup);
925 
926  for( int i = 0; i < x.dim(); ++i )
927  result.setValue(i, (*matrix[i]) * x);
928 
929  return;
930 }
931 
932 
934 {
935  assert(status() > SINGULAR);
936  assert(theLP->dim() == x.dim());
937 
938  int i;
939  DVector tmp(x);
940 
941  if (!matrixIsSetup)
942  (const_cast<SPxBasis*>(this))->loadDesc(thedesc);
943 
944  assert( matrixIsSetup );
945 
946  x.clear();
947  for (i = x.dim() - 1; i >= 0; --i)
948  {
949  if (tmp[i] != 0.0)
950  x.multAdd(tmp[i], *(matrix[i]));
951  }
952 
953  return x;
954 }
955 
956 void SPxBasis::multBaseWith(SSVector& x, SSVector& result) const
957 {
958  assert(status() > SINGULAR);
959  assert(theLP->dim() == x.dim());
960  assert(x.dim() == result.dim());
961 
962  if (!matrixIsSetup)
963  (const_cast<SPxBasis*>(this))->loadDesc(thedesc);
964 
965  assert(matrixIsSetup);
966 
967  result.clear();
968  for( int i = 0; i < x.size(); ++i )
969  {
970  result.multAdd(x[i], (*matrix[i]));
971  }
972 
973  return;
974 }
975 
976 /* compute an estimated condition number for the current basis matrix
977  * by computing estimates of the norms of B and B^-1 using the power method.
978  * maxiters and tolerance control the accuracy of the estimate.
979  */
980 Real SPxBasis::condition(int maxiters, Real tolerance)
981 {
982  int dimension = matrix.size();
983  int i;
984  int c;
985  Real norm;
986  Real norminv;
987  Real norm1;
988  Real norm2;
989 
990  SSVector x(dimension);
991  SSVector y(dimension);
992 
993  // check whether a regular basis matrix is available
994  if( status() < REGULAR )
995  return 0;
996 
997  if (!matrixIsSetup)
998  (const_cast<SPxBasis*>(this))->loadDesc(thedesc);
999 
1000  // initialize vectors
1001  norm1 = 1.0 / (Real) dimension;
1002  for( i = 0; i < dimension; i++ )
1003  x.add(i, norm1);
1004  y = x;
1005 
1006  // compute norm of B
1007  for( c = 0; c < maxiters; ++c )
1008  {
1009  norm2 = norm1;
1010 
1011  // y = B*x
1012  multBaseWith(x, y);
1013  norm1 = y.length();
1014 
1015  // stop if converged
1016  if( spxAbs(norm1 - norm2) < tolerance * norm1 )
1017  break;
1018 
1019  // x = B^T*y and normalize
1020  multWithBase(y, x);
1021  x *= 1.0 / x.length();
1022  }
1023  norm = norm1;
1024 
1025  // reinitialize vectors
1026  norm1 = 1.0 / (Real) dimension;
1027  for( i = 0; i < dimension; i++ )
1028  x.setValue(i, norm1);
1029  y = x;
1030 
1031  // compute norm of B^-1
1032  for( c = 0; c < maxiters; ++c )
1033  {
1034  norm2 = norm1;
1035 
1036  // y = B^-1*x
1037  factor->solveRight(x, y);
1038  norm1 = x.length();
1039 
1040  // stop if converged
1041  if( spxAbs(norm1 - norm2) < tolerance * norm1 )
1042  break;
1043 
1044  // x = B^-T*y and normalize
1045  factor->solveLeft(y, x);
1046  y *= 1.0 / y.length();
1047  }
1048  norminv = norm1;
1049 
1050  return norm * norminv;
1051 }
1052 
1054 {
1055  assert(status() > NO_PROBLEM);
1056  assert(theLP != 0);
1057  assert(thedesc.nRows() == theLP->nRows());
1058  assert(thedesc.nCols() == theLP->nCols());
1059  assert(theLP->dim() == matrix.size());
1060 
1061  int i, basesize;
1062 
1063  // Dump regardless of the verbosity level if this method is called.
1064 
1065  std::cout << "DBASIS09 Basis entries:";
1066  basesize = 0;
1067  for (i = 0; i < theLP->nRows(); ++i)
1068  {
1069  if (theLP->isBasic(thedesc.rowStatus(i)))
1070  {
1071  if(basesize % 10 == 0)
1072  std::cout << std::endl << "DBASIS10 ";
1073  SPxRowId id = theLP->SPxLP::rId(i);
1074  std::cout << "\tR" << theLP->number(id);
1075  basesize++;
1076  }
1077  }
1078 
1079  for (i = 0; i < theLP->nCols(); ++i)
1080  {
1081  if (theLP->isBasic(thedesc.colStatus(i)))
1082  {
1083  if(basesize % 10 == 0)
1084  std::cout << std::endl << "DBASIS11 ";
1085  SPxColId id = theLP->SPxLP::cId(i);
1086  std::cout << "\tC" << theLP->number(id);
1087  basesize++;
1088  }
1089  }
1090  std::cout << std::endl;
1091 
1092  assert(basesize == matrix.size());
1093 }
1094 
1095 
1097 {
1098 #ifdef ENABLE_CONSISTENCY_CHECKS
1099  int primals = 0;
1100  int i;
1101 
1102  if (status() > NO_PROBLEM)
1103  {
1104  if (theLP == 0)
1105  return MSGinconsistent("SPxBasis");
1106 
1107  if (theBaseId.size() != theLP->dim() || matrix.size() != theLP->dim())
1108  return MSGinconsistent("SPxBasis");
1109 
1110  if (thedesc.nCols() != theLP->nCols() || thedesc.nRows() != theLP->nRows())
1111  return MSGinconsistent("SPxBasis");
1112 
1113  for (i = 0; i < thedesc.nRows(); ++i)
1114  {
1115  if (thedesc.rowStatus(i) >= 0)
1116  {
1117  if (thedesc.rowStatus(i) != dualRowStatus(i))
1118  return MSGinconsistent("SPxBasis");
1119  }
1120  else
1121  ++primals;
1122  }
1123 
1124  for (i = 0; i < thedesc.nCols(); ++i)
1125  {
1126  if (thedesc.colStatus(i) >= 0)
1127  {
1128  if (thedesc.colStatus(i) != dualColStatus(i))
1129  return MSGinconsistent("SPxBasis");
1130  }
1131  else
1132  ++primals;
1133  }
1134  if (primals != thedesc.nCols())
1135  return MSGinconsistent("SPxBasis");
1136  }
1137  return thedesc.isConsistent() && theBaseId.isConsistent()
1138  && matrix.isConsistent() && factor->isConsistent();
1139 #else
1140  return true;
1141 #endif // CONSISTENCY_CHECKS
1142 }
1143 
1145  : theLP (0)
1146  , matrixIsSetup (false)
1147  , factor (0)
1148  , factorized (false)
1149  , maxUpdates (180)
1150  , nonzeroFactor(10.0)
1151  , fillFactor(5.0)
1152  , iterCount (0)
1153  , updateCount(0)
1154  , totalUpdateCount(0)
1155  , nzCount (1)
1156  , lastMem(0)
1157  , lastFill(0)
1158  , lastNzCount(0)
1159  , theTime(0)
1160  , timerType(ttype)
1161  , lastidx(0)
1162  , minStab(0.0)
1163  , thestatus (NO_PROBLEM)
1164  , freeSlinSolver(false)
1165  , spxout(0)
1166 {
1167  // info: is not consistent at this moment, e.g. because theLP == 0
1168 
1170 }
1171 
1172 /**@warning Do not change the LP object.
1173  * Only pointer to that object is copied.
1174  * Hint: no problem, we use this function for copy
1175  * constructor of SPxSolver
1176  */
1178  : theLP(old.theLP)
1179  , theBaseId(old.theBaseId)
1180  , matrix(old.matrix)
1181  , matrixIsSetup(old.matrixIsSetup)
1182  , factor(old.factor)
1183  , factorized(old.factorized)
1184  , maxUpdates(old.maxUpdates)
1185  , nonzeroFactor(old.nonzeroFactor)
1186  , fillFactor(old.fillFactor)
1187  , iterCount(old.iterCount)
1188  , updateCount(old.updateCount)
1189  , totalUpdateCount(old.totalUpdateCount)
1190  , nzCount(old.nzCount)
1191  , lastMem(old.lastMem)
1192  , lastFill(old.lastFill)
1193  , lastNzCount(old.lastNzCount)
1194  , theTime(old.theTime)
1195  , timerType(old.timerType)
1196  , lastin(old.lastin)
1197  , lastout(old.lastout)
1198  , lastidx(old.lastidx)
1199  , minStab(old.minStab)
1200  , thestatus(old.thestatus)
1201  , thedesc(old.thedesc)
1202  , spxout(old.spxout)
1203 {
1204 
1205  this->factor = old.factor->clone();
1206  freeSlinSolver = true;
1207 
1208  assert(SPxBasis::isConsistent());
1209 }
1210 
1212 {
1213 
1214  assert(!freeSlinSolver || factor != 0);
1215 
1216  if(freeSlinSolver)
1217  {
1218  delete factor;
1219  factor = 0;
1220  }
1221 
1222  spx_free(theTime);
1223 }
1224 
1225 
1226 /**@warning Note that we do not create a deep copy of the corresponding SPxSolver object.
1227  * Only the reference to that object is copied.
1228  */
1230 {
1231 
1232  assert(!freeSlinSolver || factor != 0);
1233 
1234  if (this != &rhs)
1235  {
1236  theLP = rhs.theLP;
1237  theBaseId = rhs.theBaseId;
1238  matrix = rhs.matrix;
1240 
1241  if(freeSlinSolver)
1242  {
1243  delete factor;
1244  factor = 0;
1245  }
1246  factor = rhs.factor->clone();
1247  freeSlinSolver = true;
1248 
1249  factorized = rhs.factorized;
1250  maxUpdates = rhs.maxUpdates;
1252  fillFactor = rhs.fillFactor;
1253  iterCount = rhs.iterCount;
1254  nzCount = rhs.nzCount;
1255  lastFill = rhs.lastFill;
1256  lastNzCount = rhs.lastNzCount;
1257  lastin = rhs.lastin;
1258  lastout = rhs.lastout;
1259  lastidx = rhs.lastidx;
1260  minStab = rhs.minStab;
1261  thestatus = rhs.thestatus;
1262  thedesc = rhs.thedesc;
1263 
1264  assert(SPxBasis::isConsistent());
1265  }
1266 
1267  return *this;
1268 }
1269 
1270 
1271 //
1272 // Auxiliary functions.
1273 //
1274 
1275 // Pretty-printing of basis status.
1276 std::ostream& operator<<( std::ostream& os,
1277  const SPxBasis::SPxStatus& status )
1278 {
1279  switch ( status )
1280  {
1281  case SPxBasis::NO_PROBLEM:
1282  os << "NO_PROBLEM";
1283  break;
1284  case SPxBasis::SINGULAR:
1285  os << "SINGULAR";
1286  break;
1287  case SPxBasis::REGULAR:
1288  os << "REGULAR";
1289  break;
1290  case SPxBasis::DUAL:
1291  os << "DUAL";
1292  break;
1293  case SPxBasis::PRIMAL:
1294  os << "PRIMAL";
1295  break;
1296  case SPxBasis::OPTIMAL:
1297  os << "OPTIMAL";
1298  break;
1299  case SPxBasis::UNBOUNDED:
1300  os << "UNBOUNDED";
1301  break;
1302  case SPxBasis::INFEASIBLE:
1303  os << "INFEASIBLE";
1304  break;
1305  default:
1306  os << "?other?";
1307  break;
1308  }
1309  return os;
1310 }
1311 
1312 
1313 } // namespace soplex