Skip to content

Commit 2b7a51f

Browse files
committed
[Code] Add sequential sub-matrix and kronecker impl
1 parent 1e758fb commit 2b7a51f

13 files changed

+202
-14
lines changed

README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,16 @@ as well as python high-level wrapper with automated resources management.
2929
- [X] CSR transpose
3030
- [X] CSR submatrix
3131
- [X] CSR matrix reduce
32-
- [ ] CSR slicing
32+
- [X] CSR slicing
33+
- [ ] Sequential fallback backend for CPU
3334
- [ ] IO matrix loading from mtx file
3435
- [ ] IO matrix saving into mtx file
3536
- [ ] IO matrix saving into gviz format
3637
- [ ] IO user-defined file logging
3738
- [X] Wrapper for Python API
38-
- [ ] Wrapper tests in Python
39+
- [ ] Wrapper syntax sugar
40+
- [ ] Tests for Python wrapper
41+
- [ ] Code examples
3942
- [ ] User guide
4043
- [X] Unit Tests collection
4144
- [X] Dummy library implementation for testing

cubool/sources/core/matrix.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ namespace cubool {
4141
}
4242

4343
void Matrix::build(const index *rows, const index *cols, size_t nvals, bool isSorted) {
44-
CHECK_RAISE_ERROR(rows != nullptr, InvalidArgument, "Null ptr rows array");
45-
CHECK_RAISE_ERROR(cols != nullptr, InvalidArgument, "Null ptr cols array");
44+
CHECK_RAISE_ERROR(rows != nullptr || nvals == 0, InvalidArgument, "Null ptr rows array");
45+
CHECK_RAISE_ERROR(cols != nullptr || nvals == 0, InvalidArgument, "Null ptr cols array");
4646

4747
mHnd->build(rows, cols, nvals, isSorted);
4848
}
@@ -69,8 +69,8 @@ namespace cubool {
6969
CHECK_RAISE_ERROR(bI <= other->getNrows(), InvalidArgument, "Provided sub-matrix range must be within matrix bounds");
7070
CHECK_RAISE_ERROR(bJ <= other->getNcols(), InvalidArgument, "Provided sub-matrix range must be within matrix bounds");
7171

72-
CHECK_RAISE_ERROR(nrows <= this->getNrows(), InvalidArgument, "Result matrix has incompatible size for extracted sub-matrix range");
73-
CHECK_RAISE_ERROR(ncols <= this->getNcols(), InvalidArgument, "Result matrix has incompatible size for extracted sub-matrix range");
72+
CHECK_RAISE_ERROR(nrows == this->getNrows(), InvalidArgument, "Result matrix has incompatible size for extracted sub-matrix range");
73+
CHECK_RAISE_ERROR(ncols == this->getNcols(), InvalidArgument, "Result matrix has incompatible size for extracted sub-matrix range");
7474

7575
mHnd->extractSubMatrix(*other->mHnd, i, j, nrows, ncols);
7676
}

