Kokkos Core Kernels Package  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
Kokkos_Crs.hpp
1 /*
2 //@HEADER
3 // ************************************************************************
4 //
5 // Kokkos v. 2.0
6 // Copyright (2014) Sandia Corporation
7 //
8 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // Questions? Contact Christian R. Trott (crtrott@sandia.gov)
39 //
40 // ************************************************************************
41 //@HEADER
42 */
43 
44 #ifndef KOKKOS_CRS_HPP
45 #define KOKKOS_CRS_HPP
46 
47 namespace Kokkos {
48 
79 template< class DataType,
80  class Arg1Type,
81  class Arg2Type = void,
82  typename SizeType = typename ViewTraits<DataType*, Arg1Type, Arg2Type, void >::size_type>
83 class Crs {
84 protected:
86 
87 public:
88  typedef DataType data_type;
89  typedef typename traits::array_layout array_layout;
90  typedef typename traits::execution_space execution_space;
91  typedef typename traits::memory_space memory_space;
92  typedef typename traits::device_type device_type;
93  typedef SizeType size_type;
94 
99 
100  row_map_type row_map;
101  entries_type entries;
102 
103  /*
104  * Default Constructors, operators and destructor
105  */
106  KOKKOS_FUNCTION Crs() = default;
107  KOKKOS_FUNCTION Crs(Crs const &) = default;
108  KOKKOS_FUNCTION Crs(Crs &&) = default;
109  KOKKOS_FUNCTION Crs& operator=(Crs const &) = default;
110  KOKKOS_FUNCTION Crs& operator=(Crs &&) = default;
111  KOKKOS_FUNCTION ~Crs() = default;
112 
117  template<class EntriesType, class RowMapType>
118  KOKKOS_INLINE_FUNCTION
119  Crs(const RowMapType& row_map_, const EntriesType& entries_)
120  : row_map(row_map_), entries(entries_)
121  {
122  }
123 
126  KOKKOS_INLINE_FUNCTION
127  size_type numRows() const {
128  return (row_map.extent(0) != 0) ?
129  row_map.extent(0) - static_cast<size_type> (1) :
130  static_cast<size_type> (0);
131  }
132 };
133 
134 /*--------------------------------------------------------------------------*/
135 
136 template< class OutCounts,
137  class DataType,
138  class Arg1Type,
139  class Arg2Type,
140  class SizeType>
141 void get_crs_transpose_counts(
142  OutCounts& out,
143  Crs<DataType, Arg1Type, Arg2Type, SizeType> const& in,
144  std::string const& name = "transpose_counts");
145 
146 template< class OutCounts,
147  class InCrs>
148 typename OutCounts::value_type get_crs_row_map_from_counts(
149  OutCounts& out,
150  InCrs const& in,
151  std::string const& name = "row_map");
152 
153 template< class DataType,
154  class Arg1Type,
155  class Arg2Type,
156  class SizeType>
157 void transpose_crs(
158  Crs<DataType, Arg1Type, Arg2Type, SizeType>& out,
159  Crs<DataType, Arg1Type, Arg2Type, SizeType> const& in);
160 
161 } // namespace Kokkos
162 
163 /*--------------------------------------------------------------------------*/
164 
165 /*--------------------------------------------------------------------------*/
166 
167 namespace Kokkos {
168 namespace Impl {
169 
170 template <class InCrs, class OutCounts>
171 class GetCrsTransposeCounts {
172  public:
173  using execution_space = typename InCrs::execution_space;
174  using self_type = GetCrsTransposeCounts<InCrs, OutCounts>;
175  using index_type = typename InCrs::size_type;
176  private:
177  InCrs in;
178  OutCounts out;
179  public:
180  KOKKOS_INLINE_FUNCTION
181  void operator()(index_type i) const {
182  atomic_increment( &out[in.entries(i)] );
183  }
184  GetCrsTransposeCounts(InCrs const& arg_in, OutCounts const& arg_out):
185  in(arg_in),out(arg_out) {
186  using policy_type = RangePolicy<index_type, execution_space>;
188  const closure_type closure(*this, policy_type(0, index_type(in.entries.size())));
189  closure.execute();
190  execution_space::fence();
191  }
192 };
193 
194 template <class InCounts, class OutRowMap>
195 class CrsRowMapFromCounts {
196  public:
197  using execution_space = typename InCounts::execution_space;
198  using value_type = typename OutRowMap::value_type;
199  using index_type = typename InCounts::size_type;
200  using last_value_type = Kokkos::View<value_type, execution_space>;
201  private:
202  InCounts m_in;
203  OutRowMap m_out;
204  last_value_type m_last_value;
205  public:
206  KOKKOS_INLINE_FUNCTION
207  void operator()(index_type i, value_type& update, bool final_pass) const {
208  if (i < m_in.size()) {
209  update += m_in(i);
210  if (final_pass) m_out(i + 1) = update;
211  } else if (final_pass) {
212  m_out(0) = 0;
213  m_last_value() = update;
214  }
215  }
216  KOKKOS_INLINE_FUNCTION
217  void init(value_type& update) const { update = 0; }
218  KOKKOS_INLINE_FUNCTION
219  void join(volatile value_type& update, const volatile value_type& input) const {
220  update += input;
221  }
222  using self_type = CrsRowMapFromCounts<InCounts, OutRowMap>;
223  CrsRowMapFromCounts(InCounts const& arg_in, OutRowMap const& arg_out):
224  m_in(arg_in), m_out(arg_out), m_last_value("last_value") {
225  }
226  value_type execute() {
227  using policy_type = RangePolicy<index_type, execution_space>;
229  closure_type closure(*this, policy_type(0, m_in.size() + 1));
230  closure.execute();
231  auto last_value = Kokkos::create_mirror_view(m_last_value);
232  Kokkos::deep_copy(last_value, m_last_value);
233  return last_value();
234  }
235 };
236 
237 template <class InCrs, class OutCrs>
238 class FillCrsTransposeEntries {
239  public:
240  using execution_space = typename InCrs::execution_space;
241  using memory_space = typename InCrs::memory_space;
242  using value_type = typename OutCrs::entries_type::value_type;
243  using index_type = typename InCrs::size_type;
244  private:
245  using counters_type = View<index_type*, memory_space>;
246  InCrs in;
247  OutCrs out;
248  counters_type counters;
249  public:
250  KOKKOS_INLINE_FUNCTION
251  void operator()(index_type i) const {
252  auto begin = in.row_map(i);
253  auto end = in.row_map(i + 1);
254  for (auto j = begin; j < end; ++j) {
255  auto ti = in.entries(j);
256  auto tbegin = out.row_map(ti);
257  auto tj = atomic_fetch_add( &counters(ti), 1 );
258  out.entries( tbegin + tj ) = i;
259  }
260  }
261  using self_type = FillCrsTransposeEntries<InCrs, OutCrs>;
262  FillCrsTransposeEntries(InCrs const& arg_in, OutCrs const& arg_out):
263  in(arg_in),out(arg_out),
264  counters("counters", arg_out.numRows()) {
265  using policy_type = RangePolicy<index_type, execution_space>;
267  const closure_type closure(*this, policy_type(0, index_type(in.numRows())));
268  closure.execute();
269  execution_space::fence();
270  }
271 };
272 
273 }} // namespace Kokkos::Impl
274 
275 /*--------------------------------------------------------------------------*/
276 
277 /*--------------------------------------------------------------------------*/
278 
279 namespace Kokkos {
280 
281 template< class OutCounts,
282  class DataType,
283  class Arg1Type,
284  class Arg2Type,
285  class SizeType>
286 void get_crs_transpose_counts(
287  OutCounts& out,
288  Crs<DataType, Arg1Type, Arg2Type, SizeType> const& in,
289  std::string const& name) {
290  using InCrs = Crs<DataType, Arg1Type, Arg2Type, SizeType>;
291  out = OutCounts(name, in.numRows());
292  Kokkos::Impl::GetCrsTransposeCounts<InCrs, OutCounts> functor(in, out);
293 }
294 
295 template< class OutRowMap,
296  class InCounts>
297 typename OutRowMap::value_type get_crs_row_map_from_counts(
298  OutRowMap& out,
299  InCounts const& in,
300  std::string const& name) {
301  out = OutRowMap(ViewAllocateWithoutInitializing(name), in.size() + 1);
302  Kokkos::Impl::CrsRowMapFromCounts<InCounts, OutRowMap> functor(in, out);
303  return functor.execute();
304 }
305 
306 template< class DataType,
307  class Arg1Type,
308  class Arg2Type,
309  class SizeType>
310 void transpose_crs(
311  Crs<DataType, Arg1Type, Arg2Type, SizeType>& out,
312  Crs<DataType, Arg1Type, Arg2Type, SizeType> const& in)
313 {
314  typedef Crs<DataType, Arg1Type, Arg2Type, SizeType> crs_type ;
315  typedef typename crs_type::memory_space memory_space ;
316  typedef View<SizeType*, memory_space> counts_type ;
317  {
318  counts_type counts;
319  Kokkos::get_crs_transpose_counts(counts, in);
320  Kokkos::get_crs_row_map_from_counts(out.row_map, counts,
321  "tranpose_row_map");
322  }
323  out.entries = decltype(out.entries)("transpose_entries", in.entries.size());
324  Kokkos::Impl::
325  FillCrsTransposeEntries<crs_type, crs_type> entries_functor(in, out);
326 }
327 
328 template< class CrsType,
329  class Functor,
330  class ExecutionSpace = typename CrsType::execution_space>
331 struct CountAndFillBase;
332 
333 template< class CrsType,
334  class Functor,
335  class ExecutionSpace>
336 struct CountAndFillBase {
337  using data_type = typename CrsType::size_type;
338  using size_type = typename CrsType::size_type;
339  using row_map_type = typename CrsType::row_map_type;
340  using counts_type = row_map_type;
341  CrsType m_crs;
342  Functor m_functor;
343  counts_type m_counts;
344  struct Count {};
345  inline void operator()(Count, size_type i) const {
346  m_counts(i) = m_functor(i, nullptr);
347  }
348  struct Fill {};
349  inline void operator()(Fill, size_type i) const {
350  auto j = m_crs.row_map(i);
351  /* we don't want to access entries(entries.size()), even if its just to get its
352  address and never use it.
353  this can happen when row (i) is empty and all rows after it are also empty.
354  we could compare to row_map(i + 1), but that is a read from global memory,
355  whereas dimension_0() should be part of the View in registers (or constant memory) */
356  data_type* fill =
357  (j == static_cast<decltype(j)>(m_crs.entries.extent(0))) ?
358  nullptr : (&(m_crs.entries(j)));
359  m_functor(i, fill);
360  }
361  CountAndFillBase(CrsType& crs, Functor const& f):
362  m_crs(crs),
363  m_functor(f)
364  {}
365 };
366 
367 #if defined( KOKKOS_ENABLE_CUDA )
368 template< class CrsType,
369  class Functor>
370 struct CountAndFillBase<CrsType, Functor, Kokkos::Cuda> {
371  using data_type = typename CrsType::size_type;
372  using size_type = typename CrsType::size_type;
373  using row_map_type = typename CrsType::row_map_type;
374  using counts_type = row_map_type;
375  CrsType m_crs;
376  Functor m_functor;
377  counts_type m_counts;
378  struct Count {};
379  __device__ inline void operator()(Count, size_type i) const {
380  m_counts(i) = m_functor(i, nullptr);
381  }
382  struct Fill {};
383  __device__ inline void operator()(Fill, size_type i) const {
384  auto j = m_crs.row_map(i);
385  /* we don't want to access entries(entries.size()), even if its just to get its
386  address and never use it.
387  this can happen when row (i) is empty and all rows after it are also empty.
388  we could compare to row_map(i + 1), but that is a read from global memory,
389  whereas dimension_0() should be part of the View in registers (or constant memory) */
390  data_type* fill =
391  (j == static_cast<decltype(j)>(m_crs.entries.extent(0))) ?
392  nullptr : (&(m_crs.entries(j)));
393  m_functor(i, fill);
394  }
395  CountAndFillBase(CrsType& crs, Functor const& f):
396  m_crs(crs),
397  m_functor(f)
398  {}
399 };
400 #endif
401 
402 template< class CrsType,
403  class Functor>
404 struct CountAndFill : public CountAndFillBase<CrsType, Functor> {
405  using base_type = CountAndFillBase<CrsType, Functor>;
406  using typename base_type::data_type;
407  using typename base_type::size_type;
408  using typename base_type::counts_type;
409  using typename base_type::Count;
410  using typename base_type::Fill;
411  using entries_type = typename CrsType::entries_type;
412  using self_type = CountAndFill<CrsType, Functor>;
413  CountAndFill(CrsType& crs, size_type nrows, Functor const& f):
414  base_type(crs, f)
415  {
416  using execution_space = typename CrsType::execution_space;
417  this->m_counts = counts_type("counts", nrows);
418  {
419  using count_policy_type = RangePolicy<size_type, execution_space, Count>;
420  using count_closure_type =
422  const count_closure_type closure(*this, count_policy_type(0, nrows));
423  closure.execute();
424  }
425  auto nentries = Kokkos::
426  get_crs_row_map_from_counts(this->m_crs.row_map, this->m_counts);
427  this->m_counts = counts_type();
428  this->m_crs.entries = entries_type("entries", nentries);
429  {
430  using fill_policy_type = RangePolicy<size_type, execution_space, Fill>;
431  using fill_closure_type =
433  const fill_closure_type closure(*this, fill_policy_type(0, nrows));
434  closure.execute();
435  }
436  crs = this->m_crs;
437  }
438 };
439 
440 template< class CrsType,
441  class Functor>
442 void count_and_fill_crs(
443  CrsType& crs,
444  typename CrsType::size_type nrows,
445  Functor const& f) {
446  Kokkos::CountAndFill<CrsType, Functor>(crs, nrows, f);
447 }
448 
449 } // namespace Kokkos
450 
451 #endif /* #define KOKKOS_CRS_HPP */
Implementation detail of parallel_scan.
void deep_copy(const View< DT, DP...> &dst, typename ViewTraits< DT, DP...>::const_value_type &value, typename std::enable_if< std::is_same< typename ViewTraits< DT, DP...>::specialize, void >::value >::type *=0)
Deep copy a value from Host memory into a view.
Compressed row storage array.
Definition: Kokkos_Crs.hpp:83
KOKKOS_INLINE_FUNCTION size_type numRows() const
Return number of rows in the graph.
Definition: Kokkos_Crs.hpp:127
KOKKOS_INLINE_FUNCTION Crs(const RowMapType &row_map_, const EntriesType &entries_)
Assign to a view of the rhs array. If the old view is the last view then allocated memory is dealloca...
Definition: Kokkos_Crs.hpp:119
Implementation of the ParallelFor operator that has a partial specialization for the device...
Traits class for accessing attributes of a View.
KOKKOS_INLINE_FUNCTION constexpr std::enable_if< std::is_integral< iType >::value, size_t >::type extent(const iType &r) const noexcept
rank() to be implemented