ALP User Documentation 0.7.0
Algebraic Programming User Documentation
label.hpp
Go to the documentation of this file.
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
27#ifndef _H_GRB_LABEL
28#define _H_GRB_LABEL
29
30#include <iostream>
31
32#include <graphblas.hpp>
33
34
35namespace grb {
36
37 namespace algorithms {
38
39#ifdef _DEBUG
40 constexpr size_t MaxPrinting = 20;
41 constexpr size_t MaxAnyPrinting = 100;
42
43 // take a vector and display with a message
44 static void printVector(
45 const Vector< double > &v, const std::string message
46 ) {
47 size_t zeros = 0;
48 size_t ones = 0;
49 size_t size = grb::size( v );
50 if( size > MaxAnyPrinting ) {
51 return;
52 }
53 std::cerr << "\t " << message << ": ";
54 for( Vector< double >::const_iterator it = v.begin(); it != v.end(); ++it ) {
55 const std::pair< size_t, double > iter = *it;
56 const double val = iter.second;
57 if( val < INFINITY ) {
58 if( size > MaxPrinting ) {
59 zeros += ( val == 0 ) ? 1 : 0;
60 ones += ( val == 1 ) ? 1 : 0;
61 } else {
62 std::cerr << val << " ";
63 }
64 }
65 }
66 if( size > MaxPrinting ) {
67 std::cerr << zeros << " zeros; " << ones << " ones.";
68 }
69 std::cerr << "\n";
70 }
71#endif
72
122 template< typename IOType >
124 Vector< IOType > &out,
125 const Vector< IOType > &y, const Matrix< IOType > &W,
126 const size_t n, const size_t l,
127 const size_t maxIterations = 1000
128 ) {
129 // label propagation vectors and matrices operate over the real domain
130 Semiring<
133 > reals;
138 > orMonoid;
139 const IOType zero = reals.template getZero< IOType >();
140
141 // dynamic checks
142 if( nrows( W ) != n || ncols( W ) != n ||
143 size( y ) != n || size( out ) != n
144 ) {
145 return ILLEGAL;
146 }
147 if( capacity( out ) != n ) {
148 return ILLEGAL;
149 }
150 if( n == 0 ) {
151 return SUCCESS;
152 }
153 if( l == 0 ) {
154 return ILLEGAL;
155 }
156
157 const size_t s = spmd<>::pid();
158
159 // compute the diagonal matrix D from the weight matrix W
160 // we represent D as a vector so we can use it to generate the probabilities
161 // matrix P
162 Vector< IOType > multiplier( n );
163 RC ret = set( multiplier, static_cast< IOType >(1) ); // a vector of 1's
164
165 Vector< IOType > diagonals( n );
166 ret = ret ? ret : set( diagonals, zero );
167 ret = ret ? ret : mxv< descriptors::dense >(
168 diagonals, W, multiplier, reals
169 ); // W*multiplier will sum each row
170#ifdef _DEBUG
171 printVector( diagonals, "diagonals matrix in vector form" );
172#endif
173
174 // compute the probabilistic transition matrix P as inverse of D * W
175 // use diagonals vector to directly compute probabilistic transition matrix P
176 // only the existing non-zero elements in W will map to P
177 // the inverse of D is represented via the inverse element in the diagonals
178 // vector
179 //
180 // update: the application of Dinv is now done within a lambda following the
181 // mxv on the original matrix P
182
183 // make diagonals equal its inverse
184 ret = ret ? ret : eWiseLambda( [ &diagonals ]( const size_t i ) {
185 diagonals[ i ] = 1.0 / diagonals[ i ];
186 }, diagonals
187 );
188
189 // set up current and new solution functions
190 Vector< IOType > f( n );
191 Vector< IOType > fNext( n );
192 Vector< bool > mask( n );
193 for( size_t i = 0; ret == SUCCESS && i < l; ++i ) {
194 ret = setElement( mask, true, i );
195 }
196
197 // fix f = y for the input set of labels
198 ret = ret ? ret : set( f, y );
199
200 // whether two successive solutions are different
201 // initially set to true so that the computation may begin
202 bool different = true;
203 // compute f as P*f
204 // main loop completes when function f is stable
205 size_t iter = 1;
206 while( ret == SUCCESS && different && iter < maxIterations ) {
207
208#ifdef _DEBUG
209 if( n < MaxAnyPrinting ) {
210 std::cerr << "\t iteration " << iter << "\n";
211 }
212
213 // fNext = P*f
214 std::cerr << "\t pre- set/mxv nnz( f ) = " << nnz( f ) << ", "
215 << "fNext = " << nnz( fNext ) << "\n";
216#endif
217 ret = ret ? ret : set( fNext, zero );
218 ret = ret ? ret : mxv( fNext, W, f, reals );
219#ifdef _DEBUG
220 std::cerr << "\t post-set/mxv nnz( f ) = " << nnz( f ) << ", "
221 << "nnz( fNext ) = " << nnz( fNext ) << "\n";
222 printVector( f, "Previous iteration solution" );
223 printVector( fNext, "New iteration solution" );
224#endif
225
226 // maintain the solution function in domain {0,1}
227 // can use the masked variant of vector assign when available ?
228 ret = ret ? ret : eWiseLambda( [ &fNext, &diagonals ]( const size_t i ) {
229 fNext[ i ] = ( fNext[ i ] * diagonals[ i ] < 0.5 ? 0 : 1 );
230 }, diagonals, fNext
231 );
232#ifdef _DEBUG
233 printVector( fNext, "New iteration solution after threshold cutoff" );
234 std::cerr << "\t pre-set nnz( fNext ) = " << nnz( fNext ) << ", "
235 << "nnz( mask ) = " << nnz( mask ) << "\n";
236#endif
237 // clamps the first l labelled nodes
238 ret = ret ? ret : foldl(
239 fNext, mask,
240 f,
242 );
243 assert( ret == SUCCESS );
244#ifdef _DEBUG
245 std::cerr << "\t post-set nnz( fNext ) = " << nnz( fNext ) << "\n";
246 printVector(
247 fNext,
248 "New iteration solution after threshold cutoff and clamping"
249 );
250#endif
251 // test for stability
252 different = false;
253 ret = ret ? ret : dot( different, f, fNext, orMonoid, notEqualOp );
254
255 // update f for the next iteration
256#ifdef _DEBUG
257 std::cerr << "\t pre-set nnz(f) = " << nnz( f ) << "\n";
258#endif
259 std::swap( f, fNext );
260#ifdef _DEBUG
261 std::cerr << "\t post-set nnz(f) = " << nnz( f ) << "\n";
262#endif
263 // go to next iteration
264 (void) ++iter;
265 }
266
267 if( ret == SUCCESS ) {
268 if( different ) {
269 if( s == 0 ) {
270 std::cerr << "Info: label propagation did not converge after "
271 << (iter-1) << " iterations\n";
272 }
273 return FAILED;
274 } else {
275 if( s == 0 ) {
276 std::cerr << "Info: label propagation converged in "
277 << (iter-1) << " iterations\n";
278 }
279 std::swap( out, f );
280 return SUCCESS;
281 }
282 }
283
284 // done
285 if( s == 0 ) {
286 std::cerr << "Warning: label propagation exiting with " << toString(ret)
287 << "\n";
288 }
289 return ret;
290 }
291
292 } // namespace algorithms
293
294} // namespace grb
295
296#endif // end _H_GRB_LABEL
297
An ALP/GraphBLAS matrix.
Definition: matrix.hpp:71
A generalised monoid.
Definition: monoid.hpp:54
A generalised semiring.
Definition: semiring.hpp:186
A GraphBLAS vector.
Definition: vector.hpp:64
Standard identitity for the logical or operator.
Definition: identities.hpp:151
Standard identity for numerical multiplication.
Definition: identities.hpp:79
Standard identity for numerical addition.
Definition: identities.hpp:57
This operator takes the sum of the two input parameters and writes it to the output variable.
Definition: ops.hpp:177
The logical or.
Definition: ops.hpp:464
This operator multiplies the two input parameters and writes the result to the output variable.
Definition: ops.hpp:210
Operator that returns false whenever its inputs compare equal, and true otherwise.
Definition: ops.hpp:407
This operator discards all left-hand side input and simply copies the right-hand side input to the ou...
Definition: ops.hpp:117
static size_t pid() noexcept
Definition: spmd.hpp:61
The main header to include in order to use the ALP/GraphBLAS API.
RC eWiseLambda(const Func f, const Vector< DataType, backend, Coords > &x, Args...)
Executes an arbitrary element-wise user-defined function f on any number of vectors of equal length.
Definition: blas1.hpp:3746
RC foldl(IOType &x, const Vector< InputType, backend, Coords > &y, const Vector< MaskType, backend, Coords > &mask, const Monoid &monoid=Monoid(), const typename std::enable_if< !grb::is_object< IOType >::value &&!grb::is_object< InputType >::value &&!grb::is_object< MaskType >::value &&grb::is_monoid< Monoid >::value, void >::type *const =nullptr)
Reduces, or folds, a vector into a scalar.
Definition: blas1.hpp:3840
RC dot(OutputType &z, const Vector< InputType1, backend, Coords > &x, const Vector< InputType2, backend, Coords > &y, const AddMonoid &addMonoid=AddMonoid(), const AnyOp &anyOp=AnyOp(), const Phase &phase=EXECUTE, const typename std::enable_if< !grb::is_object< OutputType >::value &&!grb::is_object< InputType1 >::value &&!grb::is_object< InputType2 >::value &&grb::is_monoid< AddMonoid >::value &&grb::is_operator< AnyOp >::value, void >::type *const =nullptr)
Calculates the dot product, , under a given additive monoid and multiplicative operator.
Definition: blas1.hpp:4056
RC mxv(Vector< IOType, backend, Coords > &u, const Vector< InputType3, backend, Coords > &u_mask, const Matrix< InputType2, backend, RIT, CIT, NIT > &A, const Vector< InputType1, backend, Coords > &v, const Vector< InputType4, backend, Coords > &v_mask, const Semiring &semiring=Semiring(), const Phase &phase=EXECUTE, const typename std::enable_if< grb::is_semiring< Semiring >::value &&!grb::is_object< IOType >::value &&!grb::is_object< InputType1 >::value &&!grb::is_object< InputType2 >::value &&!grb::is_object< InputType3 >::value &&!grb::is_object< InputType4 >::value, void >::type *const =nullptr)
Right-handed in-place doubly-masked sparse matrix times vector multiplication, .
Definition: blas2.hpp:243
RC set(Vector< DataType, backend, Coords > &x, const T val, const Phase &phase=EXECUTE, const typename std::enable_if< !grb::is_object< DataType >::value &&!grb::is_object< T >::value, void >::type *const =nullptr) noexcept
Sets all elements of a vector to the given value.
Definition: io.hpp:857
size_t nnz(const Vector< DataType, backend, Coords > &x) noexcept
Request the number of nonzeroes in a given vector.
Definition: io.hpp:479
size_t size(const Vector< DataType, backend, Coords > &x) noexcept
Request the size of a given vector.
Definition: io.hpp:235
size_t ncols(const Matrix< InputType, backend, RIT, CIT, NIT > &A) noexcept
Requests the column size of a given matrix.
Definition: io.hpp:339
size_t capacity(const Vector< InputType, backend, Coords > &x) noexcept
Queries the capacity of the given ALP/GraphBLAS container.
Definition: io.hpp:388
RC setElement(Vector< DataType, backend, Coords > &x, const T val, const size_t i, const Phase &phase=EXECUTE, const typename std::enable_if< !grb::is_object< DataType >::value &&!grb::is_object< T >::value, void >::type *const =nullptr)
Sets the element of a given vector at a given position to a given value.
Definition: io.hpp:1128
size_t nrows(const Matrix< InputType, backend, RIT, CIT, NIT > &A) noexcept
Requests the row size of a given matrix.
Definition: io.hpp:286
RC label(Vector< IOType > &out, const Vector< IOType > &y, const Matrix< IOType > &W, const size_t n, const size_t l, const size_t maxIterations=1000)
The label propagation algorithm.
Definition: label.hpp:123
The ALP/GraphBLAS namespace.
Definition: graphblas.hpp:452
RC
Return codes of ALP primitives.
Definition: rc.hpp:47
@ ILLEGAL
A call to a primitive has determined that one of its arguments was illegal as per the specification o...
Definition: rc.hpp:143
@ SUCCESS
Indicates the primitive has executed successfully.
Definition: rc.hpp:54
@ FAILED
Indicates when one of the grb::algorithms has failed to achieve its intended result,...
Definition: rc.hpp:154
std::string toString(const RC code)