Skip to content

Commit 377d1dc

Browse files
committed
Bugfix of BFS_levels
1 parent afc4035 commit 377d1dc

File tree

4 files changed

+271
-99
lines changed

4 files changed

+271
-99
lines changed

include/graphblas/algorithms/bfs.hpp

Lines changed: 59 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636

3737
#include <graphblas.hpp>
3838

39-
// #define BFS_DEBUG
39+
// #define _DEBUG
4040

4141
namespace grb {
4242

@@ -52,7 +52,7 @@ namespace grb {
5252
(void)name;
5353
(void)os;
5454

55-
#ifdef BFS_DEBUG
55+
#ifdef _DEBUG
5656
if( rows > 64 || cols > 64 ) {
5757
return;
5858
}
@@ -85,7 +85,7 @@ namespace grb {
8585
(void)name;
8686
(void)os;
8787

88-
#ifdef BFS_DEBUG
88+
#ifdef _DEBUG
8989
if( rows > 64 || cols > 64 ) {
9090
return;
9191
}
@@ -113,7 +113,7 @@ namespace grb {
113113
void printSparseMatrix( const Matrix< D > & mat, const std::string & name ) {
114114
(void)mat;
115115
(void)name;
116-
#ifdef BFS_DEBUG
116+
#ifdef _DEBUG
117117
wait( mat );
118118
printSparseMatrixIterator( nrows( mat ), ncols( mat ), mat.cbegin(), mat.cend(), name, std::cout );
119119
#endif
@@ -123,7 +123,7 @@ namespace grb {
123123
void printSparseMatrix< void >( const Matrix< void > & mat, const std::string & name ) {
124124
(void)mat;
125125
(void)name;
126-
#ifdef BFS_DEBUG
126+
#ifdef _DEBUG
127127
wait( mat );
128128
printSparsePatternMatrixIterator( nrows( mat ), ncols( mat ), mat.cbegin(), mat.cend(), name, std::cout );
129129
#endif
@@ -133,7 +133,7 @@ namespace grb {
133133
void printSparseVector( const Vector< D > & v, const std::string & name ) {
134134
(void)v;
135135
(void)name;
136-
#ifdef BFS_DEBUG
136+
#ifdef _DEBUG
137137
if( size( v ) > 64 ) {
138138
return;
139139
}
@@ -165,7 +165,7 @@ namespace grb {
165165
void printStdVector( const std::vector< T > & vector, const std::string & name ) {
166166
(void)vector;
167167
(void)name;
168-
#ifdef BFS_DEBUG
168+
#ifdef _DEBUG
169169
if( vector.size() > 64 ) {
170170
return;
171171
}
@@ -229,7 +229,7 @@ namespace grb {
229229
identities::infinity
230230
>,
231231
class SetFalseMonoid = Monoid<
232-
operators::logical_and<bool>,
232+
operators::logical_nand< bool >,
233233
identities::logical_false
234234
>
235235
>
@@ -253,74 +253,74 @@ namespace grb {
253253
void
254254
> * const = nullptr
255255
) {
256+
max_level = 0;
257+
explored_all = false;
258+
256259
RC rc = SUCCESS;
257260
const size_t nvertices = nrows( A );
261+
262+
// Frontier vectors
263+
rc = rc ? rc : setElement( x, true, root );
258264

259-
{
260-
// Frontier vectors
261-
rc = rc ? rc : setElement( x, true, root );
262-
263-
utils::printSparseMatrix( A, "A" );
264-
utils::printSparseVector( x, "x" );
265+
utils::printSparseMatrix( A, "A" );
266+
utils::printSparseVector( x, "x" );
265267

266-
// Output vector containing the minimum level at which each vertex is reached
267-
rc = rc ? rc : setElement( levels, static_cast< T >( 0 ), root );
268-
utils::printSparseVector( levels, "levels" );
268+
// Output vector containing the minimum level at which each vertex is reached
269+
rc = rc ? rc : setElement( levels, static_cast< T >( 0 ), root );
270+
utils::printSparseVector( levels, "levels" );
269271

270-
// Vector of unvisited vertices
271-
rc = rc ? rc : set( not_visited, true );
272-
rc = rc ? rc : setElement( not_visited, false, root );
272+
// Vector of unvisited vertices
273+
rc = rc ? rc : set( not_visited, true );
274+
rc = rc ? rc : setElement( not_visited, false, root );
273275

274-
size_t max_iter = max_iterations < 0 ? nvertices : max_iterations;
275-
for( size_t level = 1; level <= max_iter; level++ ) {
276+
size_t max_iter = max_iterations < 0 ? nvertices : max_iterations;
277+
for( size_t level = 1; level <= max_iter; level++ ) {
276278
#ifdef _DEBUG
277-
std::cout << "** Level " << level << ":" << std::endl << std::flush;
279+
std::cout << "** Level " << level << ":" << std::endl << std::flush;
278280
#endif
279-
max_level = level;
280-
281-
// Multiply the current frontier by the adjacency matrix
282-
utils::printSparseVector( x, "x" );
283-
utils::printSparseVector( not_visited, "not_visited" );
284-
rc = rc ? rc : resize( y, 0UL );
285-
286-
rc = rc ? rc : vxm( y, not_visited, x, A, bool_semiring, Phase::RESIZE );
287-
rc = rc ? rc : vxm( y, not_visited, x, A, bool_semiring, Phase::EXECUTE );
288-
utils::printSparseVector( y, "y" );
281+
// Multiply the current frontier by the adjacency matrix
282+
utils::printSparseVector( x, "x" );
283+
utils::printSparseVector( not_visited, "not_visited" );
284+
rc = rc ? rc : clear( y );
285+
rc = rc ? rc : vxm( y, not_visited, x, A, bool_semiring, Phase::RESIZE );
286+
rc = rc ? rc : vxm( y, not_visited, x, A, bool_semiring, Phase::EXECUTE );
287+
utils::printSparseVector( y, "y" );
289288

290-
// Update not_visited vector
291-
rc = rc ? rc : foldl( not_visited, y, y, not_visited_monoid, Phase::RESIZE );
292-
rc = rc ? rc : foldl( not_visited, y, y, not_visited_monoid, Phase::EXECUTE );
293-
// Assign the current level to the newly discovered vertices only
289+
// Update not_visited vector
290+
rc = rc ? rc : foldl( not_visited, y, not_visited_monoid, Phase::RESIZE );
291+
rc = rc ? rc : foldl( not_visited, y, not_visited_monoid, Phase::EXECUTE );
294292

295-
rc = rc ? rc : foldl( levels, y, level, min_monoid, Phase::RESIZE );
296-
rc = rc ? rc : foldl( levels, y, level, min_monoid, Phase::EXECUTE );
297-
utils::printSparseVector( levels, "levels" );
293+
// Assign the current level to the newly discovered vertices only
294+
rc = rc ? rc : foldl( levels, y, level, min_monoid, Phase::RESIZE );
295+
rc = rc ? rc : foldl( levels, y, level, min_monoid, Phase::EXECUTE );
296+
utils::printSparseVector( levels, "levels" );
298297

299-
// Check if all vertices have been discovered, equivalent of an std::all on the frontier
300-
explored_all = nnz( levels ) == nvertices;
301-
if( explored_all ) {
302-
// If all vertices are discovered, stop
298+
// Check if all vertices have been discovered, equivalent of an std::all on the frontier
299+
explored_all = nnz( levels ) == nvertices;
300+
if( explored_all ) {
301+
max_level = level;
302+
// If all vertices are discovered, stop
303303
#ifdef _DEBUG
304-
std::cout << "Explored " << level << " levels to discover all of the "
305-
<< nvertices << " vertices.\n" << std::flush;
304+
std::cout << "Explored " << level << " levels to discover all of the "
305+
<< nvertices << " vertices.\n" << std::flush;
306306
#endif
307-
return rc;
308-
}
309-
bool can_continue = nnz( y ) > 0;
310-
if( ! can_continue ) {
311-
max_level = level - 1;
312-
// If no new vertices are discovered, stop
307+
return rc;
308+
}
309+
bool can_continue = nnz( y ) > 0;
310+
if( !can_continue ) {
311+
max_level = level - 1;
312+
// If no new vertices are discovered, stop
313313
#ifdef _DEBUG
314-
std::cout << "Explored " << level << " levels to discover "
315-
<< nnz( levels ) << " vertices.\n" << std::flush;
314+
std::cout << "Explored " << level << " levels to discover "
315+
<< nnz( levels ) << " vertices.\n" << std::flush;
316316
#endif
317-
break;
318-
}
319-
320-
// Swap the frontier, avoid a copy
321-
std::swap( x, y );
317+
break;
322318
}
319+
320+
// Swap the frontier, avoid a copy
321+
std::swap( x, y );
323322
}
323+
324324

325325
// Maximum number of iteration passed, not every vertex has been discovered
326326
#ifdef _DEBUG

include/graphblas/base/internalops.hpp

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,114 @@ namespace grb {
4242
/** Core implementations of the standard operators in #grb::operators. */
4343
namespace internal {
4444

45+
/**
46+
* Standard negation operator.
47+
*
48+
* Assumes native availability of ! on the given data types or assumes that
49+
* the relevant operators are properly overloaded.
50+
*
51+
* @tparam Op The Operator class to negate.
52+
* Requires the following typedefs:
53+
* - \b D1: The left-hand input domain.
54+
* - \b D2: The right-hand input domain.
55+
* - \b D3: The output domain.
56+
* - \b operator_type: The internal::operator type to negate.
57+
*/
58+
template<
59+
class Op,
60+
enum Backend implementation = config::default_backend
61+
>
62+
class negate {
63+
public:
64+
65+
/** Alias to the left-hand input data type. */
66+
typedef typename Op::D1 left_type;
67+
68+
/** Alias to the right-hand input data type. */
69+
typedef typename Op::D2 right_type;
70+
71+
/** Alias to the output data type. */
72+
typedef typename Op::D3 result_type;
73+
74+
/** Whether this operator has an inplace foldl. */
75+
static constexpr bool has_foldl = Op::operator_type::has_foldl;
76+
77+
/** Whether this operator has an inplace foldr. */
78+
static constexpr bool has_foldr = Op::operator_type::has_foldr;
79+
80+
/**
81+
* Whether this operator is \em mathematically associative; that is,
82+
* associative when assuming equivalent data types for \a IN1, \a IN2,
83+
* and \a OUT, as well as assuming exact arithmetic, no overflows, etc.
84+
*/
85+
static constexpr bool is_associative = Op::operator_type::is_associative;
86+
87+
/**
88+
* Whether this operator is \em mathematically commutative; that is,
89+
* commutative when assuming equivalent data types for \a IN1, \a IN2,
90+
* and \a OUT, as well as assuming exact arithmetic, no overflows, etc.
91+
*/
92+
static constexpr bool is_commutative = Op::operator_type::is_commutative;
93+
94+
/**
95+
* Out-of-place application of the operator.
96+
*
97+
* @param[in] a The left-hand side input. Must be pre-allocated and
98+
* initialised.
99+
* @param[in] b The right-hand side input. Must be pre-allocated and
100+
* initialised.
101+
* @param[out] c The output. Must be pre-allocated.
102+
*/
103+
static void apply(
104+
const left_type * __restrict__ const a,
105+
const right_type * __restrict__ const b,
106+
result_type * __restrict__ const c
107+
) {
108+
109+
Op::operator_type::apply( a, b, c );
110+
*c = !*c;
111+
112+
}
113+
114+
/**
115+
* In-place left-to-right folding.
116+
*
117+
* @param[in] a Pointer to the left-hand side input data.
118+
* @param[in,out] c Pointer to the right-hand side input data. This also
119+
* dubs as the output memory area.
120+
*/
121+
static void foldr(
122+
const left_type * __restrict__ const a,
123+
result_type * __restrict__ const c
124+
) {
125+
126+
Op::operator_type::foldr( a, c );
127+
*c = !*c;
128+
129+
}
130+
131+
/**
132+
* In-place right-to-left folding.
133+
*
134+
* @param[in,out] c Pointer to the left-hand side input data. This also
135+
* dubs as the output memory area.
136+
* @param[in] b Pointer to the right-hand side input data.
137+
*/
138+
static void foldl(
139+
result_type * __restrict__ const c,
140+
const right_type * __restrict__ const b
141+
) {
142+
143+
Op::operator_type::foldl( c, b );
144+
*c = !*c;
145+
146+
}
147+
};
148+
149+
template< class Op >
150+
class not_op : public negate< Op > {};
151+
152+
45153
/**
46154
* Standard argmin operator.
47155
*
@@ -4179,6 +4287,9 @@ namespace grb {
41794287
/** The output domain of this operator. */
41804288
typedef typename OperatorBase< OP >::D3 D3;
41814289

4290+
/** The type of the operator OP. */
4291+
typedef OP operator_type;
4292+
41824293
/**
41834294
* Reduces a vector of type \a InputType into a value in \a IOType
41844295
* by repeated application of this operator. The \a IOType is cast

0 commit comments

Comments
 (0)