Skip to content

Commit 3dcfb02

Browse files
committed
Add new unit-test for eWiseApply(matrices)
1 parent 136005d commit 3dcfb02

File tree

3 files changed

+298
-4
lines changed

3 files changed

+298
-4
lines changed

tests/unit/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ add_grb_executables( ewiseapply ewiseapply.cpp
8585
BACKENDS reference reference_omp bsp1d hybrid hyperdags nonblocking
8686
)
8787

88+
add_grb_executables( eWiseApplyMatrix_variants eWiseApplyMatrix_variants.cpp
89+
BACKENDS reference reference_omp bsp1d hybrid hyperdags nonblocking
90+
)
91+
8892
add_grb_executables( eWiseMatrix eWiseMatrix.cpp
8993
BACKENDS reference reference_omp bsp1d hybrid hyperdags nonblocking
9094
)
Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
2+
/*
3+
* Copyright 2021 Huawei Technologies Co., Ltd.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
/*
19+
* @author Benjamin Lozes
20+
* @date 24th of May, 2023
21+
*
22+
* @brief Test for eWiseApply(Matrix, Monoid)
23+
* and eWiseApply(Matrix, Operator) variants
24+
*
25+
* This test is meant to ensure the behaviour of the eWiseApply(Matrix, Monoid)
26+
* and eWiseApply(Matrix, Operator) variants is correct. Precisely, we expect
27+
* the following behaviour:
28+
* - eWiseApply(Matrix, Monoid) should apply the monoid to all elements of
29+
* the two matrices, INCLUDING the couples (non_zero, zero), using the
30+
* provided identity value for the zero elements.
31+
* - eWiseApply(Matrix, Operator) should apply the operator to all elements
32+
* of the two matrices, EXCLUDING the couples (non_zero, zero)
33+
*
34+
*/
35+
36+
#include <iostream>
37+
#include <numeric>
38+
#include <sstream>
39+
#include <vector>
40+
41+
#include <graphblas.hpp>
42+
43+
#define _DEBUG
44+
45+
using nz_type = int;
46+
47+
constexpr size_t M = 10;
48+
constexpr size_t N = 10;
49+
constexpr nz_type A_INITIAL_VALUE = 1;
50+
constexpr nz_type B_INITIAL_VALUE = 3;
51+
52+
namespace utils {
53+
template< class Iterator >
54+
void printSparseMatrixIterator( size_t rows, size_t cols, Iterator begin, Iterator end, const std::string & name = "", std::ostream & os = std::cout ) {
55+
#ifndef _DEBUG
56+
return;
57+
#endif
58+
std::cout << "Matrix \"" << name << "\" (" << rows << "x" << cols << "):" << std::endl << "[" << std::endl;
59+
if( rows > 50 || cols > 50 ) {
60+
os << " Matrix too large to print" << std::endl;
61+
} else {
62+
// os.precision( 3 );
63+
for( size_t y = 0; y < rows; y++ ) {
64+
os << std::string( 3, ' ' );
65+
for( size_t x = 0; x < cols; x++ ) {
66+
auto nnz_val = std::find_if( begin, end, [ y, x ]( const typename std::iterator_traits< Iterator >::value_type & a ) {
67+
return a.first.first == y && a.first.second == x;
68+
} );
69+
if( nnz_val != end )
70+
os << std::fixed << ( *nnz_val ).second;
71+
else
72+
os << '_';
73+
os << " ";
74+
}
75+
os << std::endl;
76+
}
77+
}
78+
os << "]" << std::endl;
79+
std::flush( os );
80+
}
81+
82+
template< typename D >
83+
void printSparseMatrix( const grb::Matrix< D > & mat, const std::string & name = "", std::ostream & os = std::cout ) {
84+
grb::wait( mat );
85+
printSparseMatrixIterator( grb::nrows( mat ), grb::ncols( mat ), mat.cbegin(), mat.cend(), name, os );
86+
}
87+
88+
template< typename D >
89+
bool equals_matrix( const grb::Matrix< D > & A, const grb::Matrix< D > & B ) {
90+
if( grb::nrows( A ) != grb::nrows( B ) || grb::ncols( A ) != grb::ncols( B ) )
91+
return false;
92+
grb::wait( A );
93+
grb::wait( B );
94+
std::vector< std::pair< std::pair< size_t, size_t >, D > > A_vec( A.cbegin(), A.cend() );
95+
std::vector< std::pair< std::pair< size_t, size_t >, D > > B_vec( B.cbegin(), B.cend() );
96+
return std::is_permutation( A_vec.cbegin(), A_vec.cend(), B_vec.cbegin() );
97+
}
98+
} // namespace utils
99+
100+
template< class Monoid >
101+
struct input_t {
102+
const grb::Matrix< nz_type > & A;
103+
const grb::Matrix< nz_type > & B;
104+
const grb::Matrix< nz_type > & C_monoid;
105+
const grb::Matrix< nz_type > & C_operator;
106+
const Monoid & monoid;
107+
108+
input_t(
109+
const grb::Matrix< nz_type > & A = {0,0},
110+
const grb::Matrix< nz_type > & B = {0,0},
111+
const grb::Matrix< nz_type > & C_monoid = {0,0},
112+
const grb::Matrix< nz_type > & C_operator = {0,0},
113+
const Monoid & monoid = Monoid() ) :
114+
A( A ), B( B ), C_monoid( C_monoid ), C_operator( C_operator ), monoid( monoid ) {}
115+
};
116+
117+
struct output_t {
118+
grb::RC rc;
119+
};
120+
121+
template< class Monoid >
122+
void grb_program( const input_t< Monoid > & input, output_t & output ) {
123+
static_assert( grb::is_monoid< Monoid >::value, "Monoid required" );
124+
const auto & op = input.monoid.getOperator();
125+
grb::wait( input.A );
126+
grb::wait( input.B );
127+
128+
auto & rc = output.rc;
129+
130+
utils::printSparseMatrix( input.A, "A" );
131+
utils::printSparseMatrix( input.B, "B" );
132+
133+
{ // Operator variant
134+
std::cout << "-- eWiseApply using Operator, supposed to be annihilating non-zeroes -> INTERSECTION\n";
135+
grb::Matrix< nz_type > C( grb::nrows( input.A ), grb::ncols( input.A ) );
136+
rc = grb::eWiseApply( C, input.A, input.B, op, grb::Phase::RESIZE );
137+
grb::wait( C );
138+
if( rc != grb::RC::SUCCESS ) {
139+
std::cerr << "Error: Phase::RESIZE\n";
140+
return;
141+
}
142+
rc = grb::eWiseApply( C, input.A, input.B, op, grb::Phase::EXECUTE );
143+
grb::wait( C );
144+
if( rc != grb::RC::SUCCESS ) {
145+
std::cerr << "Error: Phase::EXECUTE\n";
146+
return;
147+
}
148+
149+
if( ! utils::equals_matrix( C, input.C_operator ) ) {
150+
std::cerr << "Error: Wrong result\n";
151+
utils::printSparseMatrix( C, "Obtained (operator)", std::cerr );
152+
utils::printSparseMatrix( input.C_operator, "Truth (operator)", std::cerr );
153+
rc = grb::RC::FAILED;
154+
return;
155+
}
156+
157+
std::cout << "Result (operator) is correct\n";
158+
}
159+
160+
{ // Monoid variant
161+
std::cout << "-- eWiseApply using Monoid, supposed to consider non-zeroes as the identity -> UNION\n";
162+
grb::Matrix< nz_type > C( grb::nrows( input.A ), grb::ncols( input.A ) );
163+
rc = grb::eWiseApply( C, input.A, input.B, input.monoid, grb::Phase::RESIZE );
164+
grb::wait( C );
165+
if( rc != grb::RC::SUCCESS ) {
166+
std::cerr << "Error: Phase::RESIZE\n";
167+
return;
168+
}
169+
rc = grb::eWiseApply( C, input.A, input.B, input.monoid, grb::Phase::EXECUTE );
170+
grb::wait( C );
171+
if( rc != grb::RC::SUCCESS ) {
172+
std::cerr << "Error: Phase::EXECUTE\n";
173+
return;
174+
}
175+
176+
if( ! utils::equals_matrix( C, input.C_monoid ) ) {
177+
std::cerr << "Error: Wrong result\n";
178+
utils::printSparseMatrix( C, "Obtained (monoid)", std::cerr );
179+
utils::printSparseMatrix( input.C_monoid, "Truth (monoid)", std::cerr );
180+
rc = grb::RC::FAILED;
181+
return;
182+
}
183+
184+
std::cout << "Result (monoid) is correct\n";
185+
}
186+
187+
rc = grb::RC::SUCCESS;
188+
}
189+
190+
int main( int argc, char ** argv ) {
191+
(void) argc;
192+
(void) argv;
193+
194+
if(argc > 1) std::cout << "Usage: " << argv[ 0 ] << std::endl;
195+
196+
std::cout << "This is functional test " << argv[ 0 ] << std::endl;
197+
grb::Launcher< grb::EXEC_MODE::AUTOMATIC > launcher;
198+
grb::RC rc = grb::RC::SUCCESS;
199+
200+
// Create input data
201+
/** Matrix A: Row matrix filled with A_INITIAL_VALUE
202+
* X X X X X
203+
* _ _ _ _ _
204+
* _ _ _ _ _ (...)
205+
* _ _ _ _ _
206+
* _ _ _ _ _
207+
* (...)
208+
*/
209+
grb::Matrix< nz_type > A( M, N, N );
210+
std::vector< size_t > A_rows( N, 0 ), A_cols( N, 0 );
211+
std::vector< nz_type > A_values( N, A_INITIAL_VALUE );
212+
std::iota( A_cols.begin(), A_cols.end(), 0 );
213+
rc = grb::buildMatrixUnique( A, A_rows.data(), A_cols.data(), A_values.data(), A_values.size(), grb::IOMode::SEQUENTIAL );
214+
assert( rc == grb::RC::SUCCESS );
215+
216+
/** Matrix B: Column matrix filled with B_INITIAL_VALUE
217+
* Y _ _ _ _
218+
* Y _ _ _ _
219+
* Y _ _ _ _ (...)
220+
* Y _ _ _ _
221+
* Y _ _ _ _
222+
* (...)
223+
*/
224+
grb::Matrix< nz_type > B( M, N, N );
225+
std::vector< size_t > B_rows( M, 0 ), B_cols( M, 0 );
226+
std::vector< nz_type > B_values( M, B_INITIAL_VALUE );
227+
std::iota( B_rows.begin(), B_rows.end(), 0 );
228+
rc = grb::buildMatrixUnique( B, B_rows.data(), B_cols.data(), B_values.data(), B_values.size(), grb::IOMode::SEQUENTIAL );
229+
assert( rc == grb::RC::SUCCESS );
230+
231+
{
232+
/** Matrix C_monoid_truth: Union of A and B
233+
* X+Y X X X X
234+
* Y ___ ___ ___ ___
235+
* Y ___ ___ ___ ___ (...)
236+
* Y ___ ___ ___ ___
237+
* Y ___ ___ ___ ___
238+
* (...)
239+
*/
240+
grb::Matrix< nz_type > C_monoid_truth( M, N );
241+
size_t nvalues = grb::nrows( A ) + grb::ncols( B ) - 1;
242+
std::vector< size_t > C_monoid_truth_rows( nvalues, 0 ), C_monoid_truth_cols( nvalues, 0 );
243+
std::vector< nz_type > C_monoid_truth_values( nvalues, 0 );
244+
C_monoid_truth_values[ 0 ] = A_INITIAL_VALUE + B_INITIAL_VALUE;
245+
std::iota( C_monoid_truth_rows.begin() + grb::nrows( A ), C_monoid_truth_rows.end(), 1 );
246+
std::iota( C_monoid_truth_cols.begin() + 1, C_monoid_truth_cols.begin() + grb::nrows( A ), 1 );
247+
std::fill( C_monoid_truth_values.begin() + 1, C_monoid_truth_values.begin() + grb::nrows( A ), A_INITIAL_VALUE );
248+
std::fill( C_monoid_truth_values.begin() + grb::nrows( A ), C_monoid_truth_values.end(), B_INITIAL_VALUE );
249+
rc = grb::buildMatrixUnique( C_monoid_truth, C_monoid_truth_rows.data(), C_monoid_truth_cols.data(), C_monoid_truth_values.data(), C_monoid_truth_values.size(), grb::IOMode::SEQUENTIAL );
250+
assert( rc == grb::RC::SUCCESS );
251+
252+
/** Matrix C_op_truth: Intersection of A and B
253+
* X+Y ___ ___ ___ ___
254+
* ___ ___ ___ ___ ___
255+
* ___ ___ ___ ___ ___ (...)
256+
* ___ ___ ___ ___ ___
257+
* ___ ___ ___ ___ ___
258+
* (...)
259+
*/
260+
grb::Matrix< nz_type > C_op_truth( M, N );
261+
std::vector< size_t > C_op_truth_rows( 1, 0 ), C_op_truth_cols( 1, 0 );
262+
std::vector< nz_type > C_op_truth_values( 1, A_INITIAL_VALUE + B_INITIAL_VALUE );
263+
rc = grb::buildMatrixUnique( C_op_truth, C_op_truth_rows.data(), C_op_truth_cols.data(), C_op_truth_values.data(), C_op_truth_values.size(), grb::IOMode::SEQUENTIAL );
264+
assert( rc == grb::RC::SUCCESS );
265+
266+
{ /** Test using addition operator, same type for lhs and rhs
267+
*/
268+
input_t< grb::Monoid< grb::operators::add< nz_type >, grb::identities::zero > > input { A, B, C_monoid_truth, C_op_truth,
269+
grb::Monoid< grb::operators::add< nz_type >, grb::identities::zero >() };
270+
output_t output { grb::RC::SUCCESS };
271+
// Run the test
272+
rc = launcher.exec( &grb_program, input, output, false );
273+
// Check the result
274+
assert( rc == grb::RC::SUCCESS );
275+
if( output.rc != grb::RC::SUCCESS ) {
276+
std::cout << "Test FAILED (" << grb::toString( output.rc ) << ")" << std::endl;
277+
return 1;
278+
}
279+
}
280+
}
281+
282+
std::cout << "Test OK" << std::endl;
283+
return 0;
284+
}