cubool/sources/cuBool_Matrix_Build.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@ cuBool_Status cuBool_Matrix_Build(
3434
CUBOOL_BEGIN_BODY
3535
CUBOOL_VALIDATE_LIBRARY
3636
CUBOOL_ARG_NOT_NULL(matrix)
37-
CUBOOL_ARG_NOT_NULL(rows)
38-
CUBOOL_ARG_NOT_NULL(cols)
3937
auto m = (cubool::Matrix *) matrix;
4038
m->build(rows, cols, nvals, hints & CUBOOL_HINT_VALUES_SORTED);
4139
CUBOOL_END_BODY

cubool/sources/sequential/sq_kronecker.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,55 @@
2626

2727
namespace cubool {
2828

29+
void scan(std::vector<index> &v) {
30+
index sum = 0;
31+
for (auto& val: v) {
32+
index next = sum + val;
33+
val = sum;
34+
sum = next;
35+
}
36+
}
37+
38+
void sq_kronecker(const CooData& a, const CooData& b, CooData& out) {
39+
size_t nvals = a.mNvals * b.mNvals;
40+
41+
out.mNvals = nvals;
42+
out.mRowIndices.resize(nvals);
43+
out.mColIndices.resize(nvals);
44+
45+
std::vector<index> aoffsets(a.mNrows + 1, 0);
46+
std::vector<index> boffsets(b.mNrows + 1, 0);
47+
48+
for (index k = 0; k < a.mNvals; k++) {
49+
aoffsets[a.mRowIndices[k]]++;
50+
}
51+
52+
for (index k = 0; k < b.mNvals; k++) {
53+
boffsets[b.mRowIndices[k]]++;
54+
}
55+
56+
scan(aoffsets);
57+
scan(boffsets);
58+
59+
size_t id = 0;
60+
61+
for (index ai = 0; ai < a.mNrows; ai++) {
62+
for (index bi = 0; bi < b.mNrows; bi++) {
63+
index rowId = ai * b.mNrows + bi;
64+
65+
for (index k = aoffsets[ai]; k < aoffsets[ai + 1]; k++) {
66+
index colIdBase = a.mColIndices[k] * b.mNcols;
67+
68+
for (index l = boffsets[bi]; l < boffsets[bi + 1]; l++) {
69+
index colId = colIdBase + b.mColIndices[l];
70+
71+
out.mRowIndices[id] = rowId;
72+
out.mColIndices[id] = colId;
73+
id += 1;
74+
}
75+
}
76+
}
77+
}
78+
}
79+
2980
}

cubool/sources/sequential/sq_kronecker.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,18 @@
2525
#ifndef CUBOOL_SP_KRONECKER_HPP
2626
#define CUBOOL_SP_KRONECKER_HPP
2727

28+
#include <sequential/sq_coo_data.hpp>
29+
2830
namespace cubool {
2931

32+
/**
33+
* Kronecker product of `a` and `b` matrices.
34+
* @param a Input matrix
35+
* @param b Input matrix
36+
* @param[out] out Result matrix
37+
*/
38+
void sq_kronecker(const CooData& a, const CooData& b, CooData& out);
39+
3040
}
3141

3242
#endif //CUBOOL_SP_KRONECKER_HPP

cubool/sources/sequential/sq_matrix.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424

2525
#include <sequential/sq_matrix.hpp>
2626
#include <sequential/sq_transpose.hpp>
27+
#include <sequential/sq_submatrix.hpp>
28+
#include <sequential/sq_kronecker.hpp>
2729
#include <core/error.hpp>
2830
#include <algorithm>
2931
#include <cassert>
@@ -109,7 +111,17 @@ namespace cubool {
109111
}
110112

111113
void SqMatrix::extractSubMatrix(const MatrixBase &otherBase, index i, index j, index nrows, index ncols) {
114+
auto other = dynamic_cast<const SqMatrix*>(&otherBase);
115+
116+
CHECK_RAISE_ERROR(other != nullptr, InvalidArgument, "Provided matrix does not belongs to sequential matrix class");
117+
118+
auto M = this->getNrows();
119+
auto N = this->getNcols();
112120

121+
assert(M == nrows);
122+
assert(N == ncols);
123+
124+
sq_submatrix(other->mData, this->mData, i, j, nrows, ncols);
113125
}
114126

115127
void SqMatrix::clone(const MatrixBase &otherBase) {
@@ -154,7 +166,21 @@ namespace cubool {
154166
}
155167

156168
void SqMatrix::kronecker(const MatrixBase &aBase, const MatrixBase &bBase) {
169+
auto a = dynamic_cast<const SqMatrix*>(&aBase);
170+
auto b = dynamic_cast<const SqMatrix*>(&bBase);
171+
172+
CHECK_RAISE_ERROR(a != nullptr, InvalidArgument, "Provided matrix does not belongs to sequential matrix class");
173+
CHECK_RAISE_ERROR(b != nullptr, InvalidArgument, "Provided matrix does not belongs to sequential matrix class");
174+
175+
auto M = a->getNrows();
176+
auto N = a->getNcols();
177+
auto K = b->getNrows();
178+
auto T = b->getNcols();
179+
180+
assert(M * K == this->getNrows());
181+
assert(N * T == this->getNcols());
157182

183+
sq_kronecker(a->mData, b->mData, this->mData);
158184
}
159185

160186
void SqMatrix::eWiseAdd(const MatrixBase &aBase, const MatrixBase &bBase) {

cubool/sources/sequential/sq_submatrix.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,37 @@
2626

2727
namespace cubool {
2828

29+
void sq_submatrix(const CooData& a, CooData& sub, index i, index j, index nrows, index ncols) {
30+
index first = a.mNvals;
31+
index last = 0;
32+
size_t nvals = 0;
33+
34+
for (index k = 0; k < a.mNvals; k++) {
35+
auto ai = a.mRowIndices[k];
36+
auto aj = a.mColIndices[k];
37+
38+
if (i <= ai && ai < i + nrows && j <= aj && aj < j + ncols) {
39+
first = std::min(first, k);
40+
last = std::max(last, k);
41+
nvals += 1;
42+
}
43+
}
44+
45+
sub.mNvals = nvals;
46+
sub.mRowIndices.resize(nvals);
47+
sub.mColIndices.resize(nvals);
48+
49+
size_t idx = 0;
50+
for (index k = first; k <= last; k++) {
51+
auto ai = a.mRowIndices[k];
52+
auto aj = a.mColIndices[k];
53+
54+
if (i <= ai && ai < i + nrows && j <= aj && aj < j + ncols) {
55+
sub.mRowIndices[idx] = ai - i;
56+
sub.mColIndices[idx] = aj - j;
57+
idx += 1;
58+
}
59+
}
60+
}
61+
2962
}

cubool/sources/sequential/sq_submatrix.hpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,22 @@
2525
#ifndef CUBOOL_SQ_SUBMATRIX_HPP
2626
#define CUBOOL_SQ_SUBMATRIX_HPP
2727

28+
#include <sequential/sq_coo_data.hpp>
29+
2830
namespace cubool {
2931

32+
/**
33+
* Extracts sub-matrix from matrix `a`
34+
*
35+
* @param a Source
36+
* @param[out] sub Result
37+
* @param i First sub-matrix row
38+
* @param j First sub-matrix col
39+
* @param nrows Sub-matrix size
40+
* @param ncols Sub-matrix size
41+
*/
42+
void sq_submatrix(const CooData& a, CooData& sub, index i, index j, index nrows, index ncols);
43+
3044
}
3145

3246
#endif //CUBOOL_SQ_SUBMATRIX_HPP

cubool/sources/sequential/sq_transpose.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
namespace cubool {
2828

2929
void sq_transpose(const CooData& a, CooData& at) {
30-
std::vector<index> offsets(a.mNcols + 1, 0);
30+
std::vector<index> offsets(a.mNcols, 0);
3131

3232
for (size_t k = 0; k < a.mNvals; k++) {
3333
offsets[a.mColIndices[k]]++;

cubool/tests/test_matrix_extract_sub_matrix.cpp

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,23 @@ void testMatrixExtractSubMatrix(cuBool_Index m, cuBool_Index n, cuBool_Index N,
3030
auto ta = testing::Matrix::generateSparse(m, n, density);
3131

3232
ASSERT_EQ(cuBool_Matrix_New(&a, m, n), CUBOOL_STATUS_SUCCESS);
33-
3433
ASSERT_EQ(cuBool_Matrix_Build(a, ta.mRowsIndex.data(), ta.mColsIndex.data(), ta.mNvals, CUBOOL_HINT_VALUES_SORTED), CUBOOL_STATUS_SUCCESS);
3534

35+
testing::TimeQuery query;
36+
3637
for (size_t i = 0; i < N; i++) {
3738
for (size_t j = 0; j < N; j++) {
3839
auto k = m / N;
3940
auto l = n / N;
4041

42+
testing::Timer t;
43+
4144
ASSERT_EQ(cuBool_Matrix_New(&r, k, l), CUBOOL_STATUS_SUCCESS);
42-
ASSERT_EQ(cuBool_Matrix_ExtractSubMatrix(r, a, i * k, j * l, k, l, CUBOOL_HINT_NO), CUBOOL_STATUS_SUCCESS);
45+
46+
{
47+
testing::TimeScope scope(query);
48+
ASSERT_EQ(cuBool_Matrix_ExtractSubMatrix(r, a, i * k, j * l, k, l, CUBOOL_HINT_NO), CUBOOL_STATUS_SUCCESS);
49+
}
4350

4451
auto tr = ta.subMatrix(i * k, j * l, k, l);
4552

@@ -48,6 +55,7 @@ void testMatrixExtractSubMatrix(cuBool_Index m, cuBool_Index n, cuBool_Index N,
4855
}
4956
}
5057

58+
std::cout << query.getAverageTimeMs() << "ms" << std::endl;
5159

5260
ASSERT_EQ(cuBool_Matrix_Free(a), CUBOOL_STATUS_SUCCESS);
5361
}
@@ -84,4 +92,22 @@ TEST(cuBool_Matrix, SubMatrixExtractLarge) {
8492
testRun(m, n, step, CUBOOL_HINT_NO);
8593
}
8694

95+
TEST(cuBool_Matrix, SubMatrixExtractSmallFallback) {
96+
cuBool_Index m = 100, n = 200;
97+
float step = 0.05f;
98+
testRun(m, n, step, CUBOOL_HINT_CPU_BACKEND);
99+
}
100+
101+
TEST(cuBool_Matrix, SubMatrixExtractMediumFallback) {
102+
cuBool_Index m = 400, n = 700;
103+
float step = 0.05f;
104+
testRun(m, n, step, CUBOOL_HINT_CPU_BACKEND);
105+
}
106+
107+
TEST(cuBool_Matrix, SubMatrixExtractLargeFallback) {
108+
cuBool_Index m = 2000, n = 4000;
109+
float step = 0.01f;
110+
testRun(m, n, step, CUBOOL_HINT_CPU_BACKEND);
111+
}
112+
87113
CUBOOL_GTEST_MAIN

0 commit comments

Comments
 (0)