Painless
A framework to ease parallelization of sequential CDCL SAT solvers
Loading...
Searching...
No Matches
vector2D.hpp
1#pragma once
2
3#include <algorithm>
4#include <cassert>
5#include <initializer_list>
6#include <iterator>
7#include <stdexcept>
8#include <type_traits>
9#include <unordered_map>
10#include <vector>
11
12typedef unsigned int row_size_t;
13typedef unsigned int row_id_t;
14typedef unsigned long int data_size_t;
15
16namespace painless {
17// ==================================================================SZSPAN========================================================================
18
25template<typename T>
27{
28 static_assert(std::is_arithmetic<T>::value, "skipzero_span: Template parameter T must be an arithmetic type");
29
30 public:
31 // Custom iterator that skips zero elements, add a m_ptr attribute for midway starting points ?
33 {
34 public:
35 using iterator_category = std::contiguous_iterator_tag;
36 using difference_type = std::ptrdiff_t;
37 using value_type = T;
38 using pointer = T*;
39 using reference = T&;
40
41 Iterator(pointer begin, pointer end)
42 : m_ptr(begin)
43 , m_begin(begin)
44 , m_end(end)
45 {
46 skip_zeros();
47 }
48
49 reference operator*() const { return *m_ptr; }
50 pointer operator->() { return m_ptr; }
51
52 // Prefix increment
53 Iterator& operator++()
54 {
55 ++m_ptr;
56 skip_zeros();
57 return *this;
58 }
59
60 // Postfix increment
61 Iterator operator++(int)
62 {
63 Iterator tmp = *this;
64 ++(*this);
65 return tmp;
66 }
67
68 // Prefix decrement
69 Iterator& operator--()
70 {
71 --m_ptr;
72 skip_zeros_backward();
73 return *this;
74 }
75
76 // Postfix decrement
77 Iterator operator--(int)
78 {
79 Iterator tmp = *this;
80 --(*this);
81 return tmp;
82 }
83
84 // Difference between two iterators, it counts the zeros !
85 friend difference_type operator-(const Iterator& a, const Iterator& b) { return a.m_ptr - b.m_ptr; }
86 friend bool operator==(const Iterator& a, const Iterator& b) { return a.m_ptr == b.m_ptr; }
87 friend bool operator!=(const Iterator& a, const Iterator& b) { return a.m_ptr != b.m_ptr; }
88
89 private:
90 void skip_zeros()
91 {
92 while (m_ptr != m_end && *m_ptr == 0) {
93 ++m_ptr;
94 }
95 }
96
97 void skip_zeros_backward()
98 {
99 while (m_ptr != m_begin && *m_ptr == 0) {
100 --m_ptr;
101 }
102 }
103
104 pointer m_ptr;
105 const pointer m_begin;
106 const pointer m_end;
107 };
108
109 skipzero_span(T* begin, T* end, row_size_t size)
110 : m_begin(begin)
111 , m_end(end)
112 , m_size(size)
113 {
114 }
115 skipzero_span(std::vector<T>& vec)
116 : m_begin(vec.data())
117 , m_end(vec.data() + vec.size())
118 , m_size(vec.size())
119 {
120 for (T number : vec) {
121 if (!number)
122 m_size--;
123 }
124 }
125
126 Iterator begin() const { return Iterator(m_begin, m_end); }
127 Iterator end() const { return Iterator(m_end, m_end); }
128
129 row_size_t capacity() const { return m_end - m_begin; }
130 row_size_t size() const { return this->m_size; }
131
132 T* data() { return m_begin; }
133 const T* data() const { return m_begin; }
134
135 T& front() { return *this->begin(); }
136 const T& front() const { return *this->begin(); }
137
138 T& back() { return *(--this->end()); }
139 const T& back() const { return *(--this->end()); }
140
141 private:
142 T* m_begin;
143 T* m_end;
144 row_size_t m_size;
145};
146
147// =================================================================2DVECTOR=======================================================================
148#ifdef NDEBUG
149#define CHECK_BOUNDS(i) ((void)0)
150#else
151#define CHECK_BOUNDS(i) \
152 do { \
153 if (!ROW_SIZE(i)) { \
154 throw std::invalid_argument("Clause at given index is deleted"); \
155 } \
156 if (i >= capacities.size() || i >= indexes.size()) { \
157 throw std::out_of_range("Index out of range"); \
158 } \
159 } while (false)
160#endif
161
162#define ROW_SIZE(i) this->data[indexes[i]]
163#define ROW_BEGIN(i) this->indexes[i] + 1
164#define ROW_CAP(i) this->capacities[i]
165#define ROW_END(i) ROW_BEGIN(i) + ROW_CAP(i)
166
173template<typename T>
175{
176 static_assert(std::is_arithmetic<T>::value, "vector2D: Template parameter T must be an arithmetic type");
177
178 public:
184 inline skipzero_span<T> operator[](row_id_t id);
185
191 inline skipzero_span<const T> operator[](row_id_t id) const;
192
198 inline T* begin(row_id_t id);
199
205 inline T* end(row_id_t id);
206
212 inline const T* begin(row_id_t id) const;
213
219 inline const T* end(row_id_t id) const;
220
226 inline row_size_t getRowSize(row_id_t id) const;
227
232 inline row_size_t getRowsCount() const { return this->indexes.size(); };
233
238 void push_row(const std::vector<int>& row);
239
244 void emplace_row(std::initializer_list<int> row);
245
250 inline void delete_row(row_id_t id);
251
258 bool delete_element(row_id_t rowId, row_size_t offset);
259
263 void cleanup();
264
265 private:
266 std::vector<T> data;
267 std::vector<row_size_t> capacities;
268 std::vector<data_size_t> indexes;
269 std::unordered_map<row_size_t, data_size_t> freeRows;
270};
271
272// ============================================================2DVECTORImplementation=================================================================
273
274// Getters
275// =======
276
277template<typename T>
278inline skipzero_span<T>
280{
281 CHECK_BOUNDS(id);
282 return skipzero_span<T>(begin(id), end(id), ROW_SIZE(id));
283}
284
285template<typename T>
287vector2D<T>::operator[](row_id_t id) const
288{
289 CHECK_BOUNDS(id);
290 return skipzero_span<const T>(begin(id), end(id), ROW_SIZE(id));
291}
292
293template<typename T>
294inline T*
296{
297 CHECK_BOUNDS(id);
298 return (data.data() + ROW_BEGIN(id)); /* jumping the size cell */
299}
300
301template<typename T>
302inline T*
304{
305 CHECK_BOUNDS(id);
306 /* This iterator is not incrementable */
307 return (data.data() + ROW_END(id));
308}
309
310template<typename T>
311inline const T*
312vector2D<T>::begin(row_id_t id) const
313{
314 CHECK_BOUNDS(id);
315 return (data.data() + ROW_BEGIN(id)); /* jumping the size cell */
316}
317
318template<typename T>
319inline const T*
320vector2D<T>::end(row_id_t id) const
321{
322 CHECK_BOUNDS(id);
323 /* This iterator is not incrementable */
324 return (data.data() + ROW_END(id));
325}
326
327template<typename T>
328inline row_size_t
329vector2D<T>::getRowSize(row_id_t id) const
330{
331 CHECK_BOUNDS(id);
332 return ROW_SIZE(id);
333}
334
335// Insertion
336// =========
337
338template<typename T>
339void
340vector2D<T>::push_row(const std::vector<int>& row)
341{
342 if (row.empty())
343 return;
344 indexes.push_back(data.size());
345 data.push_back(row.size()); /* size not counting zeroes */
346 capacities.push_back(row.size());
347 data.insert(data.end(), row.begin(), row.end());
348}
349
350template<typename T>
351void
352vector2D<T>::emplace_row(std::initializer_list<int> row)
353{
354 if (row.size() == 0)
355 return;
356
357 indexes.push_back(data.size());
358 data.push_back(row.size()); /* size not counting zeroes */
359 capacities.push_back(row.size());
360 data.insert(data.end(), row.begin(), row.end());
361}
362
363// Deletion
364// ========
365
366template<typename T>
367inline void
369{
370 CHECK_BOUNDS(id);
371 ROW_SIZE(id) = 0;
372}
373
374template<typename T>
375bool
376vector2D<T>::delete_element(row_id_t rowId, row_size_t offset)
377{
378 CHECK_BOUNDS(rowId);
379
380 data_size_t i = ROW_BEGIN(rowId) + offset;
381 assert(i < data.size());
382
383 data[i] = 0;
384 if (--ROW_SIZE(rowId) == 0) /* decrementing the size */
385 {
386 return false;
387 }
388 return true;
389}
390
391template<typename T>
392void
394{
395 std::vector<T> newData;
396 std::vector<row_size_t> newCapacities;
397 std::vector<data_size_t> newIndexes;
398
399 // Reserve space for newData to minimize reallocations
400 newData.reserve(data.size());
401
402 for (row_id_t rowId = 0; rowId < indexes.size(); ++rowId) {
403 if (ROW_SIZE(rowId) == 0) {
404 continue; // Skip deleted rows
405 }
406
407 newIndexes.push_back(newData.size()); // the index of next row
408 newCapacities.push_back(ROW_SIZE(rowId));
409 data_size_t start = ROW_BEGIN(rowId);
410 data_size_t end = ROW_END(rowId);
411
412 for (data_size_t i = start; i < end; ++i) {
413 if (data[i] != 0) {
414 newData.push_back(data[i]);
415 }
416 }
417 }
418
419 // Move new data to existing vectors
420 data = std::move(newData);
421 capacities = std::move(newCapacities);
422 indexes = std::move(newIndexes);
423
424 // Release unused memory, `shrink_to_fit` might reallocate
425 data.shrink_to_fit();
426 capacities.shrink_to_fit();
427 indexes.shrink_to_fit();
428}
429
430// template <typename T>
431// void vector2D<T>::cleanup()
432// {
433// // Shrink all vectors
434// this->data.shrink_to_fit();
435// this->indexes.shrink_to_fit();
436// this->capacities.shrink_to_fit();
437
438// // A map size to index is to be generated by iterating over all the clauses
439// std::unordered_map<row_size_t,data_size_t> rowBySize;
440// // Keep indexes of deleted,
441// std::unordered_map<data_size_t,row_size_t> deletedRows;
442// // In the loop: Check if the row need to be shifted because of zeroes before copying it
443// row_id_t rowCount = this->indexes.size();
444// for(row_id_t rowId = 0; rowId < rowCount; rowId++)
445// {
446// if(!ROW_SIZE(rowId))
447// {
448// // Delete row
449// deletedRows.insert({rowId, ROW_CAP(rowId)});
450// }
451// else if(ROW_CAP(rowId) != ROW_SIZE(rowId))
452// {
453// row_size_t nonZeros = ROW_SIZE(rowId);
454// data_size_t idx = ROW_BEGIN(rowId);
455// data_size_t lastNonZero = ROW_BEGIN(rowId);
456// // Compact the row
457// while(!nonZeros)
458// {
459// if(this->data[idx] != 0)
460// {
461// this->data[lastNonZero] = this->data[idx];
462// this->data[idx] = this->data[lastNonZero];
463// lastNonZero++;
464// nonZeros--;
465// }
466// idx++;
467// }
468// }
469// indexesByCapacity.insert({ROW_SIZE(rowId), rowId});
470// }
471
472// row_id_t cutId = rowCount;
473
474// // Fill all the deleted rows capacities the most optimal way.
475// for(auto& drow : deletedRows)
476// {
477// /* Algorithm:
478// - Check if the index drow.first is the before cutId, if not continue
479// - Find a row or multiple rows with index > drow.fisrt that could fit in drow.second, using rowBySize map
480// - If one of the filling rows is at index cutId - 1, update cutId to the index of the row (if multiple rows,
481// check if they are not consecutive)
482// - Update the indexes and capacities vector accordingly. The capacities become their sizes, since we are
483// looking for perfect fits
484// - Update the deletedRows with the new gaps created by the moved rows
485// */
486// }
487// // Cut data from indexes.at(cutId)
488// }
489}
Definition vector2D.hpp:33
A span-like container that skips zero elements when iterating.
Definition vector2D.hpp:27
A 2D vector implementation optimized for sparse data.
Definition vector2D.hpp:175
void emplace_row(std::initializer_list< int > row)
Adds a new row to the 2D vector using an initializer list.
Definition vector2D.hpp:352
void cleanup()
Cleans up the 2D vector by removing deleted rows and compacting data.
Definition vector2D.hpp:393
T * begin(row_id_t id)
Gets the beginning iterator for a specific row.
Definition vector2D.hpp:295
skipzero_span< T > operator[](row_id_t id)
Accesses a row in the 2D vector.
Definition vector2D.hpp:279
void delete_row(row_id_t id)
Marks a row as deleted.
Definition vector2D.hpp:368
const T * end(row_id_t id) const
Gets the end const iterator for a specific row.
Definition vector2D.hpp:320
T * end(row_id_t id)
Gets the end iterator for a specific row.
Definition vector2D.hpp:303
row_size_t getRowsCount() const
Gets the number of rows in the 2D vector.
Definition vector2D.hpp:232
row_size_t getRowSize(row_id_t id) const
Gets the size of a specific row.
Definition vector2D.hpp:329
bool delete_element(row_id_t rowId, row_size_t offset)
Deletes an element in a specific row.
Definition vector2D.hpp:376
const T * begin(row_id_t id) const
Gets the beginning const iterator for a specific row.
Definition vector2D.hpp:312
skipzero_span< const T > operator[](row_id_t id) const
Accesses a row in the 2D vector (const version).
Definition vector2D.hpp:287
void push_row(const std::vector< int > &row)
Adds a new row to the 2D vector.
Definition vector2D.hpp:340