PPL  1.2
Dense_Row.cc
Go to the documentation of this file.
1 /* Dense_Row class implementation (non-inline functions).
2  Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it>
3  Copyright (C) 2010-2016 BUGSENG srl (http://bugseng.com)
4 
5 This file is part of the Parma Polyhedra Library (PPL).
6 
7 The PPL is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 The PPL is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software Foundation,
19 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA.
20 
21 For the most up-to-date information see the Parma Polyhedra Library
22 site: http://bugseng.com/products/ppl/ . */
23 
24 #include "ppl-config.h"
25 #include "Dense_Row_defs.hh"
26 #include "Coefficient_defs.hh"
27 #include "assertions.hh"
28 #include "Sparse_Row_defs.hh"
29 #include <iostream>
30 #include <iomanip>
31 
32 namespace PPL = Parma_Polyhedra_Library;
33 
35  dimension_type sz, dimension_type capacity) {
36  resize(sz, capacity);
37  for (Sparse_Row::const_iterator i = y.begin(),
38  i_end = y.lower_bound(std::min(y.size(), sz)); i != i_end; ++i) {
39  (*this)[i.index()] = *i;
40  }
41  PPL_ASSERT(OK());
42 }
43 
44 void
46  if (new_size <= size()) {
47  shrink(new_size);
48  }
49  else {
50  if (new_size > capacity()) {
51  // Reallocation is required.
52  // TODO: Consider using realloc() here.
53  // TODO: Consider using a smarter allocation strategy.
54  const dimension_type new_capacity = new_size;
55  Coefficient* const new_vec = impl.coeff_allocator.allocate(new_capacity);
56 
57  if (impl.vec != 0) {
58  memcpy(new_vec, impl.vec, sizeof(Coefficient) * impl.size);
59  impl.coeff_allocator.deallocate(impl.vec, impl.capacity);
60  }
61 
62  impl.vec = new_vec;
63  impl.capacity = new_capacity;
64  }
65  PPL_ASSERT(new_size <= impl.capacity);
66  // Construct the additional elements.
67  while (impl.size != new_size) {
68  new(&impl.vec[impl.size]) Coefficient();
69  ++impl.size;
70  }
71  }
72  PPL_ASSERT(size() == new_size);
73  PPL_ASSERT(OK());
74 }
75 
76 void
78  PPL_ASSERT(new_size <= new_capacity);
79 
80  if (new_capacity == 0) {
81  destroy();
82  impl.vec = 0;
83  impl.size = 0;
84  impl.capacity = 0;
85 
86  PPL_ASSERT(size() == new_size);
87  PPL_ASSERT(capacity() == new_capacity);
88  PPL_ASSERT(OK());
89 
90  return;
91  }
92 
93  if (new_capacity < capacity()) {
94 
95  shrink(new_size);
96 
97  PPL_ASSERT(impl.size == new_size);
98 
99  Coefficient* const new_vec = impl.coeff_allocator.allocate(new_capacity);
100 
101  PPL_ASSERT(impl.vec != 0);
102 
103  memcpy(new_vec, impl.vec, sizeof(Coefficient) * impl.size);
104 
105  impl.coeff_allocator.deallocate(impl.vec, impl.capacity);
106 
107  impl.vec = new_vec;
108  impl.capacity = new_capacity;
109  }
110  else {
111  if (new_capacity > capacity()) {
112 
113  Coefficient* const new_vec = impl.coeff_allocator.allocate(new_capacity);
114 
115  if (impl.vec != 0) {
116  memcpy(new_vec, impl.vec, sizeof(Coefficient) * impl.size);
117  impl.coeff_allocator.deallocate(impl.vec, impl.capacity);
118  }
119 
120  impl.vec = new_vec;
121  impl.capacity = new_capacity;
122 
123  resize(new_size);
124  }
125  }
126 
127  PPL_ASSERT(size() == new_size);
128  PPL_ASSERT(capacity() == new_capacity);
129  PPL_ASSERT(OK());
130 }
131 
132 void
134  for (iterator i = begin(), i_end = end(); i != i_end; ++i) {
135  *i = 0;
136  }
137 }
138 
139 void
141  PPL_ASSERT(i <= size());
142  const dimension_type new_size = size() + n;
143  if (new_size > capacity()) {
144  Dense_Row new_row;
145  const dimension_type new_capacity = compute_capacity(new_size, max_size());
146  // This may throw.
147  new_row.impl.vec = new_row.impl.coeff_allocator.allocate(new_capacity);
148  new_row.impl.capacity = new_capacity;
149 
150  dimension_type j = i;
151  try {
152  // Construct coefficients with value 0 in
153  // new_row.impl.vec[i ... i + n - 1]
154  for ( ; j < i + n; ++j) {
155  new(&(new_row.impl.vec[j])) Coefficient(0);
156  }
157  } catch (...) {
158  // Destroy the zeroes constructed so far.
159  while (j != i) {
160  --j;
161  new_row.impl.vec[j].~Coefficient();
162  }
163  // The new_row's destructor will de-allocate the memory.
164  throw;
165  }
166 
167  // Raw-copy the coefficients.
168  memcpy(new_row.impl.vec, impl.vec, sizeof(Coefficient) * i);
169  memcpy(&(new_row.impl.vec[i + n]), &impl.vec[i],
170  sizeof(Coefficient) * (impl.size - i));
171 
172  using std::swap;
173  swap(impl.vec, new_row.impl.vec);
174  swap(impl.capacity, new_row.impl.capacity);
175 
176  // *this now owns all coefficients, including the newly-added zeroes.
177  impl.size = new_size;
178 
179  // The old vec will be de-allocated at the end of this block.
180 
181  }
182  else {
183  memmove(&impl.vec[n + i], &impl.vec[i], sizeof(Coefficient)
184  * (impl.size - i));
185  impl.size = i;
186  const dimension_type target_size = impl.size + n;
187  PPL_ASSERT(target_size == i + n);
188  try {
189  // Construct n zeroes where the moved elements resided.
190  while (impl.size != target_size) {
191  new(&impl.vec[impl.size]) Coefficient(0);
192  ++impl.size;
193  }
194  impl.size = new_size;
195  } catch (...) {
196  // impl.vec[impl.size]..impl.vec[target_size-1] are still unconstructed,
197  // but impl.vec[target_size]..impl.vec[new_size] are constructed,
198  // because the memmove() moved already-constructed objects.
199 
200  // NOTE: This loop can't throw, because destructors must not throw.
201  for (dimension_type j = target_size; j < new_size; ++j) {
202  impl.vec[j].~Coefficient();
203  }
204 
205  throw;
206  }
207  }
208 
209  PPL_ASSERT(OK());
210 }
211 
212 void
214  PPL_ASSERT(new_size <= impl.capacity);
215  PPL_ASSERT(size() <= new_size && new_size <= max_size());
216  while (impl.size != new_size) {
217  new(&impl.vec[impl.size]) Coefficient();
218  ++impl.size;
219  }
220  PPL_ASSERT(size() == new_size);
221  PPL_ASSERT(OK());
222 }
223 
224 void
226  PPL_ASSERT(new_size <= size());
227  // Since ~Coefficient() does not throw exceptions, nothing here does.
228 
229  // We assume construction was done "forward".
230  // We thus perform destruction "backward".
231  while (impl.size != new_size) {
232  --impl.size;
233  impl.vec[impl.size].~Coefficient();
234  }
235 
236  PPL_ASSERT(size() == new_size);
237  PPL_ASSERT(OK());
238 }
239 
241  : impl() {
242 
243  init(row);
244 
245  PPL_ASSERT(size() == row.size());
246  PPL_ASSERT(OK());
247 }
248 
249 void
251  impl.capacity = row.size();
252  impl.vec = impl.coeff_allocator.allocate(impl.capacity);
253  Sparse_Row::const_iterator itr = row.begin();
254  Sparse_Row::const_iterator itr_end = row.end();
255  while (impl.size != impl.capacity) {
256  // Constructs (*this)[impl.size] with row[impl.size].
257  if (itr != itr_end && itr.index() == impl.size) {
258  new(&impl.vec[impl.size]) Coefficient(*itr);
259  ++itr;
260  }
261  else {
262  new(&impl.vec[impl.size]) Coefficient();
263  }
264  ++impl.size;
265  }
266  PPL_ASSERT(size() == row.size());
267  PPL_ASSERT(OK());
268 }
269 
272  if (size() > row.size()) {
273  // TODO: If the shrink() is modified to reallocate a smaller chunk,
274  // this can be optimized.
275  shrink(row.size());
276  Sparse_Row::const_iterator itr = row.begin();
277  Sparse_Row::const_iterator itr_end = row.end();
278  for (dimension_type i = 0; i < impl.size; ++i) {
279  // Computes (*this)[impl.size] = row[impl.size].
280  if (itr != itr_end && itr.index() == i) {
281  impl.vec[impl.size] = *itr;
282  ++itr;
283  }
284  else {
285  impl.vec[impl.size] = Coefficient_zero();
286  }
287  }
288  }
289  else {
290  if (capacity() >= row.size()) {
291  // size() <= row.size() <= capacity().
292  Sparse_Row::const_iterator itr = row.begin();
293  Sparse_Row::const_iterator itr_end = row.end();
294  for (dimension_type i = 0; i < impl.size; ++i) {
295  // The following code is equivalent to (*this)[i] = row[i].
296  if (itr != itr_end && itr.index() == impl.size) {
297  new(&impl.vec[impl.size]) Coefficient(*itr);
298  ++itr;
299  }
300  else {
301  new(&impl.vec[impl.size]) Coefficient();
302  }
303  }
304  // Construct the additional elements.
305  for ( ; impl.size != row.size(); ++impl.size) {
306  // Constructs (*this)[impl.size] with row[impl.size].
307  if (itr != itr_end && itr.index() == impl.size) {
308  new(&impl.vec[impl.size]) Coefficient(*itr);
309  ++itr;
310  }
311  else {
312  new(&impl.vec[impl.size]) Coefficient();
313  }
314  }
315  }
316  else {
317  // Reallocation is required.
318  destroy();
319  init(row);
320  }
321  }
322  PPL_ASSERT(size() == row.size());
323  PPL_ASSERT(OK());
324 
325  return *this;
326 }
327 
328 void
330  Dense_Row& x = *this;
331  // Compute the GCD of all the coefficients.
332  const dimension_type sz = size();
333  dimension_type i = sz;
335  while (i > 0) {
336  Coefficient_traits::const_reference x_i = x[--i];
337  if (const int x_i_sign = sgn(x_i)) {
338  gcd = x_i;
339  if (x_i_sign < 0) {
340  neg_assign(gcd);
341  }
342  goto compute_gcd;
343  }
344  }
345  // We reach this point only if all the coefficients were zero.
346  return;
347 
348 compute_gcd:
349  if (gcd == 1) {
350  return;
351  }
352  while (i > 0) {
353  Coefficient_traits::const_reference x_i = x[--i];
354  if (x_i != 0) {
355  // Note: we use the ternary version instead of a more concise
356  // gcd_assign(gcd, x_i) to take advantage of the fact that
357  // `gcd' will decrease very rapidly (see D. Knuth, The Art of
358  // Computer Programming, second edition, Section 4.5.2,
359  // Algorithm C, and the discussion following it). Our
360  // implementation of gcd_assign(x, y, z) for checked numbers is
361  // optimized for the case where `z' is smaller than `y', so that
362  // on checked numbers we gain. On the other hand, for the
363  // implementation of gcd_assign(x, y, z) on GMP's unbounded
364  // integers we cannot make any assumption, so here we draw.
365  // Overall, we win.
366  gcd_assign(gcd, x_i, gcd);
367  if (gcd == 1) {
368  return;
369  }
370  }
371  }
372  // Divide the coefficients by the GCD.
373  for (dimension_type j = sz; j-- > 0; ) {
374  Coefficient& x_j = x[j];
375  exact_div_assign(x_j, x_j, gcd);
376  }
377 }
378 
379 void
381  PPL_ASSERT(first <= last);
382  PPL_ASSERT(last <= size());
383  for (dimension_type i = first; i < last; ++i) {
384  (*this)[i] = 0;
385  }
386 }
387 
388 void
390  Coefficient_traits::const_reference coeff1,
391  Coefficient_traits::const_reference coeff2) {
392  Dense_Row& x = *this;
393  PPL_ASSERT(x.size() == y.size());
394 
395  x.linear_combine(y, coeff1, coeff2, 0, x.size());
396 }
397 
398 void
400  Coefficient_traits::const_reference coeff1,
401  Coefficient_traits::const_reference coeff2,
402  dimension_type start, dimension_type end) {
403  Dense_Row& x = *this;
404  PPL_ASSERT(start <= end);
405  PPL_ASSERT(end <= x.size());
406  PPL_ASSERT(end <= y.size());
407  PPL_ASSERT(coeff1 != 0);
408  PPL_ASSERT(coeff2 != 0);
409 
410  // If coeff1 is 1 and/or coeff2 is 1 or -1, we use an optimized
411  // implementation.
412 
413  if (coeff1 == 1) {
414  if (coeff2 == 1) {
415  // Optimized implementation for coeff1==1, coeff2==1.
416  for (dimension_type i = start; i < end; ++i) {
417  if (y[i] != 0) {
418  x[i] += y[i];
419  }
420  }
421  return;
422  }
423  if (coeff2 == -1) {
424  // Optimized implementation for coeff1==1, coeff2==-1.
425  for (dimension_type i = start; i < end; ++i) {
426  if (y[i] != 0) {
427  x[i] -= y[i];
428  }
429  }
430  return;
431  }
432  // Optimized implementation for coeff1==1.
433  for (dimension_type i = start; i < end; ++i) {
434  Coefficient& x_i = x[i];
435  // The test against 0 gives rise to a consistent speed up: see
436  // http://www.cs.unipr.it/pipermail/ppl-devel/2009-February/014000.html
437  Coefficient_traits::const_reference y_i = y[i];
438  if (y_i != 0) {
439  add_mul_assign(x_i, y_i, coeff2);
440  }
441  }
442  return;
443  }
444 
445  if (coeff2 == 1) {
446  // Optimized implementation for coeff2==1.
447  for (dimension_type i = start; i < end; ++i) {
448  x[i] *= coeff1;
449  if (y[i] != 0) {
450  x[i] += y[i];
451  }
452  }
453  return;
454  }
455  if (coeff2 == -1) {
456  // Optimized implementation for coeff2==-1.
457  for (dimension_type i = start; i < end; ++i) {
458  x[i] *= coeff1;
459  if (y[i] != 0) {
460  x[i] -= y[i];
461  }
462  }
463  return;
464  }
465  // General case.
466  for (dimension_type i = start; i < end; ++i) {
467  Coefficient& x_i = x[i];
468  x[i] *= coeff1;
469  // The test against 0 gives rise to a consistent speed up: see
470  // http://www.cs.unipr.it/pipermail/ppl-devel/2009-February/014000.html
471  Coefficient_traits::const_reference y_i = y[i];
472  if (y_i != 0) {
473  add_mul_assign(x_i, y_i, coeff2);
474  }
475  }
476 }
477 
478 void
479 PPL::Dense_Row::ascii_dump(std::ostream& s) const {
480  const Dense_Row& x = *this;
481  const dimension_type x_size = x.size();
482  s << "size " << x_size << " ";
483  for (dimension_type i = 0; i < x_size; ++i) {
484  s << x[i] << ' ';
485  }
486  s << "\n";
487 }
488 
490 
491 bool
492 PPL::Dense_Row::ascii_load(std::istream& s) {
493  std::string str;
494  if (!(s >> str) || str != "size") {
495  return false;
496  }
497  dimension_type new_size;
498  if (!(s >> new_size)) {
499  return false;
500  }
501 
502  resize(new_size);
503 
504  for (dimension_type col = 0; col < new_size; ++col) {
505  if (!(s >> (*this)[col])) {
506  return false;
507  }
508  }
509 
510  return true;
511 }
512 
515  return external_memory_in_bytes();
516 }
517 
520  memory_size_type n = impl.capacity * sizeof(Coefficient);
521  for (dimension_type i = size(); i-- > 0; ) {
522  n += PPL::external_memory_in_bytes(impl.vec[i]);
523  }
524  return n;
525 }
526 
527 bool
529 #ifndef NDEBUG
530  using std::endl;
531  using std::cerr;
532 #endif
533 
534  bool is_broken = false;
535 
536  if (impl.capacity > max_size()) {
537 #ifndef NDEBUG
538  cerr << "Dense_Row capacity exceeds the maximum allowed size:" << endl
539  << "is " << impl.capacity
540  << ", should be less than or equal to " << max_size() << "."
541  << endl;
542 #endif
543  is_broken = true;
544  }
545 
546  if (size() > max_size()) {
547 #ifndef NDEBUG
548  cerr << "Dense_Row size exceeds the maximum allowed size:" << endl
549  << "is " << size()
550  << ", should be less than or equal to " << max_size() << "." << endl;
551 #endif
552  is_broken = true;
553  }
554 
555  if (impl.capacity < size()) {
556 #ifndef NDEBUG
557  cerr << "Dense_Row is completely broken: capacity is " << impl.capacity
558  << ", size is " << size() << "." << endl;
559 #endif
560  is_broken = true;
561  }
562 
563  if (capacity() == 0) {
564  if (impl.vec != 0) {
565  is_broken = true;
566  }
567  }
568  else {
569  if (impl.vec == 0) {
570  is_broken = true;
571  }
572  }
573 
574  return !is_broken;
575 }
576 
577 bool
578 PPL::Dense_Row::OK(const dimension_type row_size) const {
579 #ifndef NDEBUG
580  using std::endl;
581  using std::cerr;
582 #endif
583 
584  bool is_broken = !OK();
585 
586  // Check the declared size.
587  if (size() != row_size) {
588 #ifndef NDEBUG
589  cerr << "Dense_Row size mismatch: is " << size()
590  << ", should be " << row_size << "." << endl;
591 #endif
592  is_broken = true;
593  }
594  return !is_broken;
595 }
596 
598 bool
599 PPL::operator==(const Dense_Row& x, const Dense_Row& y) {
600  const dimension_type x_size = x.size();
601  const dimension_type y_size = y.size();
602 
603  if (x_size != y_size) {
604  return false;
605  }
606 
607  for (dimension_type i = x_size; i-- > 0; ) {
608  if (x[i] != y[i]) {
609  return false;
610  }
611  }
612 
613  return true;
614 }
dimension_type index() const
Returns the index of the element pointed to by *this.
void swap(CO_Tree &x, CO_Tree &y)
A finite sequence of coefficients.
memory_size_type external_memory_in_bytes() const
Returns a lower bound to the size in bytes of the memory managed by *this.
Definition: Dense_Row.cc:519
Dense_Row & operator=(const Dense_Row &y)
Assignment operator.
size_t dimension_type
An unsigned integral type for representing space dimensions.
void normalize()
Normalizes the modulo of coefficients so that they are mutually prime.
Definition: Dense_Row.cc:329
dimension_type size() const
Returns the size of the row.
#define PPL_DIRTY_TEMP_COEFFICIENT(id)
Declare a local variable named id, of type Coefficient, and containing an unknown initial value...
std::allocator< Coefficient > coeff_allocator
The allocator used to allocate/deallocate vec.
void add_mul_assign(GMP_Integer &x, const GMP_Integer &y, const GMP_Integer &z)
void linear_combine(const Dense_Row &y, Coefficient_traits::const_reference coeff1, Coefficient_traits::const_reference coeff2)
Definition: Dense_Row.cc:389
Dense_Row()
Constructs an empty row.
A finite sparse sequence of coefficients.
The standard C++ namespace.
const iterator & end()
Returns an iterator that points after the last stored element.
void exact_div_assign(Checked_Number< T, Policy > &x, const Checked_Number< T, Policy > &y, const Checked_Number< T, Policy > &z)
void ascii_dump() const
Writes to std::cerr an ASCII representation of *this.
dimension_type compute_capacity(dimension_type requested_size, dimension_type maximum_size)
Speculative allocation function.
dimension_type size() const
Gives the number of coefficients currently in use.
void add_zeroes_and_shift(dimension_type n, dimension_type i)
Adds n zeroes before index i.
Definition: Dense_Row.cc:140
Enable_If< Is_Native< T >::value, memory_size_type >::type external_memory_in_bytes(const T &)
For native types, returns the size in bytes of the memory managed by the type of the (unused) paramet...
#define PPL_OUTPUT_DEFINITIONS_ASCII_ONLY(class_name)
void clear()
Resets all the elements of this row.
Definition: Dense_Row.cc:133
Enable_If< Is_Native_Or_Checked< T >::value, bool >::type ascii_load(std::istream &s, T &t)
PPL_COEFFICIENT_TYPE Coefficient
An alias for easily naming the type of PPL coefficients.
void expand_within_capacity(dimension_type new_size)
Expands the row to size new_size.
Definition: Dense_Row.cc:213
void init(const Sparse_Row &row)
Definition: Dense_Row.cc:250
void shrink(dimension_type new_size)
Shrinks the row by erasing elements at the end.
Definition: Dense_Row.cc:225
bool OK() const
Checks if all the invariants are satisfied.
Definition: Dense_Row.cc:528
void neg_assign(GMP_Integer &x)
Coefficient_traits::const_reference Coefficient_zero()
Returns a const reference to a Coefficient with value 0.
The entire library is confined to this namespace.
Definition: version.hh:61
A const iterator on the tree elements, ordered by key.
iterator lower_bound(dimension_type i)
Lower bound of index i.
iterator begin()
Returns an iterator that points at the first stored element.
void resize(dimension_type sz)
Resizes the row to sz.
Definition: Dense_Row.cc:45
void gcd_assign(GMP_Integer &x, const GMP_Integer &y, const GMP_Integer &z)
dimension_type capacity
The capacity of the row.
int sgn(Boundary_Type type, const T &x, const Info &info)
bool operator==(const Box< ITV > &x, const Box< ITV > &y)
size_t memory_size_type
An unsigned integral type for representing memory size in bytes.