Scippy

SoPlex

Sequential object-oriented simPlex

ratrecon.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-2018 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SoPlex is distributed under the terms of the ZIB Academic Licence. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SoPlex; see the file COPYING. If not email to soplex@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 #include <iostream>
17 #include <assert.h>
18 
19 #include "soplex/spxdefines.h"
20 #include "soplex/ratrecon.h"
21 
22 namespace soplex
23 {
24 #ifdef SOPLEX_WITH_GMP
25  static void GMPv_init(mpz_t* vect, int dim)
26  {
27  for( int i = 0; i < dim; i++ )
28  mpz_init(vect[i]);
29  }
30 
31  static void GMPv_clear(mpz_t* vect, int dim)
32  {
33  for( int i = 0; i < dim; i++ )
34  mpz_clear(vect[i]);
35  }
36 
37 #ifdef SOPLEX_DEBUG
38  /** print integer to stream */
39  static std::ostream& operator<<(std::ostream& os, const mpz_t* number)
40  {
41  os << mpz_get_str(0, 10, *number);
42  return os;
43  }
44 #endif
45 
46  /** this reconstruction routine will set x equal to the mpq vector where each component is the best rational
47  * approximation of xnum / denom with where the GCD of denominators of x is at most Dbound; it will return true on
48  * success and false if more accuracy is required: specifically if componentwise rational reconstruction does not
49  * produce such a vector
50  */
51  static int Reconstruct(VectorRational& resvec, mpz_t* xnum, mpz_t denom, int dim, const Rational& denomBoundSquared, const DIdxSet* indexSet = 0)
52  {
53  bool rval = true;
54  int done = 0;
55 
56  /* denominator must be positive */
57  assert(mpz_sgn(denom) > 0);
58  assert(denomBoundSquared > 0);
59 
60  mpz_t temp;
61  mpz_t td;
62  mpz_t tn;
63  mpz_t Dbound;
64  mpz_t gcd;
65 
66  mpz_init(gcd); /* stores the gcd of denominators; abort if too big */
67  mpz_set_ui(gcd, 1);
68  mpz_init(temp);
69  mpz_init(td);
70  mpz_init(tn);
71  mpz_init(Dbound);
72 
73 #if 1
74  mpz_set_q(Dbound, denomBoundSquared.getMpqRef()); /* this is the working bound on the denominator size */
75 #else
76  mpz_set(Dbound, denom); /* this is the working bound on the denominator size */
77 #endif
78 
79  mpz_sqrt(Dbound, Dbound);
80 
81  MSG_DEBUG( std::cout << "reconstructing " << dim << " dimensional vector with denominator bound " << mpz_get_str(0, 10, Dbound) << "\n" );
82 
83  /* if Dbound is below 2^24 increase it to this value, this avoids changing input vectors that have low denominator
84  * because they are floating point representable
85  */
86  if( mpz_cmp_ui(Dbound,16777216) < 0 )
87  mpz_set_ui(Dbound,16777216);
88 
89  /* The following represent a_i, the cont frac representation and p_i/q_i, the convergents */
90  mpz_t a0;
91  mpz_t ai;
92  mpz_init(a0);
93  mpz_init(ai);
94 
95  /* here we use p[2]=pk, p[1]=pk-1,p[0]=pk-2 and same for q */
96  mpz_t p[3];
97  GMPv_init(p, 3);
98  mpz_t q[3];
99  GMPv_init(q, 3);
100 
101  for( int c = 0; (indexSet == 0 && c < dim) || (indexSet != 0 && c < indexSet->size()); c++ )
102  {
103  int j = (indexSet == 0 ? c : indexSet->index(c));
104 
105  assert(j >= 0);
106  assert(j < dim);
107 
108  MSG_DEBUG( std::cout << " --> component " << j << " = " << &xnum[j] << " / denom\n" );
109 
110  /* if xnum =0 , then just leave x[j] as zero */
111  if( mpz_sgn(xnum[j]) != 0 )
112  {
113  /* setup n and d for computing a_i the cont. frac. rep */
114  mpz_set(tn,xnum[j]);
115  mpz_set(td,denom);
116 
117  /* divide tn and td by gcd */
118  mpz_gcd(temp,tn,td);
119  mpz_divexact(tn,tn,temp);
120  mpz_divexact(td,td,temp);
121 
122  if(mpz_cmp(td,Dbound)<=0)
123  {
124  MSG_DEBUG( std::cout << "marker 1\n" );
125 
126  mpq_set_num(resvec[j].getMpqRef_w(),tn);
127  mpq_set_den(resvec[j].getMpqRef_w(),td);
128  }
129  else
130  {
131  MSG_DEBUG( std::cout << "marker 2\n" );
132 
133  mpz_set_ui(temp,1);
134 
135  mpz_fdiv_q(a0,tn,td);
136  mpz_fdiv_r(temp,tn,td);
137  mpz_set(tn,td);
138  mpz_set(td,temp);
139  mpz_fdiv_q(ai,tn,td);
140  mpz_fdiv_r(temp,tn,td);
141  mpz_set(tn,td);
142  mpz_set(td,temp);
143 
144  mpz_set(p[1],a0);
145  mpz_set_ui(p[2],1);
146  mpz_addmul(p[2],a0,ai);
147 
148  mpz_set_ui(q[1],1);
149  mpz_set(q[2],ai);
150 
151  done = 0;
152 
153  /* if q is already big, skip loop */
154  if( mpz_cmp(q[2],Dbound) > 0 )
155  {
156  MSG_DEBUG( std::cout << "marker 3\n" );
157  done = 1;
158  }
159 
160  int cfcnt = 2;
161  while( !done && mpz_cmp_ui(td,0) )
162  {
163  /* update everything: compute next ai, then update convergents */
164 
165  /* update ai */
166  mpz_fdiv_q(ai, tn, td);
167  mpz_fdiv_r(temp, tn, td);
168  mpz_set(tn, td);
169  mpz_set(td, temp);
170 
171  /* shift p,q */
172  mpz_set(q[0], q[1]);
173  mpz_set(q[1], q[2]);
174  mpz_set(p[0], p[1]);
175  mpz_set(p[1], p[2]);
176 
177  /* compute next p,q */
178  mpz_set(p[2], p[0]);
179  mpz_addmul(p[2], p[1], ai);
180  mpz_set(q[2], q[0]);
181  mpz_addmul(q[2], q[1], ai);
182 
183  if( mpz_cmp(q[2], Dbound) > 0 )
184  done = 1;
185  cfcnt++;
186 
187  MSG_DEBUG( std::cout << " --> convergent denominator = " << &q[2] << "\n" );
188  }
189 
190  /* Assign the values */
191  mpq_set_num(resvec[j].getMpqRef_w(), p[1]);
192  mpq_set_den(resvec[j].getMpqRef_w(), q[1]);
193  mpq_canonicalize(resvec[j].getMpqRef_w());
194  mpz_gcd(temp, gcd, mpq_denref(resvec[j].getMpqRef()));
195  mpz_mul(gcd, gcd, temp);
196 
197  if( mpz_cmp(gcd, Dbound) > 0 )
198  {
199  MSG_DEBUG( std::cout << "terminating with gcd " << &gcd << " exceeding Dbound " << &Dbound << "\n" );
200  rval = false;
201  goto CLEANUP;
202  }
203  }
204  }
205  }
206 
207  CLEANUP:
208  GMPv_clear(q, 3);
209  GMPv_clear(p, 3);
210  mpz_clear(td);
211  mpz_clear(tn);
212  mpz_clear(a0);
213  mpz_clear(ai);
214  mpz_clear(temp);
215  mpz_clear(Dbound);
216  mpz_clear(gcd);
217 
218  return rval;
219  }
220 #endif
221 
222 
223 
224  /** reconstruct a rational vector */
225  bool reconstructVector(VectorRational& input, const Rational& denomBoundSquared, const DIdxSet* indexSet)
226  {
227 #ifdef SOPLEX_WITH_GMP
228  mpz_t* xnum = 0; /* numerator of input vector */
229  mpz_t denom; /* common denominator of input vector */
230  int rval = true;
231  int dim;
232 
233  dim = input.dim();
234 
235  /* convert vector to mpz format */
236  spx_alloc(xnum, dim);
237  GMPv_init(xnum, dim);
238  mpz_init_set_ui(denom, 1);
239 
240  /* find common denominator */
241  if( indexSet == 0 )
242  {
243  for( int i = 0; i < dim; i++ )
244  mpz_lcm(denom, denom, mpq_denref(input[i].getMpqRef()));
245 
246  for( int i = 0; i < dim; i++ )
247  {
248  mpz_mul(xnum[i], denom, mpq_numref(input[i].getMpqRef()));
249  mpz_divexact(xnum[i], xnum[i], mpq_denref(input[i].getMpqRef()));
250  }
251  }
252  else
253  {
254  for( int i = 0; i < indexSet->size(); i++ )
255  {
256  assert(indexSet->index(i) >= 0);
257  assert(indexSet->index(i) < input.dim());
258  mpz_lcm(denom, denom, mpq_denref(input[indexSet->index(i)].getMpqRef()));
259  }
260 
261  for( int i = 0; i < indexSet->size(); i++ )
262  {
263  int k = indexSet->index(i);
264  assert(k >= 0);
265  assert(k < input.dim());
266  mpz_mul(xnum[k], denom, mpq_numref(input[k].getMpqRef()));
267  mpz_divexact(xnum[k], xnum[k], mpq_denref(input[k].getMpqRef()));
268  }
269  }
270 
271  MSG_DEBUG( std::cout << "LCM = " << mpz_get_str(0, 10, denom) << "\n" );
272 
273  /* reconstruct */
274  rval = Reconstruct(input, xnum, denom, dim, denomBoundSquared, indexSet);
275 
276  mpz_clear(denom);
277  GMPv_clear(xnum, dim);
278  spx_free(xnum);
279 
280  return rval;
281 #else
282  return false;
283 #endif
284  }
285 
286 
287 
288  /** reconstruct a rational solution */
289  /**@todo make this a method of class SoPlex */
290  bool reconstructSol(SolRational& solution)
291  {
292 #if 0
293  DVectorRational buffer;
294 
295  if( solution.hasPrimal() )
296  {
297  buffer.reDim((solution._primal).dim());
298  solution.getPrimal(buffer);
299  reconstructVector(buffer);
300  solution._primal = buffer;
301 
302  buffer.reDim((solution._slacks).dim());
303  solution.getSlacks(buffer);
304  reconstructVector(buffer);
305  solution._slacks = buffer;
306  }
307 
308  if( solution.hasPrimalray() )
309  {
310  buffer.reDim((solution._primalray).dim());
311  solution.getPrimalray(buffer);
312  reconstructVector(buffer);
313  solution._primalray = buffer;
314  }
315 
316  if( solution.hasDual() )
317  {
318  buffer.reDim((solution._dual).dim());
319  solution.getDual(buffer);
320  reconstructVector(buffer);
321  solution._dual = buffer;
322 
323  buffer.reDim((solution._redcost).dim());
324  solution.getRedcost(buffer);
325  reconstructVector(buffer);
326  solution._redcost = buffer;
327  }
328 
329  if( solution.hasDualfarkas() )
330  {
331  buffer.reDim((solution._dualfarkas).dim());
332  solution.getDualfarkas(buffer);
333  reconstructVector(buffer);
334  solution._dualfarkas = buffer;
335  }
336 #endif
337  return true;
338  }
339 } // namespace soplex
DVectorBase< R > _slacks
Definition: solbase.h:219
bool getDual(VectorBase< R > &vector) const
gets the dual solution vector; returns true on success
Definition: solbase.h:94
void reDim(int newdim, const bool setZero=true)
Resets DVectorBase&#39;s dimension to newdim.
Definition: dvectorbase.h:249
Dense vector.Class VectorBase provides dense linear algebra vectors. It does not provide memory manag...
Definition: dsvectorbase.h:28
bool getSlacks(VectorBase< R > &vector) const
gets the vector of slack values; returns true on success
Definition: solbase.h:65
Wrapper for GMP type mpq_class.We wrap mpq_class so that we can replace it by a double type if GMP is...
Definition: rational.h:44
bool getPrimal(VectorBase< R > &vector) const
gets the primal solution vector; returns true on success
Definition: solbase.h:57
void spx_alloc(T &p, int n=1)
Allocate memory.
Definition: spxalloc.h:48
Rational reconstruction of solution vector.
bool reconstructVector(VectorRational &input, const Rational &denomBoundSquared, const DIdxSet *indexSet)
Definition: ratrecon.cpp:225
DVectorBase< R > _primal
Definition: solbase.h:218
bool reconstructSol(SolRational &solution)
Definition: ratrecon.cpp:290
#define MSG_DEBUG(x)
Definition: spxdefines.h:132
std::ostream & operator<<(std::ostream &s, const VectorBase< R > &vec)
Output operator.
Definition: basevectors.h:1123
int size() const
returns the number of used indices.
Definition: idxset.h:124
Dynamic index set.Class DIdxSet provides dynamic IdxSet in the sense, that no restrictions are posed ...
Definition: didxset.h:42
Debugging, floating point type and parameter definitions.
int dim() const
Dimension of vector.
Definition: vectorbase.h:215
Everything should be within this namespace.
VectorBase< Rational > VectorRational
Definition: vector.h:31
int index(int n) const
access n &#39;th index.
Definition: idxset.h:118
DVectorBase< R > _dual
Definition: solbase.h:221
void spx_free(T &p)
Release memory.
Definition: spxalloc.h:109