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-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 #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,
52  const Rational& denomBoundSquared, const DIdxSet* indexSet = 0)
53 {
54  bool rval = true;
55  int done = 0;
56 
57  /* denominator must be positive */
58  assert(mpz_sgn(denom) > 0);
59  assert(denomBoundSquared > 0);
60 
61  mpz_t temp;
62  mpz_t td;
63  mpz_t tn;
64  mpz_t Dbound;
65  mpz_t gcd;
66 
67  mpz_init(gcd); /* stores the gcd of denominators; abort if too big */
68  mpz_set_ui(gcd, 1);
69  mpz_init(temp);
70  mpz_init(td);
71  mpz_init(tn);
72  mpz_init(Dbound);
73 
74 #if 1
75  mpz_set_q(Dbound,
76  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 " <<
84  mpz_get_str(0, 10, Dbound) << "\n");
85 
86  /* if Dbound is below 2^24 increase it to this value, this avoids changing input vectors that have low denominator
87  * because they are floating point representable
88  */
89  if(mpz_cmp_ui(Dbound, 16777216) < 0)
90  mpz_set_ui(Dbound, 16777216);
91 
92  /* The following represent a_i, the cont frac representation and p_i/q_i, the convergents */
93  mpz_t a0;
94  mpz_t ai;
95  mpz_init(a0);
96  mpz_init(ai);
97 
98  /* here we use p[2]=pk, p[1]=pk-1,p[0]=pk-2 and same for q */
99  mpz_t p[3];
100  GMPv_init(p, 3);
101  mpz_t q[3];
102  GMPv_init(q, 3);
103 
104  for(int c = 0; (indexSet == 0 && c < dim) || (indexSet != 0 && c < indexSet->size()); c++)
105  {
106  int j = (indexSet == 0 ? c : indexSet->index(c));
107 
108  assert(j >= 0);
109  assert(j < dim);
110 
111  MSG_DEBUG(std::cout << " --> component " << j << " = " << &xnum[j] << " / denom\n");
112 
113  /* if xnum =0 , then just leave x[j] as zero */
114  if(mpz_sgn(xnum[j]) != 0)
115  {
116  /* setup n and d for computing a_i the cont. frac. rep */
117  mpz_set(tn, xnum[j]);
118  mpz_set(td, denom);
119 
120  /* divide tn and td by gcd */
121  mpz_gcd(temp, tn, td);
122  mpz_divexact(tn, tn, temp);
123  mpz_divexact(td, td, temp);
124 
125  if(mpz_cmp(td, Dbound) <= 0)
126  {
127  MSG_DEBUG(std::cout << "marker 1\n");
128 
129  mpq_set_num(resvec[j].getMpqRef_w(), tn);
130  mpq_set_den(resvec[j].getMpqRef_w(), td);
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 
165  while(!done && mpz_cmp_ui(td, 0))
166  {
167  /* update everything: compute next ai, then update convergents */
168 
169  /* update ai */
170  mpz_fdiv_q(ai, tn, td);
171  mpz_fdiv_r(temp, tn, td);
172  mpz_set(tn, td);
173  mpz_set(td, temp);
174 
175  /* shift p,q */
176  mpz_set(q[0], q[1]);
177  mpz_set(q[1], q[2]);
178  mpz_set(p[0], p[1]);
179  mpz_set(p[1], p[2]);
180 
181  /* compute next p,q */
182  mpz_set(p[2], p[0]);
183  mpz_addmul(p[2], p[1], ai);
184  mpz_set(q[2], q[0]);
185  mpz_addmul(q[2], q[1], ai);
186 
187  if(mpz_cmp(q[2], Dbound) > 0)
188  done = 1;
189 
190  cfcnt++;
191 
192  MSG_DEBUG(std::cout << " --> convergent denominator = " << &q[2] << "\n");
193  }
194 
195  /* Assign the values */
196  mpq_set_num(resvec[j].getMpqRef_w(), p[1]);
197  mpq_set_den(resvec[j].getMpqRef_w(), q[1]);
198  mpq_canonicalize(resvec[j].getMpqRef_w());
199  mpz_gcd(temp, gcd, mpq_denref(resvec[j].getMpqRef()));
200  mpz_mul(gcd, gcd, temp);
201 
202  if(mpz_cmp(gcd, Dbound) > 0)
203  {
204  MSG_DEBUG(std::cout << "terminating with gcd " << &gcd << " exceeding Dbound " << &Dbound << "\n");
205  rval = false;
206  goto CLEANUP;
207  }
208  }
209  }
210  }
211 
212 CLEANUP:
213  GMPv_clear(q, 3);
214  GMPv_clear(p, 3);
215  mpz_clear(td);
216  mpz_clear(tn);
217  mpz_clear(a0);
218  mpz_clear(ai);
219  mpz_clear(temp);
220  mpz_clear(Dbound);
221  mpz_clear(gcd);
222 
223  return rval;
224 }
225 #endif
226 
227 
228 
229 /** reconstruct a rational vector */
230 bool reconstructVector(VectorRational& input, const Rational& denomBoundSquared,
231  const DIdxSet* indexSet)
232 {
233 #ifdef SOPLEX_WITH_GMP
234  mpz_t* xnum = 0; /* numerator of input vector */
235  mpz_t denom; /* common denominator of input vector */
236  int rval = true;
237  int dim;
238 
239  dim = input.dim();
240 
241  /* convert vector to mpz format */
242  spx_alloc(xnum, dim);
243  GMPv_init(xnum, dim);
244  mpz_init_set_ui(denom, 1);
245 
246  /* find common denominator */
247  if(indexSet == 0)
248  {
249  for(int i = 0; i < dim; i++)
250  mpz_lcm(denom, denom, mpq_denref(input[i].getMpqRef()));
251 
252  for(int i = 0; i < dim; i++)
253  {
254  mpz_mul(xnum[i], denom, mpq_numref(input[i].getMpqRef()));
255  mpz_divexact(xnum[i], xnum[i], mpq_denref(input[i].getMpqRef()));
256  }
257  }
258  else
259  {
260  for(int i = 0; i < indexSet->size(); i++)
261  {
262  assert(indexSet->index(i) >= 0);
263  assert(indexSet->index(i) < input.dim());
264  mpz_lcm(denom, denom, mpq_denref(input[indexSet->index(i)].getMpqRef()));
265  }
266 
267  for(int i = 0; i < indexSet->size(); i++)
268  {
269  int k = indexSet->index(i);
270  assert(k >= 0);
271  assert(k < input.dim());
272  mpz_mul(xnum[k], denom, mpq_numref(input[k].getMpqRef()));
273  mpz_divexact(xnum[k], xnum[k], mpq_denref(input[k].getMpqRef()));
274  }
275  }
276 
277  MSG_DEBUG(std::cout << "LCM = " << mpz_get_str(0, 10, denom) << "\n");
278 
279  /* reconstruct */
280  rval = Reconstruct(input, xnum, denom, dim, denomBoundSquared, indexSet);
281 
282  mpz_clear(denom);
283  GMPv_clear(xnum, dim);
284  spx_free(xnum);
285 
286  return rval;
287 #else
288  return false;
289 #endif
290 }
291 
292 
293 
294 /** reconstruct a rational solution */
295 /**@todo make this a method of class SoPlex */
297 {
298 #if 0
299  DVectorRational buffer;
300 
301  if(solution.hasPrimal())
302  {
303  buffer.reDim((solution._primal).dim());
304  solution.getPrimal(buffer);
305  reconstructVector(buffer);
306  solution._primal = buffer;
307 
308  buffer.reDim((solution._slacks).dim());
309  solution.getSlacks(buffer);
310  reconstructVector(buffer);
311  solution._slacks = buffer;
312  }
313 
314  if(solution.hasPrimalray())
315  {
316  buffer.reDim((solution._primalray).dim());
317  solution.getPrimalray(buffer);
318  reconstructVector(buffer);
319  solution._primalray = buffer;
320  }
321 
322  if(solution.hasDual())
323  {
324  buffer.reDim((solution._dual).dim());
325  solution.getDual(buffer);
326  reconstructVector(buffer);
327  solution._dual = buffer;
328 
329  buffer.reDim((solution._redcost).dim());
330  solution.getRedcost(buffer);
331  reconstructVector(buffer);
332  solution._redcost = buffer;
333  }
334 
335  if(solution.hasDualfarkas())
336  {
337  buffer.reDim((solution._dualfarkas).dim());
338  solution.getDualfarkas(buffer);
339  reconstructVector(buffer);
340  solution._dualfarkas = buffer;
341  }
342 
343 #endif
344  return true;
345 }
346 } // 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:253
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:230
DVectorBase< R > _primal
Definition: solbase.h:218
bool reconstructSol(SolRational &solution)
Definition: ratrecon.cpp:296
#define MSG_DEBUG(x)
Definition: spxdefines.h:132
std::ostream & operator<<(std::ostream &s, const VectorBase< R > &vec)
Output operator.
Definition: basevectors.h:1136
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:217
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:110