1 /* Bit_Matrix 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 "Bit_Matrix_defs.hh"
26 #include "Dense_Row_defs.hh"
27 #include "globals_defs.hh"
28 #include "swapping_sort_templates.hh"
29 #include "C_Integer.hh"
30 #include <iostream>
31 #include <string>
32 
33 namespace PPL = Parma_Polyhedra_Library;
34 
35 PPL::Bit_Matrix&
operator =(const Bit_Matrix & y)36 PPL::Bit_Matrix::operator=(const Bit_Matrix& y) {
37   rows = y.rows;
38   row_size = y.row_size;
39   PPL_ASSERT(OK());
40   return *this;
41 }
42 
43 void
sort_rows()44 PPL::Bit_Matrix::sort_rows() {
45   const dimension_type num_elems = rows.size();
46   if (num_elems < 2) {
47     return;
48   }
49   // Build the function objects implementing indirect sort comparison,
50   // indirect unique comparison and indirect swap operation.
51   using namespace Implementation;
52   typedef std::vector<Bit_Row> Cont;
53   typedef Indirect_Sort_Compare<Cont, Bit_Row_Less_Than> Sort_Compare;
54   typedef Indirect_Unique_Compare<Cont> Unique_Compare;
55   typedef Indirect_Swapper<Cont> Swapper;
56   const dimension_type num_duplicates
57     = indirect_sort_and_unique(num_elems,
58                                Sort_Compare(rows),
59                                Unique_Compare(rows),
60                                Swapper(rows));
61 
62   if (num_duplicates > 0) {
63     typedef Cont::iterator Iter;
64     typedef std::iterator_traits<Iter>::difference_type diff_t;
65     Iter last = rows.end();
66     Iter first = last - static_cast<diff_t>(num_duplicates);
67     rows.erase(first, last);
68   }
69 
70   PPL_ASSERT(OK());
71 }
72 
73 void
add_recycled_row(Bit_Row & row)74 PPL::Bit_Matrix::add_recycled_row(Bit_Row& row) {
75   const dimension_type new_rows_size = rows.size() + 1;
76   if (rows.capacity() < new_rows_size) {
77     // Reallocation will take place.
78     std::vector<Bit_Row> new_rows;
79     new_rows.reserve(compute_capacity(new_rows_size, max_num_rows()));
80     new_rows.insert(new_rows.end(), new_rows_size, Bit_Row());
81     // Put the new row in place.
82     dimension_type i = new_rows_size-1;
83     new_rows[i].m_swap(row);
84     // Steal the old rows.
85     while (i-- > 0) {
86       new_rows[i].m_swap(rows[i]);
87     }
88     // Put the new rows into place.
89     using std::swap;
90     swap(rows, new_rows);
91   }
92   else {
93     // Reallocation will NOT take place: append an empty row
94     // and swap it with the new row.
95     rows.insert(rows.end(), Bit_Row())->m_swap(row);
96   }
97   PPL_ASSERT(OK());
98 }
99 
100 void
transpose()101 PPL::Bit_Matrix::transpose() {
102   const Bit_Matrix& x = *this;
103   const dimension_type nrows = num_rows();
104   const dimension_type ncols = num_columns();
105   Bit_Matrix tmp(ncols, nrows);
106   for (dimension_type i = nrows; i-- > 0; ) {
107     for (unsigned long j = x[i].last();
108          j != C_Integer<unsigned long>::max; j = x[i].prev(j)) {
109       tmp[j].set(i);
110     }
111   }
112   m_swap(tmp);
113   PPL_ASSERT(OK());
114 }
115 
116 void
transpose_assign(const Bit_Matrix & y)117 PPL::Bit_Matrix::transpose_assign(const Bit_Matrix& y) {
118   const dimension_type y_num_rows = y.num_rows();
119   const dimension_type y_num_columns = y.num_columns();
120   Bit_Matrix tmp(y_num_columns, y_num_rows);
121   for (dimension_type i = y_num_rows; i-- > 0; ) {
122     for (unsigned long j = y[i].last();
123          j != C_Integer<unsigned long>::max; j = y[i].prev(j)) {
124       tmp[j].set(i);
125     }
126   }
127   m_swap(tmp);
128   PPL_ASSERT(OK());
129 }
130 
131 void
resize(dimension_type new_n_rows,dimension_type new_n_columns)132 PPL::Bit_Matrix::resize(dimension_type new_n_rows,
133                         dimension_type new_n_columns) {
134   PPL_ASSERT(OK());
135   const dimension_type old_num_rows = num_rows();
136   if (new_n_columns < row_size) {
137     const dimension_type num_preserved_rows
138       = std::min(old_num_rows, new_n_rows);
139     Bit_Matrix& x = *this;
140     for (dimension_type i = num_preserved_rows; i-- > 0; ) {
141       x[i].clear_from(new_n_columns);
142     }
143   }
144   row_size = new_n_columns;
145   if (new_n_rows > old_num_rows) {
146     if (rows.capacity() < new_n_rows) {
147       // Reallocation will take place.
148       std::vector<Bit_Row> new_rows;
149       new_rows.reserve(compute_capacity(new_n_rows, max_num_rows()));
150       new_rows.insert(new_rows.end(), new_n_rows, Bit_Row());
151       // Steal the old rows.
152       for (dimension_type i = old_num_rows; i-- > 0; ) {
153         new_rows[i].m_swap(rows[i]);
154       }
155       // Put the new vector into place.
156       using std::swap;
157       swap(rows, new_rows);
158     }
159     else {
160       // Reallocation will NOT take place.
161       rows.insert(rows.end(), new_n_rows - old_num_rows, Bit_Row());
162     }
163   }
164   else if (new_n_rows < old_num_rows) {
165     // Drop some rows.
166     rows.resize(new_n_rows);
167   }
168 
169   PPL_ASSERT(OK());
170 }
171 
172 void
ascii_dump(std::ostream & s) const173 PPL::Bit_Matrix::ascii_dump(std::ostream& s) const {
174   const Bit_Matrix& x = *this;
175   const char separator = ' ';
176   s << num_rows() << separator << 'x' << separator
177     << num_columns() << "\n";
178   for (dimension_type i = 0; i < num_rows(); ++i) {
179     for (dimension_type j = 0; j < num_columns(); ++j) {
180       s << x[i][j] << separator;
181     }
182     s << "\n";
183   }
184 }
185 
PPL_OUTPUT_DEFINITIONS_ASCII_ONLY(Bit_Matrix)186 PPL_OUTPUT_DEFINITIONS_ASCII_ONLY(Bit_Matrix)
187 
188 bool
189 PPL::Bit_Matrix::ascii_load(std::istream& s) {
190   Bit_Matrix& x = *this;
191   dimension_type nrows;
192   dimension_type ncols;
193   std::string str;
194   if (!(s >> nrows)) {
195     return false;
196   }
197   if (!(s >> str) || str != "x") {
198     return false;
199   }
200   if (!(s >> ncols)) {
201     return false;
202   }
203   resize(nrows, ncols);
204 
205   for (dimension_type i = 0; i < num_rows(); ++i) {
206     for (dimension_type j = 0; j < num_columns(); ++j) {
207       int bit;
208       if (!(s >> bit)) {
209         return false;
210       }
211       if (bit != 0) {
212         x[i].set(j);
213       }
214       else {
215         x[i].clear(j);
216       }
217     }
218   }
219   // Check invariants.
220   PPL_ASSERT(OK());
221   return true;
222 }
223 
224 PPL::memory_size_type
external_memory_in_bytes() const225 PPL::Bit_Matrix::external_memory_in_bytes() const {
226   memory_size_type n = rows.capacity() * sizeof(Dense_Row);
227   for (dimension_type i = num_rows(); i-- > 0; ) {
228     n += rows[i].external_memory_in_bytes();
229   }
230   return n;
231 }
232 
233 bool
OK() const234 PPL::Bit_Matrix::OK() const {
235 #ifndef NDEBUG
236   using std::endl;
237   using std::cerr;
238 #endif
239 
240   const Bit_Matrix& x = *this;
241   for (dimension_type i = num_rows(); i-- > 0; ) {
242     const Bit_Row& row = x[i];
243     if (!row.OK()) {
244       return false;
245     }
246     else if (row.last() != C_Integer<unsigned long>::max
247              && row.last() >= row_size) {
248 #ifndef NDEBUG
249       cerr << "Bit_Matrix[" << i << "] is a row with too many bits!"
250            << endl
251            << "(row_size == " << row_size
252            << ", row.last() == " << row.last() << ")"
253            << endl;
254 #endif
255       return false;
256     }
257   }
258   return true;
259 }
260 
261 #ifndef NDEBUG
262 bool
check_sorted() const263 PPL::Bit_Matrix::check_sorted() const {
264   const Bit_Matrix& x = *this;
265   for (dimension_type i = num_rows(); i-- > 1; ) {
266     if (compare(x[i-1], x[i]) > 0) {
267       return false;
268     }
269   }
270   return true;
271 }
272 #endif
273 
274 /*! \relates Parma_Polyhedra_Library::Bit_Matrix */
275 bool
operator ==(const Bit_Matrix & x,const Bit_Matrix & y)276 PPL::operator==(const Bit_Matrix& x, const Bit_Matrix& y) {
277   const dimension_type x_num_rows = x.num_rows();
278   if (x_num_rows != y.num_rows()
279       || x.num_columns() != y.num_columns()) {
280     return false;
281   }
282   for (dimension_type i = x_num_rows; i-- > 0; ) {
283     if (x[i] != y[i]) {
284       return false;
285     }
286   }
287   return true;
288 }
289