Scippy

SoPlex

Sequential object-oriented simPlex

spxleastsqsc.cpp
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the class library */
4 /* SoPlex --- the Sequential object-oriented simPlex. */
5 /* */
6 /* Copyright (C) 1996-2019 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SoPlex is distributed under the terms of the ZIB Academic Licence. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SoPlex; see the file COPYING. If not email to soplex@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file spxleastsqsc.cpp
17  * @brief LP least squares scaling.
18  */
19 #include <cmath>
20 #include <assert.h>
21 #include "soplex/spxleastsqsc.h"
22 #include "soplex/spxout.h"
23 #include "soplex/basevectors.h"
24 #include "soplex/svsetbase.h"
25 #include "soplex/svectorbase.h"
26 #include "soplex/ssvectorbase.h"
27 #include <array>
28 
29 namespace soplex
30 {
31 
32 /* update scaling vector */
33 static void updateScale(
34  const SSVector vecnnzeroes,
35  const SSVector resnvec,
36  SSVector& tmpvec,
37  SSVector*& psccurr,
38  SSVector*& pscprev,
39  Real qcurr,
40  Real qprev,
41  Real eprev1,
42  Real eprev2)
43 {
44  assert(psccurr != NULL);
45  assert(pscprev != NULL);
46  assert(qcurr * qprev != 0.0);
47 
48  Real fac = -(eprev1 * eprev2);
49 
50  SSVector* pssv;
51 
52  *pscprev -= *psccurr;
53 
54  if(isZero(fac))
55  (*pscprev).clear();
56  else
57  *pscprev *= fac;
58 
59  *pscprev += tmpvec.assignPWproduct4setup(resnvec, vecnnzeroes);
60 
61  *pscprev *= 1.0 / (qcurr * qprev);
62  *pscprev += *psccurr;
63 
64  /* swap pointers */
65  pssv = psccurr;
66  psccurr = pscprev;
67  pscprev = pssv;
68 }
69 
70 /* update scaling vector after main loop */
71 static void updateScaleFinal(
72  const SSVector vecnnzeroes,
73  const SSVector resnvec,
74  SSVector& tmpvec,
75  SSVector*& psccurr,
76  SSVector*& pscprev,
77  Real q,
78  Real eprev1,
79  Real eprev2)
80 {
81  assert(q != 0);
82  assert(psccurr != NULL);
83  assert(pscprev != NULL);
84 
85  Real fac = -(eprev1 * eprev2);
86 
87  *pscprev -= *psccurr;
88 
89  if(isZero(fac))
90  (*pscprev).clear();
91  else
92  *pscprev *= fac;
93 
94  *pscprev += tmpvec.assignPWproduct4setup(resnvec, vecnnzeroes);
95  *pscprev *= 1.0 / q;
96  *pscprev += *psccurr;
97 
98  psccurr = pscprev;
99 }
100 
101 /* update residual vector */
102 static inline void updateRes(
103  const SVSet facset,
104  const SSVector resvecprev,
105  SSVector& resvec,
106  SSVector& tmpvec,
107  Real eprev,
108  Real qcurr)
109 {
110  assert(qcurr != 0.0);
111 
112  if(isZero(eprev))
113  resvec.clear();
114  else
115  resvec *= eprev;
116 
117  tmpvec.assign2product4setup(facset, resvecprev);
118  tmpvec.setup();
119  resvec += tmpvec;
120 
121  resvec *= (-1.0 / qcurr);
122  resvec.setup();
123 }
124 
125 
126 /* initialize constant vectors and matrices */
127 static void initConstVecs(
128  const SVSet* vecset,
129  SVSet& facset,
130  SSVector& veclogs,
131  SSVector& vecnnzinv)
132 {
133  assert(vecset != NULL);
134 
135  const int nvec = vecset->num();
136 
137  for(int k = 0; k < nvec; ++k)
138  {
139  Real logsum = 0.0;
140  int nnz = 0;
141  // get kth row or column of LP
142  const SVector& lpvec = (*vecset)[k];
143  const int size = lpvec.size();
144 
145  for(int i = 0; i < size; ++i)
146  {
147  const Real a = lpvec.value(i);
148 
149  if(!isZero(a))
150  {
151  logsum += log2(double(spxAbs(a))); // todo spxLog2?
152  nnz++;
153  }
154  }
155 
156  Real nnzinv;
157 
158  if(nnz > 0)
159  {
160  nnzinv = 1.0 / nnz;
161  }
162  else
163  {
164  /* all-0 entries */
165  logsum = 1.0;
166  nnzinv = 1.0;
167  }
168 
169  veclogs.add(k, logsum);
170  vecnnzinv.add(k, nnzinv);
171 
172  /* create new vector for facset */
173  SVector& vecnew = (*(facset.create(nnz)));
174 
175  for(int i = 0; i < size; ++i)
176  {
177  if(!isZero(lpvec.value(i)))
178  vecnew.add(lpvec.index(i), nnzinv);
179  }
180 
181  vecnew.sort();
182  }
183 
184  assert(veclogs.isSetup());
185  assert(vecnnzinv.isSetup());
186 }
187 
188 /* return name of scaler */
189 static const char* makename()
190 {
191  return "Least squares";
192 }
193 
195  : SPxScaler(makename(), false, false)
196 {}
197 
200 {}
201 
203 {
204  if(this != &rhs)
205  {
207  }
208 
209  return *this;
210 }
211 
212 
213 void SPxLeastSqSC::setRealParam(Real param, const char* name)
214 {
215  assert(param >= 1.0);
216  acrcydivisor = param;
217 }
218 
219 void SPxLeastSqSC::setIntParam(int param, const char* name)
220 {
221  assert(param >= 0);
222  maxrounds = param;
223 }
224 
225 void SPxLeastSqSC::scale(SPxLP& lp, bool persistent)
226 {
227  MSG_INFO1((*spxout), (*spxout) << "Least squares LP scaling" << (persistent ? " (persistent)" : "")
228  << std::endl;)
229 
230  setup(lp);
231 
232  const int nrows = lp.nRows();
233  const int ncols = lp.nCols();
234  const int lpnnz = lp.nNzos();
235 
236  /* constant factor matrices;
237  * in Curtis-Reid article
238  * facnrows equals E^T M^(-1)
239  * facncols equals E N^(-1)
240  * */
241  SVSet facnrows(nrows, nrows, 1.1, 1.2);
242  SVSet facncols(ncols, ncols, 1.1, 1.2);
243 
244  /* column scaling factor vectors */
245  SSVector colscale1(ncols);
246  SSVector colscale2(ncols);
247 
248  /* row scaling factor vectors */
249  SSVector rowscale1(nrows);
250  SSVector rowscale2(nrows);
251 
252  /* residual vectors */
253  SSVector resnrows(nrows);
254  SSVector resncols(ncols);
255 
256  /* vectors to store temporary values */
257  SSVector tmprows(nrows);
258  SSVector tmpcols(ncols);
259 
260  /* vectors storing the row and column sums (respectively) of logarithms of
261  *(absolute values of) non-zero elements of left hand matrix of LP
262  */
263  SSVector rowlogs(nrows);
264  SSVector collogs(ncols);
265 
266  /* vectors storing the inverted number of non-zeros in each row and column
267  *(respectively) of left hand matrix of LP
268  */
269  SSVector rownnzinv(nrows);
270  SSVector colnnzinv(ncols);
271 
272  /* vector pointers */
273  SSVector* csccurr = &colscale1;
274  SSVector* cscprev = &colscale2;
275  SSVector* rsccurr = &rowscale1;
276  SSVector* rscprev = &rowscale2;
277 
278  MSG_INFO2((*spxout), (*spxout) << "before scaling:"
279  << " min= " << lp.minAbsNzo()
280  << " max= " << lp.maxAbsNzo()
281  << " col-ratio= " << maxColRatio(lp)
282  << " row-ratio= " << maxRowRatio(lp)
283  << std::endl;)
284 
285  /* initialize scalars, vectors and matrices */
286 
287  assert(acrcydivisor > 0.0);
288 
289  const Real smax = lpnnz / acrcydivisor;
290  Real qcurr = 1.0;
291  Real qprev = 0.0;
292 
293  std::array<Real, 3> eprev;
294  eprev.fill(0.0);
295 
296  initConstVecs(lp.rowSet(), facnrows, rowlogs, rownnzinv);
297  initConstVecs(lp.colSet(), facncols, collogs, colnnzinv);
298 
299  assert(tmprows.isSetup());
300  assert(tmpcols.isSetup());
301  assert(rowscale1.isSetup());
302  assert(rowscale2.isSetup());
303  assert(colscale1.isSetup());
304  assert(colscale2.isSetup());
305 
306  // compute first residual vector r0
307  resncols = collogs - tmpcols.assign2product4setup(facnrows, rowlogs);
308 
309  resncols.setup();
310  resnrows.setup();
311 
312  rowscale1.assignPWproduct4setup(rownnzinv, rowlogs);
313  rowscale2 = rowscale1;
314 
315  Real scurr = resncols * tmpcols.assignPWproduct4setup(colnnzinv, resncols);
316 
317  int k;
318 
319  /* conjugate gradient loop */
320  for(k = 0; k < maxrounds; ++k)
321  {
322  const Real sprev = scurr;
323 
324  // is k even?
325  if((k % 2) == 0)
326  {
327  // not in first iteration?
328  if(k != 0) // true, then update row scaling factor vector
329  updateScale(rownnzinv, resnrows, tmprows, rsccurr, rscprev, qcurr, qprev, eprev[1], eprev[2]);
330 
331  updateRes(facncols, resncols, resnrows, tmprows, eprev[0], qcurr);
332  scurr = resnrows * tmprows.assignPWproduct4setup(resnrows, rownnzinv);
333  }
334  else // k is odd
335  {
336  // update column scaling factor vector
337  updateScale(colnnzinv, resncols, tmpcols, csccurr, cscprev, qcurr, qprev, eprev[1], eprev[2]);
338 
339  updateRes(facnrows, resnrows, resncols, tmpcols, eprev[0], qcurr);
340  scurr = resncols * tmpcols.assignPWproduct4setup(resncols, colnnzinv);
341  }
342 
343  // shift eprev entries one to the right
344  for(unsigned l = 2; l > 0; --l)
345  eprev[l] = eprev[l - 1];
346 
347  eprev[0] = (qcurr * scurr) / sprev;
348 
349  const Real tmp = qcurr;
350  qcurr = 1.0 - eprev[0];
351  qprev = tmp;
352 
353  // termination criterion met?
354  if(scurr < smax)
355  break;
356  }
357 
358  // is k even?
359  if((k % 2) == 0)
360  {
361  // update column scaling factor vector
362  updateScaleFinal(colnnzinv, resncols, tmpcols, csccurr, cscprev, qprev, eprev[1], eprev[2]);
363  }
364  else // k is odd
365  {
366  // update row scaling factor vector
367  updateScaleFinal(rownnzinv, resnrows, tmprows, rsccurr, rscprev, qprev, eprev[1], eprev[2]);
368  }
369 
370  /* compute actual scaling factors */
371 
372  const SSVector& rowscale = *rsccurr;
373  const SSVector& colscale = *csccurr;
374 
375  DataArray<int>& colscaleExp = *m_activeColscaleExp;
376  DataArray<int>& rowscaleExp = *m_activeRowscaleExp;
377 
378  for(k = 0; k < nrows; ++k)
379  rowscaleExp[k] = -int(rowscale[k] + ((rowscale[k] >= 0.0) ? (+0.5) : (-0.5)));
380 
381  for(k = 0; k < ncols; ++k)
382  colscaleExp[k] = -int(colscale[k] + ((colscale[k] >= 0.0) ? (+0.5) : (-0.5)));
383 
384  // scale
385  applyScaling(lp);
386 
387  MSG_INFO3((*spxout), (*spxout) << "Row scaling min= " << minAbsRowscale()
388  << " max= " << maxAbsRowscale()
389  << std::endl
390  << "Col scaling min= " << minAbsColscale()
391  << " max= " << maxAbsColscale()
392  << std::endl;)
393 
394  MSG_INFO2((*spxout), (*spxout) << "after scaling: "
395  << " min= " << lp.minAbsNzo(false)
396  << " max= " << lp.maxAbsNzo(false)
397  << " col-ratio= " << maxColRatio(lp)
398  << " row-ratio= " << maxRowRatio(lp)
399  << std::endl;)
400 }
401 
402 } // namespace soplex
Rational spxAbs(const Rational &r)
Absolute.
Definition: rational.cpp:4102
virtual void setup(SPxLPBase< Real > &lp)
clear and setup scaling arrays in the LP
Definition: spxscaler.cpp:129
bool isSetup() const
Returns setup status.
Definition: ssvectorbase.h:121
virtual R minAbsNzo(bool unscaled=true) const
Absolute smallest non-zero element in (possibly scaled) LP.
static const char * makename(bool doBoth)
Definition: spxequilisc.cpp:29
int size() const
Number of used indices.
Definition: svectorbase.h:153
static void updateRes(const SVSet facset, const SSVector resvecprev, SSVector &resvec, SSVector &tmpvec, Real eprev, Real qcurr)
Set of sparse vectors.
Least squares scaling.This SPxScaler implementation performs least squares scaling as suggested by Cu...
Definition: spxleastsqsc.h:36
virtual Real maxRowRatio(const SPxLPBase< Real > &lp) const
maximum ratio between absolute biggest and smallest element in any row.
Definition: spxscaler.cpp:866
SVectorBase< R > * create(int idxmax=0)
Creates new SVectorBase in set.
Definition: svsetbase.h:437
R & value(int n)
Reference to value of n &#39;th nonzero.
Definition: svectorbase.h:253
SPxLeastSqSC()
default constructor (this scaler makes no use of inherited member m_colFirst)
static void updateScale(const SSVector vecnnzeroes, const SSVector resnvec, SSVector &tmpvec, SSVector *&psccurr, SSVector *&pscprev, Real qcurr, Real qprev, Real eprev1, Real eprev2)
Wrapper for different output streams and verbosity levels.
int nRows() const
Returns number of rows in LP.
Definition: spxlpbase.h:152
DataArray< int > * m_activeColscaleExp
pointer to currently active column scaling factors
Definition: spxscaler.h:84
int nNzos() const
Returns number of nonzeros in LP.
Definition: spxlpbase.h:164
virtual void applyScaling(SPxLPBase< Real > &lp)
applies m_colscale and m_rowscale to the lp.
Definition: spxscaler.cpp:177
virtual void scale(SPxLP &lp, bool persistent=true)
Scale the loaded SPxLP.
static void initConstVecs(const SVSet *vecset, SVSet &facset, SSVector &veclogs, SSVector &vecnnzinv)
double Real
Definition: spxdefines.h:218
SPxOut * spxout
message handler
Definition: spxscaler.h:88
int & index(int n)
Reference to index of n &#39;th nonzero.
Definition: svectorbase.h:235
#define MSG_INFO2(spxout, x)
Prints out message x if the verbosity level is at least SPxOut::INFO2.
Definition: spxdefines.h:120
void clear()
Clears vector.
Definition: ssvectorbase.h:603
virtual Real maxAbsColscale() const
absolute biggest column scaling factor
Definition: spxscaler.cpp:781
virtual Real minAbsColscale() const
absolute smallest column scaling factor
Definition: spxscaler.cpp:768
virtual void setIntParam(int param, const char *name)
set int param (maximal conjugate gradient rounds)
#define MSG_INFO3(spxout, x)
Prints out message x if the verbosity level is at least SPxOut::INFO3.
Definition: spxdefines.h:122
DataArray< int > * m_activeRowscaleExp
pointer to currently active row scaling factors
Definition: spxscaler.h:85
void add(int i, const R &v)
Append one nonzero (i,v).
Definition: svectorbase.h:271
virtual Real minAbsRowscale() const
absolute smallest row scaling factor
Definition: spxscaler.cpp:795
LP least squares scaling.
Collection of dense, sparse, and semi-sparse vectors.
static void updateScaleFinal(const SSVector vecnnzeroes, const SSVector resnvec, SSVector &tmpvec, SSVector *&psccurr, SSVector *&pscprev, Real q, Real eprev1, Real eprev2)
Everything should be within this namespace.
SPxLeastSqSC & operator=(const SPxLeastSqSC &)
assignment operator
void setup()
Initializes nonzero indices for elements with absolute values above epsilon and sets all other elemen...
Definition: ssvectorbase.h:133
Sparse vectors.
virtual void setRealParam(Real param, const char *name)
set real param (conjugate gradient accuracy)
Semi sparse vector.
LP scaler abstract base class.Instances of classes derived from SPxScaler may be loaded to SoPlex in ...
Definition: spxscaler.h:76
void sort()
Sort nonzeros to increasing indices.
Definition: svectorbase.h:437
virtual Real maxAbsRowscale() const
absolute biggest row scaling factor
Definition: spxscaler.cpp:808
#define MSG_INFO1(spxout, x)
Prints out message x if the verbosity level is at least SPxOut::INFO1.
Definition: spxdefines.h:118
int nCols() const
Returns number of columns in LP.
Definition: spxlpbase.h:158
SSVectorBase< R > & assignPWproduct4setup(const SSVectorBase< S > &x, const SSVectorBase< T > &y)
Assigns pair wise vector product to SSVectorBase.
Definition: basevectors.h:478
const SVSetBase< R > * colSet() const
Returns the complete SVSetBase.
Definition: lpcolsetbase.h:68
bool isZero(Real a, Real eps=Param::epsilon())
returns true iff |a| <= eps
Definition: spxdefines.h:412
virtual Real maxColRatio(const SPxLPBase< Real > &lp) const
maximum ratio between absolute biggest and smallest element in any column.
Definition: spxscaler.cpp:825
const SVSetBase< R > * rowSet() const
Returns the complete SVSet.
Definition: lprowsetbase.h:69
void add(int i, R x)
Adds nonzero (i, x) to SSVectorBase.
Definition: ssvectorbase.h:209
int num() const
Current number of SVectorBases.
Definition: svsetbase.h:759
virtual R maxAbsNzo(bool unscaled=true) const
Absolute biggest non-zero element in (in rational case possibly scaled) LP.
SPxScaler & operator=(const SPxScaler &)
assignment operator
Definition: spxscaler.cpp:88
SSVectorBase< R > & assign2product4setup(const SVSetBase< S > &A, const SSVectorBase< T > &x)
Assigns SSVectorBase to for a setup x.
Definition: basevectors.h:570