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