Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Random Sparse2dArrays #372

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions lib/cpp-test/array/array_gtest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class ArrayTest : public ::testing::Test {
typedef ::testing::Types<ArrayFloat, ArrayDouble, ArrayShort, ArrayUShort,
ArrayInt, ArrayUInt, ArrayLong, ArrayULong>
MyArrayTypes;
TYPED_TEST_CASE(ArrayTest, MyArrayTypes);
TYPED_TEST_SUITE(ArrayTest, MyArrayTypes);

template <typename ArrType>
class Array2dTest : public ::testing::Test {
Expand All @@ -49,7 +49,7 @@ typedef ::testing::Types<ArrayFloat2d, ArrayDouble2d, ArrayShort2d,
ArrayUShort2d, ArrayInt2d, ArrayUInt2d, ArrayLong2d,
ArrayULong2d>
MyArray2dTypes;
TYPED_TEST_CASE(Array2dTest, MyArray2dTypes);
TYPED_TEST_SUITE(Array2dTest, MyArray2dTypes);

TYPED_TEST(ArrayTest, InitToZero) {
TypeParam arr{TICK_TEST_DATA_SIZE};
Expand Down Expand Up @@ -626,6 +626,15 @@ TYPED_TEST(Array2dTest, SerializationBinary) {
TypeParam>();
}

TEST(SparseTesting, RandomSparse2d) {
auto random_sparse = SparseArray2d<double>::RANDOM(100, 100, .33);
auto dense = random_sparse->as_array2d();
auto sparse = dense.as_sparsearray2d();
ASSERT_EQ(random_sparse->size(), sparse->size());
ASSERT_EQ(random_sparse->n_rows(), sparse->n_rows());
ASSERT_EQ(random_sparse->n_cols(), sparse->n_cols());
}

#ifdef ADD_MAIN
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
Expand Down
2 changes: 1 addition & 1 deletion lib/cpp-test/array/atomic_array_gtest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ class AtomicArrayTest : public ::testing::Test {
};

typedef ::testing::Types<Array<float>, Array<double>> MyArrayTypes;
TYPED_TEST_CASE(AtomicArrayTest, MyArrayTypes);
TYPED_TEST_SUITE(AtomicArrayTest, MyArrayTypes);

TYPED_TEST(AtomicArrayTest, InitToZero) {
TypeParam arr{TICK_TEST_DATA_SIZE};
Expand Down
2 changes: 1 addition & 1 deletion lib/cpp-test/array/linear_system_gtest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class LinearSystemTest : public ::testing::Test {
};

typedef ::testing::Types<ArrayFloat, ArrayDouble> MyArrayTypes;
TYPED_TEST_CASE(LinearSystemTest, MyArrayTypes);
TYPED_TEST_SUITE(LinearSystemTest, MyArrayTypes);



Expand Down
112 changes: 112 additions & 0 deletions lib/include/tick/array/array2d.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ class SArray2d;
template <typename T, typename MAJ = RowMajor>
class SparseArray2d;

template <typename T, typename MAJ>
class SSparseArray2d;

/*! \class Array2d
* \brief Template class for basic non sparse 2d arrays of type `T`.
*
Expand Down Expand Up @@ -51,6 +54,81 @@ class Array2d : public BaseArray2d<T, MAJ> {
using AbstractArray1d2d<T, MAJ>::is_sparse;
using AbstractArray1d2d<T, MAJ>::init_to_zero;

// implement this properly
explicit Array2d(std::vector<std::vector<T>> data) {
allocVector2D_Data(data);
}

Array2d<T>& operator=(std::vector<std::vector<T>> data) {
allocVector2D_Data(data);
return *this;
}

void allocVector2D_Data(std::vector<std::vector<T>> data) {
if (data.size() == 0) {
TICK_ERROR("data empty");
return;
}

if (is_data_allocation_owned)
TICK_PYTHON_FREE(_data);

_n_cols = data[0].size();
_n_rows = data.size();
_size = _n_cols * _n_rows;

is_data_allocation_owned = true;
TICK_PYTHON_MALLOC(_data, T, _size);

ulong index = 0;
for (std::vector<T> vec : data) {
if (vec.size() != _n_cols)
TICK_ERROR("non consistent column length");
memcpy(_data + index, vec.data(), _n_cols * sizeof(T));
index+=_n_cols * sizeof(T) / sizeof(void*);
}
}

std::shared_ptr<SSparseArray2d<T, MAJ>> toSSparseArray2dPtr() {
std::vector<T> data;
std::vector<uint> row_idx(_n_rows + 1);
std::vector<uint> col;

ulong nnz = 0;

row_idx[0] = 0;
for (uint r = 0; r < _n_rows; r++) {
int nnz_row = 0;
for (uint c = 0; c < _n_cols; c++) {
if (operator()(r, c) != (T)0) {
T val = operator()(r, c);
nnz++;
nnz_row++;
data.push_back(val);
col.push_back(c);
}
}
row_idx[r + 1] = row_idx[r] + nnz_row;
}

uint* row_ptr = new uint[row_idx.size()];
uint* col_ptr = new uint[col.size()];
T* data_ptr = new T[data.size()];

memcpy(row_ptr, row_idx.data(), row_idx.size() * sizeof(uint));
memcpy(col_ptr, col.data(), col.size() * sizeof(uint));
memcpy(data_ptr, data.data(), data.size() * sizeof(T));

std::shared_ptr<SSparseArray2d<T, MAJ>> arrayptr =
SSparseArray2d<T, MAJ>::new_ptr(0, 0, 0);

arrayptr->set_data_indices_rowindices(data_ptr, col_ptr, row_ptr, _n_rows, _n_cols);
return arrayptr;
}


//

//! @brief Constructor for an empty array.
Array2d() : BaseArray2d<T, MAJ>(true) {}

Expand Down Expand Up @@ -192,6 +270,8 @@ class Array2d : public BaseArray2d<T, MAJ> {
// The definition is in the file sarray.h
std::shared_ptr<SArray2d<T, MAJ>> as_sarray2d_ptr();

std::shared_ptr<SparseArray2d<T, MAJ>> as_sparsearray2d() const;

public:
bool compare(const Array2d<T, MAJ>& that) const {
bool are_equal = BaseArray2d<T, MAJ>::compare(that);
Expand Down Expand Up @@ -484,4 +564,36 @@ inline std::ostream &operator<<(std::ostream &s, const std::vector<T> &p) {
return s << typeid(p).name() << "<" << typeid(T).name() << ">";
}

template <typename T, typename MAJ>
std::shared_ptr<SparseArray2d<T, MAJ>> Array2d<T, MAJ>::as_sparsearray2d() const {
T zero {0};
auto this_data = this->data();
size_t _n_rows = this->n_rows(), _n_cols = this->n_cols(), nnz = 0, size = 0;
for (size_t r = 0; r < _n_rows; r++) {
for (size_t c = 0; c < _n_cols; c++) {
T val {0};
if ((val = this_data[(r * _n_cols) + c]) != zero) size++;
}
}
auto sparse = SSparseArray2d<T, MAJ>::new_ptr(_n_rows, _n_cols, size);
auto *data = sparse->data();
auto *indices = sparse->indices();
auto *row_indices = sparse->row_indices();
row_indices[0] = 0;
for (size_t r = 0; r < _n_rows; r++) {
size_t nnz_row = 0;
for (size_t c = 0; c < _n_cols; c++) {
T val {0};
if ((val = this_data[(r * _n_cols) + c]) != zero) {
data[nnz] = val;
indices[nnz] = c;
nnz++;
nnz_row++;
}
}
row_indices[r + 1] = row_indices[r] + nnz_row;
}
return sparse;
}

#endif // LIB_INCLUDE_TICK_ARRAY_ARRAY2D_H_
62 changes: 62 additions & 0 deletions lib/include/tick/array/sparse2d/random2d.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@

#ifndef LIB_INCLUDE_TICK_ARRAY_SPARSE2D_RANDOM2D_H_
#define LIB_INCLUDE_TICK_ARRAY_SPARSE2D_RANDOM2D_H_

#include <random>

template <typename T, typename MAJ>
std::shared_ptr<SparseArray2d<T, MAJ>> SparseArray2d<T, MAJ>::RANDOM(size_t rows, size_t cols, T density, T seed) {
if (density < 0 || density > 1)
throw std::runtime_error("Invalid sparse density, must be between 0 and 1");

size_t size = std::floor(rows * cols * density);
auto arr = SSparseArray2d<T, MAJ>::new_ptr(rows, cols, size);

std::mt19937_64 generator;
if (seed > 0) {
generator = std::mt19937_64(seed);
} else {
std::random_device r;
std::seed_seq seed_seq{r(), r(), r(), r(), r(), r(), r(), r()};
generator = std::mt19937_64(seed_seq);
}
std::uniform_real_distribution<T> dist;
auto data = arr->data();
for (size_t i = 0; i < size; i++) data[i] = dist(generator);

size_t nnz = size;
std::vector<size_t> nnz_row(rows, 0);

size_t index = 0;
while (nnz > 0) {
std::uniform_int_distribution<size_t> dist_int(1, 100); // to do 50 50
if (dist_int(generator) > 50) {
nnz_row[index]++;
nnz--;
}
index++;
if (index >= rows) index = 0;
}

index = 0;
auto indices = arr->indices();
for (size_t i : nnz_row) {
std::vector<size_t> indice_comb;
for (size_t j = 0; j < cols; j++) indice_comb.emplace_back(j);
std::shuffle(indice_comb.begin(), indice_comb.end(), generator);
for (size_t j = 0; j < i; j++) {
indices[index++] = indice_comb[j];
}
}

// if (index != arr->indices().size() - 1)
// std::runtime_error("Uh something is wrong");

auto row_indices = arr->row_indices();
row_indices[0] = 0;
for (size_t i = 1; i < rows + 1; i++) row_indices[i] = row_indices[i - 1] + nnz_row[i - 1];

return arr;
}

#endif // LIB_INCLUDE_TICK_ARRAY_SPARSE2D_RANDOM2D_H_
4 changes: 4 additions & 0 deletions lib/include/tick/array/sparsearray2d.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ class SparseArray2d : public BaseArray2d<T, MAJ> {
//! called on a view
std::shared_ptr<SSparseArray2d<T, MAJ>> as_ssparsearray2d_ptr();

static std::shared_ptr<SparseArray2d<T, MAJ>> RANDOM(size_t rows, size_t cols, T density, T seed = -1);

template <class Archive>
void save(Archive &ar) const {
ar(this->_size_sparse);
Expand Down Expand Up @@ -277,4 +279,6 @@ SPARSE_ARRAY2D_DEFINE_TYPE(ulong, ULong);
* @}
*/

#include "tick/array/sparse2d/random2d.h"

#endif // LIB_INCLUDE_TICK_ARRAY_SPARSEARRAY2D_H_