summaryrefslogtreecommitdiff
path: root/src/Bit_Matrix.cc
blob: 071e63ce69d61d7527876bebf980ae69e03f74d6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
/* Bit_Matrix class implementation (non-inline functions).
   Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it>
   Copyright (C) 2010-2011 BUGSENG srl (http://bugseng.com)

This file is part of the Parma Polyhedra Library (PPL).

The PPL is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3 of the License, or (at your
option) any later version.

The PPL is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA.

For the most up-to-date information see the Parma Polyhedra Library
site: http://www.cs.unipr.it/ppl/ . */

#include <ppl-config.h>

#include "Bit_Matrix.defs.hh"
#include "globals.defs.hh"
#include <iostream>
#include <string>
#include <climits>

#include "swapping_sort.icc"

namespace PPL = Parma_Polyhedra_Library;

PPL::Bit_Matrix&
PPL::Bit_Matrix::operator=(const Bit_Matrix& y){
  rows = y.rows;
  row_size = y.row_size;
  PPL_ASSERT(OK());
  return *this;
}

void
PPL::Bit_Matrix::sort_rows() {
  const dimension_type num_elems = rows.size();
  if (num_elems < 2)
    return;

  // Build the function objects implementing indirect sort comparison,
  // indirect unique comparison and indirect swap operation.
  typedef std::vector<Bit_Row> Cont;
  Indirect_Sort_Compare<Cont, Bit_Row_Less_Than> sort_cmp(rows);
  Indirect_Unique_Compare<Cont> unique_cmp(rows);
  Indirect_Swapper<Cont> swapper(rows);

  const dimension_type num_duplicates
    = indirect_sort_and_unique(num_elems, sort_cmp, unique_cmp, swapper);

  if (num_duplicates > 0)
    rows.erase(rows.end() - num_duplicates, rows.end());

  PPL_ASSERT(OK());
}

void
PPL::Bit_Matrix::add_recycled_row(Bit_Row& row) {
  const dimension_type new_rows_size = rows.size() + 1;
  if (rows.capacity() < new_rows_size) {
    // Reallocation will take place.
    std::vector<Bit_Row> new_rows;
    new_rows.reserve(compute_capacity(new_rows_size, max_num_rows()));
    new_rows.insert(new_rows.end(), new_rows_size, Bit_Row());
    // Put the new row in place.
    dimension_type i = new_rows_size-1;
    new_rows[i].swap(row);
    // Steal the old rows.
    while (i-- > 0)
      new_rows[i].swap(rows[i]);
    // Put the new rows into place.
    std::swap(rows, new_rows);
  }
  else
    // Reallocation will NOT take place: append an empty row
    // and swap it with the new row.
    rows.insert(rows.end(), Bit_Row())->swap(row);
  PPL_ASSERT(OK());
}

void
PPL::Bit_Matrix::transpose() {
  const Bit_Matrix& x = *this;
  const dimension_type nrows = num_rows();
  const dimension_type ncols = num_columns();
  Bit_Matrix tmp(ncols, nrows);
  for (dimension_type i = nrows; i-- > 0; )
    for (unsigned long j = x[i].last(); j != ULONG_MAX; j = x[i].prev(j))
      tmp[j].set(i);
  swap(tmp);
  PPL_ASSERT(OK());
}

void
PPL::Bit_Matrix::transpose_assign(const Bit_Matrix& y) {
  const dimension_type y_nrows = y.num_rows();
  const dimension_type y_ncols = y.num_columns();
  Bit_Matrix tmp(y_ncols, y_nrows);
  for (dimension_type i = y_nrows; i-- > 0; )
    for (unsigned long j = y[i].last(); j != ULONG_MAX; j = y[i].prev(j))
      tmp[j].set(i);
  swap(tmp);
  PPL_ASSERT(OK());
}

