Skip to content

Commit c5d9102

Browse files
committed
Smoke test for SSSP with hard-coded simple cases
1 parent 10ed4c3 commit c5d9102

File tree

4 files changed

+263
-2
lines changed

4 files changed

+263
-2
lines changed

include/graphblas/algorithms/sssp.hpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,9 +174,20 @@ namespace grb {
174174
}
175175
} // namespace utils
176176

177-
template< typename D >
178-
grb::RC sssp( const Matrix< D > & A, size_t root, grb::Vector< size_t > & distances ) {
177+
template<
178+
typename D,
179+
typename std::enable_if< std::is_arithmetic< D >::value, int >::type = 0
180+
>
181+
grb::RC sssp( const Matrix< D > & A, size_t root, grb::Vector< D > & distances ) {
179182
grb::RC rc = grb::RC::SUCCESS;
183+
184+
// Resize the output vector and fill it with -1, except for the root node which is set to 0
185+
rc = rc ? rc : grb::resize( distances, grb::nrows( A ) );
186+
rc = rc ? rc : grb::set( distances, -1L );
187+
rc = rc ? rc : grb::setElement( distances, root, 0 );
188+
189+
190+
180191
return rc;
181192
}
182193

tests/smoke/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,11 @@ add_grb_executables( kcore_decomposition kcore_decomposition.cpp
180180
BACKENDS reference reference_omp hyperdags nonblocking bsp1d hybrid
181181
)
182182

183+
add_grb_executables( sssp sssp.cpp
184+
ADDITIONAL_LINK_LIBRARIES test_utils_headers
185+
BACKENDS reference reference_omp hyperdags nonblocking
186+
)
187+
183188
# targets to list and build the test for this category
184189
get_property( smoke_tests_list GLOBAL PROPERTY tests_category_smoke )
185190
add_custom_target( "list_tests_category_smoke"

tests/smoke/smoketests.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,12 @@ for BACKEND in ${BACKENDS[@]}; do
296296
fi
297297
echo " "
298298

299+
echo ">>> [x] [ ] Testing the Single-Source Shortest Path algorithm"
300+
$runner ${TEST_BIN_DIR}/sssp_${BACKEND} &> ${TEST_OUT_DIR}/sssp_${BACKEND}_${P}_${T}.log
301+
head -1 ${TEST_OUT_DIR}/sssp_${BACKEND}_${P}_${T}.log
302+
grep 'Test OK' ${TEST_OUT_DIR}/sssp_${BACKEND}_${P}_${T}.log || echo "Test FAILED"
303+
echo " "
304+
299305
for ((i=0;i<${#LABELTEST_SIZES[@]};++i));
300306
do
301307
LABELTEST_SIZE=${LABELTEST_SIZES[i]}

tests/smoke/sssp.cpp

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
/*
2+
* Copyright 2021 Huawei Technologies Co., Ltd.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include <exception>
18+
#include <iostream>
19+
#include <vector>
20+
21+
#include <inttypes.h>
22+
23+
#include <graphblas/algorithms/sssp.hpp>
24+
#include <graphblas/utils/Timer.hpp>
25+
#include <graphblas/utils/parser.hpp>
26+
27+
#include <graphblas.hpp>
28+
#include <utils/output_verification.hpp>
29+
30+
template< typename T >
31+
grb::Vector< T > stdToGrbVector( const std::vector< T > & in ) {
32+
grb::Vector< T > out( in.size() );
33+
for( size_t i = 0; i < in.size(); i++ )
34+
grb::setElement( out, in[ i ], i );
35+
return out;
36+
}
37+
38+
template< typename T >
39+
struct input_t {
40+
grb::Matrix< T > A;
41+
size_t root;
42+
const grb::Vector< T > & expected_distances;
43+
};
44+
45+
struct output_t {
46+
grb::RC rc = grb::RC::SUCCESS;
47+
grb::utils::TimerResults times;
48+
size_t data_in_local;
49+
};
50+
51+
template< typename T >
52+
void grbProgram( const struct input_t< T > & input, struct output_t & output ) {
53+
std::cout << std::endl << "Running SSSP" << std::endl;
54+
grb::utils::Timer timer;
55+
56+
grb::Vector< T > distances( grb::nrows( input.A ) );
57+
58+
timer.reset();
59+
output.rc = output.rc ? output.rc : grb::algorithms::sssp( input.A, input.root, distances );
60+
timer.reset();
61+
62+
// Check distances by comparing it with the expected one
63+
if( std::equal( input.expected_distances.cbegin(), input.expected_distances.cend(), distances.cbegin() ) ) {
64+
std::cout << "SUCCESS: distances are correct" << std::endl;
65+
} else {
66+
std::cerr << "FAILED: distances are incorrect" << std::endl;
67+
std::cerr << "distances != expected_distances" << std::endl;
68+
for( size_t i = 0; i < grb::nrows( input.A ); i++ )
69+
std::cerr << std::string( 3, ' ' ) << distances[ i ] << " | " << input.expected_distances[ i ] << std::endl;
70+
output.rc = grb::RC::FAILED;
71+
}
72+
}
73+
74+
int main( int argc, char ** argv ) {
75+
(void)argc;
76+
(void)argv;
77+
constexpr size_t niterations = 1;
78+
79+
grb::Benchmarker< grb::EXEC_MODE::AUTOMATIC > benchmarker;
80+
std::cout << "Test executable: " << argv[ 0 ] << std::endl;
81+
82+
// Check if we are testing on a file
83+
if( argc != 1 && argc != 4 ) {
84+
std::cerr << "Usage: \n\t" << argv[ 0 ] << " [ <graph_filepath> <root> <expected_distances_filepath> ]" << std::endl;
85+
return 1;
86+
}
87+
bool test_on_file = ( argc == 4 );
88+
89+
if( test_on_file ) { // Test on a file
90+
std::string graph_filepath( argv[ 1 ] );
91+
size_t root = std::stoul( argv[ 2 ] );
92+
std::string expected_distances_filepath( argv[ 3 ] );
93+
94+
std::cout << "-- Running test on file " << graph_filepath << std::endl;
95+
96+
// Read matrix from file
97+
grb::utils::MatrixFileReader< double > reader( graph_filepath, false, true );
98+
size_t r = reader.n(), c = reader.m();
99+
assert( r == c );
100+
grb::Matrix< double > A( r, c );
101+
grb::RC rc_build = buildMatrixUnique( A, reader.cbegin( grb::IOMode::SEQUENTIAL ), reader.cend( grb::IOMode::SEQUENTIAL ), grb::IOMode::PARALLEL );
102+
if( rc_build != grb::RC::SUCCESS ) {
103+
std::cerr << "ERROR during buildMatrixUnique: rc = " << rc_build << std::endl;
104+
return 1;
105+
}
106+
std::cout << "Matrix read successfully" << std::endl;
107+
grb::Vector< double > expected_distances( r );
108+
// TODO: Read expected_distances vector from file
109+
// Run the algorithm
110+
input_t< double > input { A, root, expected_distances };
111+
output_t output;
112+
grb::RC bench_rc = benchmarker.exec( &grbProgram, input, output, niterations, 1, true );
113+
if( bench_rc ) {
114+
std::cerr << "ERROR during execution on file " << graph_filepath << ": rc = " << bench_rc << std::endl;
115+
return bench_rc;
116+
} else if( output.rc ) {
117+
std::cerr << "Test failed: rc = " << output.rc << std::endl;
118+
return output.rc;
119+
}
120+
} else {
121+
122+
/** Matrix A1:
123+
*
124+
* Schema:
125+
* 0 ----- 1
126+
* | \
127+
* | \
128+
* | \
129+
* 2 3
130+
*
131+
*/
132+
{ // Directed version, root = 0, uniform weights = 1
133+
size_t root = 0;
134+
std::vector< double > expected_distances { 0, 1, 1, 1 };
135+
std::cout << "-- Running test on A1 (directed, root " + std::to_string( root ) + ")" << std::endl;
136+
grb::Matrix< double > A( 4, 4 );
137+
std::vector< size_t > A_rows { { 0, 0, 0 } };
138+
std::vector< size_t > A_cols { { 1, 2, 3 } };
139+
std::vector< double > A_values( A_rows.size(), 1 );
140+
grb::buildMatrixUnique( A, A_rows.data(), A_cols.data(), A_values.data(), A_rows.size(), grb::IOMode::PARALLEL );
141+
input_t< double > input { A, root, stdToGrbVector( expected_distances ) };
142+
output_t output;
143+
grb::RC bench_rc = benchmarker.exec( &grbProgram, input, output, niterations, 1, true );
144+
if( bench_rc ) {
145+
std::cerr << "ERROR during execution: rc = " << bench_rc << std::endl;
146+
return bench_rc;
147+
} else if( output.rc ) {
148+
std::cerr << "Test failed: rc = " << output.rc << std::endl;
149+
return output.rc;
150+
}
151+
std::cout << std::endl;
152+
}
153+
154+
/** Matrix A2:
155+
*
156+
* Schema:
157+
* 0 ----- 2 ----- 3
158+
* |
159+
* |
160+
* |
161+
* 1
162+
*
163+
*/
164+
{ // Directed version, root = 0, uniform weights = 1
165+
size_t root = 0;
166+
std::vector< double > expected_distances { 0, 1, 1, 2 };
167+
std::cout << "-- Running test on A2 (directed, root " + std::to_string( root ) + ")" << std::endl;
168+
grb::Matrix< double > A( 4, 4 );
169+
std::vector< size_t > A_rows { { 0, 0, 2 } };
170+
std::vector< size_t > A_cols { { 1, 2, 3 } };
171+
std::vector< double > A_values( A_rows.size(), 1 );
172+
grb::buildMatrixUnique( A, A_rows.data(), A_cols.data(), A_values.data(), A_rows.size(), grb::IOMode::PARALLEL );
173+
input_t< double > input { A, root, stdToGrbVector( expected_distances ) };
174+
output_t output;
175+
grb::RC bench_rc = benchmarker.exec( &grbProgram, input, output, niterations, 1, true );
176+
if( bench_rc ) {
177+
std::cerr << "ERROR during execution: rc = " << bench_rc << std::endl;
178+
return bench_rc;
179+
} else if( output.rc ) {
180+
std::cerr << "Test failed: rc = " << output.rc << std::endl;
181+
return output.rc;
182+
}
183+
std::cout << std::endl;
184+
}
185+
186+
/** Matrix A3:
187+
*
188+
* Schema:
189+
*
190+
* 0 ----- 1 ----- 2 ----- 3
191+
*
192+
*/
193+
{ // Directed version, root = 0, uniform weights = 1
194+
size_t root = 0;
195+
std::vector< double > expected_distances { 0, 1, 2, 3 };
196+
std::cout << "-- Running test on A2.1 (directed, root " + std::to_string( root ) + ")" << std::endl;
197+
grb::Matrix< double > A( 4, 4 );
198+
std::vector< size_t > A_rows { { 0, 0, 2 } };
199+
std::vector< size_t > A_cols { { 1, 2, 3 } };
200+
std::vector< double > A_values( A_rows.size(), 1 );
201+
grb::buildMatrixUnique( A, A_rows.data(), A_cols.data(), A_values.data(), A_rows.size(), grb::IOMode::PARALLEL );
202+
input_t< double > input { A, root, stdToGrbVector( expected_distances ) };
203+
output_t output;
204+
grb::RC bench_rc = benchmarker.exec( &grbProgram, input, output, niterations, 1, true );
205+
if( bench_rc ) {
206+
std::cerr << "ERROR during execution: rc = " << bench_rc << std::endl;
207+
return bench_rc;
208+
} else if( output.rc ) {
209+
std::cerr << "Test failed: rc = " << output.rc << std::endl;
210+
return output.rc;
211+
}
212+
std::cout << std::endl;
213+
}
214+
{ // Directed version, root = 0, uniform weights = 10
215+
size_t root = 0;
216+
std::vector< double > expected_distances { 0, 10, 10, 30 };
217+
std::cout << "-- Running test on A2.2 (directed, root " + std::to_string( root ) + ")" << std::endl;
218+
grb::Matrix< double > A( 4, 4 );
219+
std::vector< size_t > A_rows { { 0, 0, 2 } };
220+
std::vector< size_t > A_cols { { 1, 2, 3 } };
221+
std::vector< double > A_values( A_rows.size(), 10 );
222+
grb::buildMatrixUnique( A, A_rows.data(), A_cols.data(), A_values.data(), A_rows.size(), grb::IOMode::PARALLEL );
223+
input_t< double > input { A, root, stdToGrbVector( expected_distances ) };
224+
output_t output;
225+
grb::RC bench_rc = benchmarker.exec( &grbProgram, input, output, niterations, 1, true );
226+
if( bench_rc ) {
227+
std::cerr << "ERROR during execution: rc = " << bench_rc << std::endl;
228+
return bench_rc;
229+
} else if( output.rc ) {
230+
std::cerr << "Test failed: rc = " << output.rc << std::endl;
231+
return output.rc;
232+
}
233+
std::cout << std::endl;
234+
}
235+
}
236+
std::cout << "Test OK" << std::endl;
237+
238+
return 0;
239+
}

0 commit comments

Comments
 (0)