Program Listing for File gray_reorder.cc
↰ Return to documentation for file (src/sparsebase/reorder/gray_reorder.cc
)
#include "sparsebase/reorder/gray_reorder.h"
#include "sparsebase/reorder/reorderer.h"
#include "sparsebase/utils/logger.h"
namespace sparsebase::reorder {
template <typename IDType, typename NNZType, typename ValueType>
GrayReorder<IDType, NNZType, ValueType>::GrayReorder(
BitMapSize resolution, int nnz_threshold, int sparse_density_group_size) {
auto params_struct = new GrayReorderParams;
params_struct->resolution = resolution;
params_struct->nnz_threshold = nnz_threshold;
params_struct->sparse_density_group_size = sparse_density_group_size;
this->params_ = std::unique_ptr<GrayReorderParams>(params_struct);
this->RegisterFunction(
{format::CSR<IDType, NNZType, ValueType>::get_id_static()},
GrayReorderingCSR);
}
template <typename IDType, typename NNZType, typename ValueType>
GrayReorder<IDType, NNZType, ValueType>::GrayReorder(GrayReorderParams p)
: GrayReorder(p.resolution, p.nnz_threshold, p.sparse_density_group_size) {}
template <typename IDType, typename NNZType, typename ValueType>
bool GrayReorder<IDType, NNZType, ValueType>::desc_comparator(
const row_grey_pair &l, const row_grey_pair &r) {
return l.second > r.second;
}
template <typename IDType, typename NNZType, typename ValueType>
bool GrayReorder<IDType, NNZType, ValueType>::asc_comparator(
const row_grey_pair &l, const row_grey_pair &r) {
return l.second < r.second;
}
template <typename IDType, typename NNZType, typename ValueType>
// not sure if all IDTypes work for this
unsigned long GrayReorder<IDType, NNZType, ValueType>::grey_bin_to_dec(
unsigned long n) {
unsigned long inv = 0;
for (; n; n = n >> 1) inv ^= n;
return inv;
}
template <typename IDType, typename NNZType, typename ValueType>
void GrayReorder<IDType, NNZType, ValueType>::print_dec_in_bin(unsigned long n,
int size) {
// array to store binary number
int binaryNum[size];
// counter for binary array
int i = 0;
while (n > 0) {
// storing remainder in binary array
binaryNum[i] = n % 2;
n = n / 2;
i++;
}
// printing binary array in reverse order
std::string bin_nums = "";
for (int j = i - 1; j >= 0; j--)
bin_nums = bin_nums + std::to_string(binaryNum[j]);
utils::Logger l(typeid(GrayReorder));
l.Log(bin_nums, utils::LogLevel::LOG_LVL_INFO);
}
// not sure if all IDTypes work for this
template <typename IDType, typename NNZType, typename ValueType>
unsigned long GrayReorder<IDType, NNZType, ValueType>::bin_to_grey(
unsigned long n) {
/* Right Shift the number by 1
taking xor with original number */
return n ^ (n >> 1);
}
template <typename IDType, typename NNZType, typename ValueType>
bool GrayReorder<IDType, NNZType, ValueType>::is_banded(
int nnz, int n_cols, NNZType *row_ptr, IDType *cols,
std::vector<IDType> order, int band_size) {
if (band_size == -1) band_size = n_cols / 64;
int band_count = 0;
bool banded = false;
for (int r = 0; r < order.size(); r++) {
for (int i = row_ptr[order[r]]; i < row_ptr[order[r] + 1]; i++) {
int col = cols[i];
if (abs(col - r) <= band_size) band_count++;
}
}
if (double(band_count) / nnz >= 0.3) {
banded = true;
}
utils::Logger logger(typeid(GrayReorder));
logger.Log("NNZ % in band: " + std::to_string(double(band_count) / nnz),
utils::LogLevel::LOG_LVL_INFO);
return banded;
}
template <typename IDType, typename NNZType, typename ValueType>
IDType *GrayReorder<IDType, NNZType, ValueType>::GrayReorderingCSR(
std::vector<format::Format *> input_sf, utils::Parameters *poly_params) {
auto csr = input_sf[0]->AsAbsolute<format::CSR<IDType, NNZType, ValueType>>();
context::CPUContext *cpu_context =
static_cast<context::CPUContext *>(csr->get_context());
IDType n_rows = csr->get_dimensions()[0];
/*This array stores the permutation vector such as order[0] = 243 means that
* row 243 is the first row of the reordered matrix*/
IDType *order = new IDType[n_rows]();
GrayReorderParams *params = static_cast<GrayReorderParams *>(poly_params);
int group_size = params->sparse_density_group_size;
int bit_resolution = params->resolution;
int raise_to = 0;
int adder = 0;
int start_split_reorder, end_split_reorder;
int last_row_nnz_count = 0;
int threshold = 0; // threshold used to set a bit in bitmap to 1
bool decresc_grey_order = false;
int group_count = 0;
// Initializing row order
std::vector<IDType> v_order;
std::vector<IDType> sparse_v_order;
std::vector<IDType> dense_v_order;
// Splitting original matrix's rows in two submatrices
IDType sparse_dense_split = 0;
for (IDType i = 0; i < n_rows; i++) {
if ((csr->get_row_ptr()[i + 1] - csr->get_row_ptr()[i]) <=
params->nnz_threshold) {
sparse_v_order.push_back(i);
sparse_dense_split++;
} else {
dense_v_order.push_back(i);
}
}
v_order.reserve(sparse_v_order.size() +
dense_v_order.size()); // preallocate memory
bool is_sparse_banded =
is_banded(csr->get_num_nnz(), csr->get_dimensions()[1],
csr->get_row_ptr(), csr->get_col(), sparse_v_order);
utils::Logger logger(typeid(GrayReorder));
if (is_sparse_banded)
logger.Log(
"Sparse Sub-Matrix highly banded - Performing just density reordering",
utils::LogLevel::LOG_LVL_INFO);
bool is_dense_banded =
is_banded(csr->get_num_nnz(), csr->get_dimensions()[1],
csr->get_row_ptr(), csr->get_col(), dense_v_order);
if (is_dense_banded)
logger.Log("Dense Sub-Matrix highly banded - Maintaining structure",
utils::LogLevel::LOG_LVL_INFO);
std::sort(sparse_v_order.begin(), sparse_v_order.end(),
[&](int i, int j) -> bool {
return (csr->get_row_ptr()[i + 1] - csr->get_row_ptr()[i]) <
(csr->get_row_ptr()[j + 1] - csr->get_row_ptr()[j]);
}); // reorder sparse matrix into nnz amount
// the bit resolution determines the width of the bitmap of each row
if (n_rows < bit_resolution) {
bit_resolution = n_rows;
}
int row_split = n_rows / bit_resolution;
auto nnz_per_row_split = new IDType[bit_resolution];
auto nnz_per_row_split_bin = new IDType[bit_resolution];
unsigned long decimal_bit_map = 0;
unsigned long dec_begin = 0;
int dec_begin_ind = 0;
std::vector<row_grey_pair>
reorder_section; // vector that contains a section to be reordered
if (!is_sparse_banded) { // if banded just row ordering by nnz count is
// enough, else do bitmap reordering in groups
for (int i = 0; i < sparse_v_order.size();
i++) { // sparse sub matrix if not highly banded
if (i == 0) {
last_row_nnz_count =
csr->get_row_ptr()[sparse_v_order[i] + 1] -
csr->get_row_ptr()[sparse_v_order[i]]; // get nnz count in first
// row
start_split_reorder = 0;
} // check if nnz amount changes from last row
if ((csr->get_row_ptr()[sparse_v_order[i] + 1] -
csr->get_row_ptr()[sparse_v_order[i]]) ==
0) { // for cases where rows are empty
start_split_reorder = i + 1;
last_row_nnz_count = csr->get_row_ptr()[sparse_v_order[i + 1] + 1] -
csr->get_row_ptr()[sparse_v_order[i + 1]];
continue;
}
// reset bitmap for this row
for (int j = 0; j < bit_resolution; j++) nnz_per_row_split[j] = 0;
for (int j = 0; j < bit_resolution; j++) nnz_per_row_split_bin[j] = 0;
// get number of nnz in each bitmap section
for (int k = csr->get_row_ptr()[sparse_v_order[i]];
k < csr->get_row_ptr()[sparse_v_order[i] + 1]; k++) {
nnz_per_row_split[csr->get_col()[k] / row_split]++;
}
// get bitmap of the row in decimal value (first rows are less significant
// bits)
decimal_bit_map = 0;
for (int j = 0; j < bit_resolution; j++) {
adder = 0;
if (nnz_per_row_split[j] > threshold) {
nnz_per_row_split_bin[j] = 1;
raise_to = j;
adder = pow(2, raise_to);
decimal_bit_map = decimal_bit_map + adder;
}
}
// if number of nnz changed from last row, increment group count, which
// might trigger a reorder of the group
if ((i != 0) &&
(last_row_nnz_count != (csr->get_row_ptr()[sparse_v_order[i] + 1] -
csr->get_row_ptr()[sparse_v_order[i]]))) {
group_count = group_count + 1;
logger.Log("Rows[" + std::to_string(start_split_reorder) + " -> " +
std::to_string(i - 1) +
"] NNZ Count: " + std::to_string(last_row_nnz_count),
utils::LogLevel::LOG_LVL_INFO);
// update nnz count for current row
last_row_nnz_count = csr->get_row_ptr()[sparse_v_order[i] + 1] -
csr->get_row_ptr()[sparse_v_order[i]];
// if group size achieved, start reordering section until this row
if (group_count == group_size) {
end_split_reorder = i;
logger.Log("Reorder Group[" + std::to_string(start_split_reorder) +
" -> " + std::to_string(end_split_reorder - 1) + "]",
utils::LogLevel::LOG_LVL_INFO);
// start next split the split for processing
// process and reorder the reordered_matrix array till this point
// (ascending or descending alternately)
if (!decresc_grey_order) {
sort(reorder_section.begin(), reorder_section.end(),
asc_comparator);
decresc_grey_order = !decresc_grey_order;
} else {
sort(reorder_section.begin(), reorder_section.end(),
desc_comparator);
decresc_grey_order = !decresc_grey_order;
}
dec_begin = reorder_section[0].second;
dec_begin_ind = start_split_reorder;
// apply reordered
for (int a = start_split_reorder; a < end_split_reorder; a++) {
if ((dec_begin !=
reorder_section[a - start_split_reorder].second) &&
(a < 100000)) {
logger.Log("Rows[" + std::to_string(dec_begin_ind) + " -> " +
std::to_string(a) + "] Grey Order: " +
std::to_string(dec_begin) + "// Binary:",
utils::LogLevel::LOG_LVL_INFO);
// print_dec_in_bin(bin_to_grey(dec_begin));
dec_begin = reorder_section[a - start_split_reorder].second;
dec_begin_ind = a;
}
sparse_v_order[a] = reorder_section[a - start_split_reorder].first;
}
start_split_reorder = i;
reorder_section.clear();
group_count = 0;
}
}
// if(decimal_bit_map != 0){
// for(int i = 0; i < bit_resolution; i++){
// std::cout << "[" << nnz_per_row_split_bin[(bit_resolution-1)-i] <<
// "]";
// }
// std::cout << "\nRow "<< i << "[" << v_order[i] << "] grey value: "
// << decimal_bit_map << " translates to: "<<
// grey_bin_to_dec(decimal_bit_map) <<"\n";
// }
//
reorder_section.push_back(
row_grey_pair(sparse_v_order[i], grey_bin_to_dec(decimal_bit_map)));
// when reaching end of sparse submatrix, reorder section
if (i == sparse_v_order.size() - 1) {
end_split_reorder = sparse_v_order.size();
logger.Log("Rows[" + std::to_string(start_split_reorder) + " -> " +
std::to_string(end_split_reorder - 1) +
"] NNZ Count: " + std::to_string(last_row_nnz_count),
utils::LogLevel::LOG_LVL_INFO);
if (!decresc_grey_order) {
sort(reorder_section.begin(), reorder_section.end(), asc_comparator);
decresc_grey_order = !decresc_grey_order;
} else {
sort(reorder_section.begin(), reorder_section.end(), desc_comparator);
decresc_grey_order = !decresc_grey_order;
}
for (int a = start_split_reorder; a < end_split_reorder; a++) {
sparse_v_order[a] = reorder_section[a - start_split_reorder].first;
}
}
}
reorder_section.clear();
}
if (!is_dense_banded) {
logger.Log("Rows [" + std::to_string(sparse_dense_split) + "-" +
std::to_string(n_rows) +
"] Starting Dense Sorting through NNZ and Grey code..",
utils::LogLevel::LOG_LVL_INFO);
for (int i = 0; i < dense_v_order.size(); i++) {
// if first row, establish the nnz amount, and starting index
for (int j = 0; j < bit_resolution; j++) nnz_per_row_split[j] = 0;
for (int k = csr->get_row_ptr()[dense_v_order[i]];
k < csr->get_row_ptr()[dense_v_order[i] + 1]; k++) {
nnz_per_row_split[csr->get_col()[k] / row_split]++;
}
threshold = (csr->get_row_ptr()[dense_v_order[i] + 1] -
csr->get_row_ptr()[dense_v_order[i]]) /
bit_resolution; // floor
decimal_bit_map = 0;
for (int j = 0; j < bit_resolution; j++) {
adder = 0;
if (nnz_per_row_split[j] > threshold) {
raise_to = j; // row 0 = lowest significant bit
adder = pow(2, raise_to);
decimal_bit_map = decimal_bit_map + adder;
}
}
reorder_section.push_back(
row_grey_pair(dense_v_order[i], grey_bin_to_dec(decimal_bit_map)));
}
logger.Log("Reordering Rows based on grey values...",
utils::LogLevel::LOG_LVL_INFO);
std::sort(reorder_section.begin(), reorder_section.end(), asc_comparator);
for (int a = 0; a < dense_v_order.size(); a++) {
dense_v_order[a] = reorder_section[a].first;
}
reorder_section.clear();
}
v_order.insert(v_order.end(), sparse_v_order.begin(), sparse_v_order.end());
v_order.insert(v_order.end(), dense_v_order.begin(), dense_v_order.end());
/*This order array stores the inverse permutation vector such as order[0] =
* 243 means that row 0 is placed at the row 243 of the reordered matrix*/
// std::vector<IDType> v_order_inv(n_rows);
for (int i = 0; i < n_rows; i++) {
order[v_order[i]] = i;
}
// std::copy(v_order_inv.begin(), v_order_inv.end(), order);
return order;
}
#if !defined(_HEADER_ONLY)
#include "init/gray_reorder.inc"
#endif
} // namespace sparsebase::reorder