void
PPL::Bit_Matrix::resize(dimension_type new_n_rows,
		       dimension_type new_n_columns) {
  PPL_ASSERT(OK());
  const dimension_type old_num_rows = num_rows();
  if (new_n_columns < row_size) {
    const dimension_type num_preserved_rows
      = std::min(old_num_rows, new_n_rows);
    Bit_Matrix& x = *this;
    for (dimension_type i = num_preserved_rows; i-- > 0; )
      x[i].clear_from(new_n_columns);
  }
  row_size = new_n_columns;
  if (new_n_rows > old_num_rows) {
    if (rows.capacity() < new_n_rows) {
      // Reallocation will take place.
      std::vector<Bit_Row> new_rows;
      new_rows.reserve(compute_capacity(new_n_rows, max_num_rows()));
      new_rows.insert(new_rows.end(), new_n_rows, Bit_Row());
      // Steal the old rows.
      for (dimension_type i = old_num_rows; i-- > 0; )
	new_rows[i].swap(rows[i]);
      // Put the new vector into place.
      std::swap(rows, new_rows);
    }
    else
      // Reallocation will NOT take place.
      rows.insert(rows.end(), new_n_rows - old_num_rows, Bit_Row());
  }
  else if (new_n_rows < old_num_rows)
    // Drop some rows.
    rows.erase(rows.begin() + new_n_rows, rows.end());

  PPL_ASSERT(OK());
}

void
PPL::Bit_Matrix::ascii_dump(std::ostream& s) const {
  const Bit_Matrix& x = *this;
  const char separator = ' ';
  s << num_rows() << separator << 'x' << separator
    << num_columns() << "\n";
  for (dimension_type i = 0; i < num_rows(); ++i) {
    for (dimension_type j = 0; j < num_columns(); ++j)
      s << x[i][j] << separator;
    s << "\n";
  }
}

PPL_OUTPUT_DEFINITIONS_ASCII_ONLY(Bit_Matrix)

bool
PPL::Bit_Matrix::ascii_load(std::istream& s) {
  Bit_Matrix& x = *this;
  dimension_type nrows;
  dimension_type ncols;
  std::string str;
  if (!(s >> nrows))
    return false;
  if (!(s >> str) || str != "x")
    return false;
  if (!(s >> ncols))
    return false;
  resize(nrows, ncols);

  for (dimension_type i = 0; i < num_rows(); ++i)
    for (dimension_type j = 0; j < num_columns(); ++j) {
      int bit;
      if (!(s >> bit))
	return false;
      if (bit)
	x[i].set(j);
      else
	x[i].clear(j);
    }

  // Check invariants.
  PPL_ASSERT(OK());
  return true;
}

PPL::memory_size_type
PPL::Bit_Matrix::external_memory_in_bytes() const {
  memory_size_type n = rows.capacity() * sizeof(Row);
  for (dimension_type i = num_rows(); i-- > 0; )
    n += rows[i].external_memory_in_bytes();
  return n;
}

bool
PPL::Bit_Matrix::OK() const {
#ifndef NDEBUG
  using std::endl;
  using std::cerr;
#endif

  const Bit_Matrix& x = *this;
  for (dimension_type i = num_rows(); i-- > 1; ) {
    const Bit_Row& row = x[i];
    if (!row.OK())
      return false;
    else if (row.last() != ULONG_MAX && row.last() >= row_size) {
#ifndef NDEBUG
      cerr << "Bit_Matrix[" << i << "] is a row with too many bits!"
	   << endl
	   << "(row_size == " << row_size
	   << ", row.last() == " << row.last() << ")"
	   << endl;
#endif
      return false;
    }
  }
  return true;
}

#ifndef NDEBUG
bool
PPL::Bit_Matrix::check_sorted() const {
  const Bit_Matrix& x = *this;
  for (dimension_type i = num_rows(); i-- > 1; )
    if (compare(x[i-1], x[i]) > 0)
      return false;
  return true;
}
#endif

/*! \relates Parma_Polyhedra_Library::Bit_Matrix */
bool
PPL::operator==(const Bit_Matrix& x, const Bit_Matrix& y) {
  const dimension_type x_num_rows = x.num_rows();
  if (x_num_rows != y.num_rows()
      || x.num_columns() != y.num_columns())
    return false;
  for (dimension_type i = x_num_rows; i-- > 0; )
    if (x[i] != y[i])
      return false;
  return true;
}