Skip to content

Commit 79194cb

Browse files
committed
[Code] Add mxv, vxm seq ops iml && add respective tests
1 parent d25f0bd commit 79194cb

File tree

10 files changed

+434
-9
lines changed

10 files changed

+434
-9
lines changed

cubool/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,8 @@ if (CUBOOL_WITH_SEQUENTIAL)
147147
sources/sequential/sq_ewiseadd.hpp
148148
sources/sequential/sq_spgemm.cpp
149149
sources/sequential/sq_spgemm.hpp
150+
sources/sequential/sq_spgemv.cpp
151+
sources/sequential/sq_spgemv.hpp
150152
sources/sequential/sq_reduce.cpp
151153
sources/sequential/sq_reduce.hpp
152154
sources/sequential/sq_submatrix.cpp

cubool/sources/core/vector.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ namespace cubool {
198198
CHECK_RAISE_ERROR(m != nullptr, InvalidArgument, "Passed matrix does not belong to core matrix class");
199199

200200
CHECK_RAISE_ERROR(v->getNrows() == m->getNrows(), InvalidArgument, "Provided vector and matrix have incompatible size for operation");
201-
CHECK_RAISE_ERROR(this->getNrows() == v->getNrows(), InvalidArgument, "This vector has incompatible size for operation result");
201+
CHECK_RAISE_ERROR(this->getNrows() == m->getNcols(), InvalidArgument, "This vector has incompatible size for operation result");
202202

203203
v->commitCache();
204204
m->commitCache();
@@ -229,7 +229,7 @@ namespace cubool {
229229
CHECK_RAISE_ERROR(m != nullptr, InvalidArgument, "Passed matrix does not belong to core matrix class");
230230

231231
CHECK_RAISE_ERROR(v->getNrows() == m->getNcols(), InvalidArgument, "Provided vector and matrix have incompatible size for operation");
232-
CHECK_RAISE_ERROR(this->getNrows() == v->getNrows(), InvalidArgument, "This vector has incompatible size for operation result");
232+
CHECK_RAISE_ERROR(this->getNrows() == m->getNrows(), InvalidArgument, "This vector has incompatible size for operation result");
233233

234234
v->commitCache();
235235
m->commitCache();

cubool/sources/sequential/sq_backend.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,19 @@ namespace cubool {
3737

3838
void SqBackend::finalize() {
3939
assert(mMatCount == 0);
40+
assert(mVecCount == 0);
4041

4142
if (mMatCount > 0) {
4243
LogStream stream(*Library::getLogger());
4344
stream << Logger::Level::Error
4445
<< "Lost some (" << mMatCount << ") matrix objects" << LogStream::cmt;
4546
}
47+
48+
if (mVecCount > 0) {
49+
LogStream stream(*Library::getLogger());
50+
stream << Logger::Level::Error
51+
<< "Lost some (" << mVecCount << ") vector objects" << LogStream::cmt;
52+
}
4653
}
4754

4855
bool SqBackend::isInitialized() const {
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/**********************************************************************************/
2+
/* MIT License */
3+
/* */
4+
/* Copyright (c) 2020, 2021 JetBrains-Research */
5+
/* */
6+
/* Permission is hereby granted, free of charge, to any person obtaining a copy */
7+
/* of this software and associated documentation files (the "Software"), to deal */
8+
/* in the Software without restriction, including without limitation the rights */
9+
/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
10+
/* copies of the Software, and to permit persons to whom the Software is */
11+
/* furnished to do so, subject to the following conditions: */
12+
/* */
13+
/* The above copyright notice and this permission notice shall be included in all */
14+
/* copies or substantial portions of the Software. */
15+
/* */
16+
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
17+
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
18+
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
19+
/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
20+
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
21+
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */
22+
/* SOFTWARE. */
23+
/**********************************************************************************/
24+
25+
#include <sequential/sq_spgemm.hpp>
26+
27+
namespace cubool {
28+
29+
void sq_spgemv(const CsrData& a, const VecData& b, VecData& out) {
30+
std::vector<index> result;
31+
32+
for (index i = 0; i < a.nrows; i++) {
33+
const index* ar = a.colIndices.data() + a.rowOffsets[i];
34+
const index* vr = b.indices.data();
35+
36+
const index* arend = ar + (a.rowOffsets[i + 1] - a.rowOffsets[i]);
37+
const index* vrend = vr + b.nvals;
38+
39+
bool nonZero = false;
40+
41+
while (ar != arend && vr != vrend) {
42+
if (*ar == *vr) {
43+
nonZero = true;
44+
break;
45+
}
46+
else if (*ar < *vr) {
47+
ar++;
48+
}
49+
else {
50+
vr++;
51+
}
52+
}
53+
54+
if (nonZero) {
55+
result.push_back(i);
56+
}
57+
}
58+
59+
out.nvals = result.size();
60+
out.indices = std::move(result);
61+
}
62+
63+
void sq_spgemv_transposed(const CsrData& a, const VecData& b, VecData& out) {
64+
std::vector<bool> mask(a.ncols, false);
65+
66+
for (index i: b.indices) {
67+
for (index k = a.rowOffsets[i]; k < a.rowOffsets[i + 1]; k++) {
68+
mask[a.colIndices[k]] = true;
69+
}
70+
}
71+
72+
std::vector<index> result;
73+
74+
for (index i = 0; i < mask.size(); i++) {
75+
if (mask[i])
76+
result.push_back(i);
77+
}
78+
79+
out.nvals = result.size();
80+
out.indices = std::move(result);
81+
}
82+
83+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/**********************************************************************************/
2+
/* MIT License */
3+
/* */
4+
/* Copyright (c) 2020, 2021 JetBrains-Research */
5+
/* */
6+
/* Permission is hereby granted, free of charge, to any person obtaining a copy */
7+
/* of this software and associated documentation files (the "Software"), to deal */
8+
/* in the Software without restriction, including without limitation the rights */
9+
/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
10+
/* copies of the Software, and to permit persons to whom the Software is */
11+
/* furnished to do so, subject to the following conditions: */
12+
/* */
13+
/* The above copyright notice and this permission notice shall be included in all */
14+
/* copies or substantial portions of the Software. */
15+
/* */
16+
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
17+
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
18+
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
19+
/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
20+
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
21+
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */
22+
/* SOFTWARE. */
23+
/**********************************************************************************/
24+
25+
#ifndef CUBOOL_SQ_SPGEMV_HPP
26+
#define CUBOOL_SQ_SPGEMV_HPP
27+
28+
#include <sequential/sq_data.hpp>
29+
30+
namespace cubool {
31+
32+
/**
33+
* Matrix-vector multiplication of `a` and `b`.
34+
*
35+
* @param a Input matrix
36+
* @param b Input vector
37+
* @param[out] out Where to store result
38+
*/
39+
void sq_spgemv(const CsrData& a, const VecData& b, VecData& out);
40+
41+
/**
42+
* Matrix(^T)-vector multiplication of `a` and `b`.
43+
*
44+
* @param a Input matrix
45+
* @param b Input vector
46+
* @param[out] out Where to store result
47+
*/
48+
void sq_spgemv_transposed(const CsrData& a, const VecData& b, VecData& out);
49+
50+
}
51+
52+
#endif //CUBOOL_SQ_SPGEMV_HPP

cubool/sources/sequential/sq_vector.cpp

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <sequential/sq_reduce.hpp>
2828
#include <sequential/sq_ewiseadd.hpp>
2929
#include <sequential/sq_subvector.hpp>
30+
#include <sequential/sq_spgemv.hpp>
3031
#include <utils/data_utils.hpp>
3132
#include <core/error.hpp>
3233
#include <cassert>
@@ -77,7 +78,7 @@ namespace cubool {
7778

7879
assert(other->getNrows() == this->getNrows());
7980

80-
this->mData = other->mData;
81+
mData = other->mData;
8182
}
8283

8384
void SqVector::reduce(index &result, bool checkTime) {
@@ -104,7 +105,7 @@ namespace cubool {
104105
else
105106
sq_reduce(other->mData, out);
106107

107-
this->mData = std::move(out);
108+
mData = std::move(out);
108109
}
109110

110111
void SqVector::eWiseAdd(const VectorBase &aBase, const VectorBase &bBase, bool checkTime) {
@@ -122,7 +123,7 @@ namespace cubool {
122123

123124
sq_ewiseadd(a->mData, b->mData, out);
124125

125-
this->mData = std::move(out);
126+
mData = std::move(out);
126127
}
127128

128129
void SqVector::multiplyVxM(const VectorBase &vBase, const class MatrixBase &mBase, bool checkTime) {
@@ -132,7 +133,15 @@ namespace cubool {
132133
CHECK_RAISE_ERROR(v != nullptr, InvalidArgument, "Provided vector does not belongs to sequential vector class");
133134
CHECK_RAISE_ERROR(m != nullptr, InvalidArgument, "Provided matrix does not belongs to sequential matrix class");
134135

135-
// todo
136+
assert(v->getNrows() == m->getNrows());
137+
assert(this->getNrows() == m->getNcols());
138+
139+
VecData out;
140+
out.nrows = this->getNrows();
141+
142+
sq_spgemv_transposed(m->mData, v->mData, out);
143+
144+
mData = std::move(out);
136145
}
137146

138147
void SqVector::multiplyMxV(const class MatrixBase &mBase, const VectorBase &vBase, bool checkTime) {
@@ -142,7 +151,15 @@ namespace cubool {
142151
CHECK_RAISE_ERROR(v != nullptr, InvalidArgument, "Provided vector does not belongs to sequential vector class");
143152
CHECK_RAISE_ERROR(m != nullptr, InvalidArgument, "Provided matrix does not belongs to sequential matrix class");
144153

145-
// todo
154+
assert(v->getNrows() == m->getNcols());
155+
assert(this->getNrows() == m->getNrows());
156+
157+
VecData out;
158+
out.nrows = this->getNrows();
159+
160+
sq_spgemv(m->mData, v->mData, out);
161+
162+
mData = std::move(out);
146163
}
147164

148165
index SqVector::getNrows() const {

cubool/tests/CMakeLists.txt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,10 @@ add_executable(test_vector_element test_vector_element.cpp)
3535
target_link_libraries(test_vector_element PUBLIC testing)
3636

3737
add_executable(test_vector_ewiseadd test_vector_ewiseadd.cpp)
38-
target_link_libraries(test_vector_ewiseadd PUBLIC testing)
38+
target_link_libraries(test_vector_ewiseadd PUBLIC testing)
39+
40+
add_executable(test_vector_mxv test_vector_mxv.cpp)
41+
target_link_libraries(test_vector_mxv PUBLIC testing)
42+
43+
add_executable(test_vector_vxm test_vector_vxm.cpp)
44+
target_link_libraries(test_vector_vxm PUBLIC testing)

cubool/tests/test_vector_mxv.cpp

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/**********************************************************************************/
2+
/* MIT License */
3+
/* */
4+
/* Copyright (c) 2020, 2021 JetBrains-Research */
5+
/* */
6+
/* Permission is hereby granted, free of charge, to any person obtaining a copy */
7+
/* of this software and associated documentation files (the "Software"), to deal */
8+
/* in the Software without restriction, including without limitation the rights */
9+
/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
10+
/* copies of the Software, and to permit persons to whom the Software is */
11+
/* furnished to do so, subject to the following conditions: */
12+
/* */
13+
/* The above copyright notice and this permission notice shall be included in all */
14+
/* copies or substantial portions of the Software. */
15+
/* */
16+
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
17+
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
18+
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
19+
/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
20+
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
21+
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */
22+
/* SOFTWARE. */
23+
/**********************************************************************************/
24+
25+
#include <testing/testing.hpp>
26+
27+
void testMatrixVectorMultiplyAdd(cuBool_Index m, cuBool_Index n, float density) {
28+
cuBool_Matrix a;
29+
cuBool_Vector v, r;
30+
31+
// Generate test data with specified density
32+
testing::Matrix ta = std::move(testing::Matrix::generateSparse(m, n, density));
33+
testing::Vector tv = std::move(testing::Vector::generateSparse(n, density));
34+
35+
// Allocate input matrices and resize to fill with input data
36+
ASSERT_EQ(cuBool_Matrix_New(&a, m, n), CUBOOL_STATUS_SUCCESS);
37+
ASSERT_EQ(cuBool_Vector_New(&v, n), CUBOOL_STATUS_SUCCESS);
38+
ASSERT_EQ(cuBool_Vector_New(&r, m), CUBOOL_STATUS_SUCCESS);
39+
40+
// Transfer input data into input matrices
41+
ASSERT_EQ(cuBool_Matrix_Build(a, ta.rowsIndex.data(), ta.colsIndex.data(), ta.nvals, CUBOOL_HINT_VALUES_SORTED & CUBOOL_HINT_NO_DUPLICATES), CUBOOL_STATUS_SUCCESS);
42+
ASSERT_EQ(cuBool_Vector_Build(v, tv.index.data(), tv.nvals, CUBOOL_HINT_VALUES_SORTED & CUBOOL_HINT_NO_DUPLICATES), CUBOOL_STATUS_SUCCESS);
43+
44+
// Evaluate naive r += a x b on the cpu to compare results
45+
testing::MatrixVectorMultiplyFunctor functor;
46+
testing::Vector tr = functor(ta, tv);
47+
48+
// Evaluate r += a x b
49+
ASSERT_EQ(cuBool_MxV(r, a, v, CUBOOL_HINT_NO), CUBOOL_STATUS_SUCCESS);
50+
51+
// Compare results
52+
ASSERT_EQ(tr.areEqual(r), true);
53+
54+
// Deallocate matrices
55+
ASSERT_EQ(cuBool_Matrix_Free(a), CUBOOL_STATUS_SUCCESS);
56+
ASSERT_EQ(cuBool_Vector_Free(v), CUBOOL_STATUS_SUCCESS);
57+
ASSERT_EQ(cuBool_Vector_Free(r), CUBOOL_STATUS_SUCCESS);
58+
}
59+
60+
void testRun(cuBool_Index m, cuBool_Index n, cuBool_Hints setup) {
61+
// Setup library
62+
ASSERT_EQ(cuBool_Initialize(setup), CUBOOL_STATUS_SUCCESS);
63+
64+
for (size_t i = 0; i < 5; i++) {
65+
testMatrixVectorMultiplyAdd(m, n, 0.1f + (0.05f) * ((float) i));
66+
}
67+
68+
// Finalize library
69+
ASSERT_EQ(cuBool_Finalize(), CUBOOL_STATUS_SUCCESS);
70+
}
71+
72+
TEST(cuBool_Matrix, MultiplyMatrixVectorSmall) {
73+
cuBool_Index m = 60, n = 80;
74+
testRun(m, n, CUBOOL_HINT_NO);
75+
}
76+
77+
TEST(cuBool_Matrix, MultiplyMatrixVectorMedium) {
78+
cuBool_Index m = 500, n = 800;
79+
testRun(m, n, CUBOOL_HINT_NO);
80+
}
81+
82+
TEST(cuBool_Matrix, MultiplyMatrixVectorLarge) {
83+
cuBool_Index m = 1000, n = 500;
84+
testRun(m, n, CUBOOL_HINT_NO);
85+
}
86+
87+
TEST(cuBool_Matrix, MultiplyMatrixVectorSmallFallback) {
88+
cuBool_Index m = 60, n = 80;
89+
testRun(m, n, CUBOOL_HINT_CPU_BACKEND);
90+
}
91+
92+
TEST(cuBool_Matrix, MultiplyMatrixVectorMediumFallback) {
93+
cuBool_Index m = 500, n = 800;
94+
testRun(m, n, CUBOOL_HINT_CPU_BACKEND);
95+
}
96+
97+
TEST(cuBool_Matrix, MultiplyMatrixVectorLargeFallback) {
98+
cuBool_Index m = 1000, n = 500;
99+
testRun(m, n, CUBOOL_HINT_CPU_BACKEND);
100+
}
101+
102+
CUBOOL_GTEST_MAIN

0 commit comments

Comments
 (0)