tests/unit/unittests.sh

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -539,10 +539,16 @@ for MODE in ${MODES}; do
539539
grep 'Test OK' ${TEST_OUT_DIR}/eWiseApply_matrix_${MODE}_${BACKEND}_${P}_${T} || echo "Test FAILED"
540540
echo " "
541541

542-
echo ">>> [x] [ ] Testing grb::eWiseLambda (matrices)"
543-
$runner ${TEST_BIN_DIR}/eWiseMatrix_${MODE}_${BACKEND} &> ${TEST_OUT_DIR}/eWiseMatrix_${MODE}_${BACKEND}_${P}_${T}.log
544-
head -1 ${TEST_OUT_DIR}/eWiseMatrix_${MODE}_${BACKEND}_${P}_${T}.log
545-
grep 'Test OK' ${TEST_OUT_DIR}/eWiseMatrix_${MODE}_${BACKEND}_${P}_${T}.log || echo "Test FAILED"
542+
echo ">>> [x] [ ] Testing grb::id on vectors and matrices"
543+
$runner ${TEST_BIN_DIR}/id_${MODE}_${BACKEND} &> ${TEST_OUT_DIR}/id_${MODE}_${BACKEND}_${P}_${T}.log
544+
head -1 ${TEST_OUT_DIR}/id_${MODE}_${BACKEND}_${P}_${T}.log
545+
grep 'Test OK' ${TEST_OUT_DIR}/id_${MODE}_${BACKEND}_${P}_${T}.log || echo "Test FAILED"
546+
echo " "
547+
548+
echo ">>> [x] [ ] Testing grb::eWiseApply (matrices, Monoid / Operator)"
549+
$runner ${TEST_BIN_DIR}/eWiseApplyMatrix_variants_${MODE}_${BACKEND} &> ${TEST_OUT_DIR}/eWiseApplyMatrix_variants_${MODE}_${BACKEND}_${P}_${T}.log
550+
head -1 ${TEST_OUT_DIR}/eWiseApplyMatrix_variants_${MODE}_${BACKEND}_${P}_${T}.log
551+
grep 'Test OK' ${TEST_OUT_DIR}/eWiseApplyMatrix_variants_${MODE}_${BACKEND}_${P}_${T}.log || echo "Test FAILED"
546552
echo " "
547553

548554
echo ">>> [x] [ ] Testing grb::zip on two vectors of doubles and"

0 commit comments

Comments
 (0)