ALP User Documentation  0.8.preview
Algebraic Programming User Documentation
kcore_decomposition.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 
28 #ifndef _H_GRB_KCORE_DECOMPOSITION
29 #define _H_GRB_KCORE_DECOMPOSITION
30 
31 #include <graphblas.hpp>
32 
33 
34 namespace grb {
35 
36  namespace algorithms {
37 
136  template<
138  bool criticalSection = false,
139  typename IOType, typename NZType
140  >
142  const Matrix< NZType > &A,
143  Vector< IOType > &core,
144  Vector< IOType > &distances,
145  Vector< IOType > &temp,
146  Vector< IOType > &update,
147  Vector< bool > &status,
148  IOType &k
149  ) {
150  // Add constants/expressions
151  Semiring<
154  > ring;
155  Monoid<
158  > lorMonoid;
159 
160  // Runtime sanity checks
161  const size_t n = nrows(A);
162  {
163  // Verify that A is square
164  if( n != ncols( A )){
165  return ILLEGAL;
166  }
167  // Verify sizes of vectors
168  if( size( core ) != n ||
169  size( distances ) != n ||
170  size( temp ) != n ||
171  size( update ) != n ||
172  size( status ) != n
173  ) {
174  return MISMATCH;
175  }
176  // Verify capacity
177  if( capacity( core ) != n ||
178  capacity( distances ) != n ||
179  capacity( temp ) != n ||
180  capacity( update ) != n ||
181  capacity( status ) != n
182  ) {
183  return ILLEGAL;
184  }
185  }
186 
187  // Initialise
188  IOType current_k = 0; // current coreness level
189 
190  // Set initial values
191  RC ret = grb::SUCCESS;
192  ret = ret ? ret : set( temp, static_cast< IOType >( 1 ) );
193  ret = ret ? ret : set( distances, static_cast< IOType >( 0 ) );
194  ret = ret ? ret : set( core, static_cast< IOType >( 0 ) );
195  ret = ret ? ret : set( status, true );
196  ret = ret ? ret : clear( update );
197  assert( ret == SUCCESS );
198 
199  ret = ret ? ret : grb::mxv< descr | descriptors::dense >(
200  distances, A, temp, ring );
201  assert( ret == SUCCESS );
202 
203  if( SUCCESS != ret ) {
204  std::cerr << " Initialization of k-core decomposition failed with error "
205  << grb::toString( ret ) << "\n";
206  return ret;
207  }
208 
209  size_t count = 0;
210  while( count < n && SUCCESS == ret ) {
211  bool flag = true;
212 
213  // Update filter to exclude completed nodes
214  ret = ret ? ret : set( update, status, status );
215 
216  while( flag ) {
217  flag = false;
218 
219  // Update nodes in parallel
220  if( criticalSection ) {
221  ret = ret ? ret : clear( temp );
222  ret = ret ? ret : eWiseLambda( [ &, current_k ]( const size_t i ) {
223  if( status[ i ] && distances[ i ] <= current_k ) {
224  core[ i ] = current_k;
225  // Remove node from checking
226  status[ i ] = false;
227  // Set update
228  flag = true;
229  #pragma omp critical
230  {
231  // Add node index to update neighbours
232  setElement( temp, 1, i );
233  }
234  }
235  }, update,
236  status, distances, core, temp
237  );
238  // WARN: even with the below, this variant does not auto-parallelise in
239  // the distributed-memory sense. The reason is a performance
240  // contract violation by the above critical section -- setElement
241  // should be a collective call, but its use from within eWiseLambda
242  // does not ensure a collective call. The result is that PANIC will
243  // at some point be returned.
244  //ret = ret ? ret : collectives<>::allreduce( flag,
245  // lorMonoid.getOperator() );
246  } else {
247  ret = ret ? ret : eWiseApply( temp, status, distances, current_k,
249  ret = ret ? ret : foldl( core, temp, current_k,
251  ret = ret ? ret : foldl( status, temp, false,
253  ret = ret ? ret : foldl( flag, temp, lorMonoid );
254  ret = ret ? ret : set( update, temp, 1 );
255  if( ret == SUCCESS ) {
256  std::swap( update, temp );
257  }
258  }
259  assert( ret == SUCCESS );
260 
261  if( ret == SUCCESS && flag ) {
262  ret = clear( update );
263  assert( ret == SUCCESS );
264 
265  // Increase number of nodes completed
266  count += nnz( temp );
267 
268  // Get the neighbours of the updated nodes
269  ret = ret ? ret : grb::mxv< descr >( update, A, temp, ring );
270  assert( ret == SUCCESS );
271 
272  // Decrease distances of the neighbours
273  ret = ret ? ret : grb::eWiseApply( distances, distances, update,
275  assert( ret == SUCCESS );
276  }
277  }
278  (void) ++current_k;
279  }
280 
281  if( SUCCESS != ret ){
282  std::cerr << " Excecution of k-core decomposition failed with error "
283  << grb::toString(ret) << "\n";
284  } else {
285  k = current_k;
286  }
287 
288  return ret;
289  }
290 
291  } // namespace algorithms
292 
293 } // namespace grb
294 
295 #endif // end _H_GRB_KCORE_DECOMPOSITION
296 
RC eWiseApply(Vector< OutputType, backend, Coords > &z, const InputType1 alpha, const InputType2 beta, const OP &op=OP(), 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_operator< OP >::value, void >::type *const =nullptr)
Computes , out of place, operator version.
Definition: blas1.hpp:208
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:858
Standard identity for numerical addition.
Definition: identities.hpp:57
A call to a primitive has determined that one of its arguments was illegal as per the specification o...
Definition: rc.hpp:143
An ALP/GraphBLAS matrix.
Definition: matrix.hpp:72
RC
Return codes of ALP primitives.
Definition: rc.hpp:47
A GraphBLAS vector.
Definition: vector.hpp:64
Standard identity for numerical multiplication.
Definition: identities.hpp:79
Numerical substraction of two numbers.
Definition: ops.hpp:301
This operation returns whether the left operand compares less-than or equal to the right operand.
Definition: ops.hpp:736
size_t nnz(const Vector< DataType, backend, Coords > &x) noexcept
Request the number of nonzeroes in a given vector.
Definition: io.hpp:479
static constexpr Descriptor no_operation
Indicates no additional pre- or post-processing on any of the GraphBLAS function arguments.
Definition: descriptors.hpp:63
This operator multiplies the two input parameters and writes the result to the output variable.
Definition: ops.hpp:208
unsigned int Descriptor
Descriptors indicate pre- or post-processing for some or all of the arguments to an ALP/GraphBLAS cal...
Definition: descriptors.hpp:54
size_t nrows(const Matrix< InputType, backend, RIT, CIT, NIT > &A) noexcept
Requests the row size of a given matrix.
Definition: io.hpp:286
Standard identitity for the logical or operator.
Definition: identities.hpp:151
size_t ncols(const Matrix< InputType, backend, RIT, CIT, NIT > &A) noexcept
Requests the column size of a given matrix.
Definition: io.hpp:339
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
This operator discards all left-hand side input and simply copies the right-hand side input to the ou...
Definition: ops.hpp:115
This operator takes the sum of the two input parameters and writes it to the output variable.
Definition: ops.hpp:175
The ALP/GraphBLAS namespace.
Definition: graphblas.hpp:477
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
size_t size(const Vector< DataType, backend, Coords > &x) noexcept
Request the size of a given vector.
Definition: io.hpp:235
RC kcore_decomposition(const Matrix< NZType > &A, Vector< IOType > &core, Vector< IOType > &distances, Vector< IOType > &temp, Vector< IOType > &update, Vector< bool > &status, IOType &k)
The -core decomposition algorithm.
Definition: kcore_decomposition.hpp:141
Indicates the primitive has executed successfully.
Definition: rc.hpp:54
size_t capacity(const Vector< InputType, backend, Coords > &x) noexcept
Queries the capacity of the given ALP/GraphBLAS container.
Definition: io.hpp:388
The logical or.
Definition: ops.hpp:462
A generalised semiring.
Definition: semiring.hpp:190
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:1129
RC clear(Vector< DataType, backend, Coords > &x) noexcept
Clears a given vector of all nonzeroes.
Definition: io.hpp:574
One or more of the ALP/GraphBLAS objects passed to the primitive that returned this error have mismat...
Definition: rc.hpp:90
std::string toString(const RC code)
A generalised monoid.
Definition: monoid.hpp:54