Stokhos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Stokhos_FlatSparse3Tensor.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Stokhos Package
4 //
5 // Copyright 2009 NTESS and the Stokhos contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #ifndef STOKHOS_FLAT_SPARSE_3_TENSOR_HPP
11 #define STOKHOS_FLAT_SPARSE_3_TENSOR_HPP
12 
13 #include "Kokkos_Core.hpp"
14 
15 #include "Stokhos_Multiply.hpp"
16 #include "Stokhos_ProductBasis.hpp"
19 
20 
21 //----------------------------------------------------------------------------
22 //----------------------------------------------------------------------------
23 
24 namespace Stokhos {
25 
29 template< typename ValueType , class ExecutionSpace >
31 public:
32 
33  typedef ExecutionSpace execution_space ;
34  typedef typename execution_space::size_type size_type ;
35  typedef ValueType value_type ;
36 
37 private:
38 
39  typedef Kokkos::View< size_type[] , execution_space > coord_array_type ;
40  typedef Kokkos::View< value_type[], execution_space > value_array_type ;
41  typedef Kokkos::View< size_type[], execution_space > entry_array_type ;
42  typedef Kokkos::View< size_type[], execution_space > row_map_array_type ;
43 
53 
54 public:
55 
56  inline
58 
59  inline
61  m_k_coord() ,
62  m_j_coord() ,
63  m_value() ,
64  m_num_k() ,
65  m_num_j() ,
66  m_k_row_map() ,
67  m_j_row_map() ,
68  m_nnz(0) ,
69  m_flops(0) {}
70 
71  inline
73  m_k_coord( rhs.m_k_coord ) ,
74  m_j_coord( rhs.m_j_coord ) ,
75  m_value( rhs.m_value ) ,
76  m_num_k( rhs.m_num_k ) ,
77  m_num_j( rhs.m_num_j ) ,
78  m_k_row_map( rhs.m_k_row_map ) ,
79  m_j_row_map( rhs.m_j_row_map ) ,
80  m_nnz( rhs.m_nnz ) ,
81  m_flops( rhs.m_flops ) {}
82 
83  inline
85  {
86  m_k_coord = rhs.m_k_coord ;
87  m_j_coord = rhs.m_j_coord ;
88  m_value = rhs.m_value ;
89  m_num_k = rhs.m_num_k ;
90  m_num_j = rhs.m_num_j ;
91  m_k_row_map = rhs.m_k_row_map ;
92  m_j_row_map = rhs.m_j_row_map ;
93  m_nnz = rhs.m_nnz;
94  m_flops = rhs.m_flops;
95  return *this ;
96  }
97 
99  KOKKOS_INLINE_FUNCTION
100  size_type dimension() const { return m_k_row_map.extent(0) - 1 ; }
101 
103  KOKKOS_INLINE_FUNCTION
105  { return m_j_coord.extent(0); }
106 
108  KOKKOS_INLINE_FUNCTION
110  { return m_k_row_map[i]; }
111 
113  KOKKOS_INLINE_FUNCTION
115  { return m_k_row_map[i] + m_num_k(i); }
116 
118  KOKKOS_INLINE_FUNCTION
120  { return m_num_k(i); }
121 
123  KOKKOS_INLINE_FUNCTION
124  const size_type& k_coord( const size_type kEntry ) const
125  { return m_k_coord( kEntry ); }
126 
128  KOKKOS_INLINE_FUNCTION
129  size_type j_begin( size_type kEntry ) const
130  { return m_j_row_map[kEntry]; }
131 
133  KOKKOS_INLINE_FUNCTION
134  size_type j_end( size_type kEntry ) const
135  { return m_j_row_map[kEntry] + m_num_j(kEntry); }
136 
138  KOKKOS_INLINE_FUNCTION
139  size_type num_j( size_type kEntry ) const
140  { return m_num_j(kEntry); }
141 
143  KOKKOS_INLINE_FUNCTION
144  const size_type& j_coord( const size_type jEntry ) const
145  { return m_j_coord( jEntry ); }
146 
148  KOKKOS_INLINE_FUNCTION
149  const value_type & value( const size_type jEntry ) const
150  { return m_value( jEntry ); }
151 
153  KOKKOS_INLINE_FUNCTION
155  { return m_nnz; }
156 
158  KOKKOS_INLINE_FUNCTION
160  { return m_flops; }
161 
162  template <typename OrdinalType>
163  static FlatSparse3Tensor
167  {
169 
170  // Compute number of k's for each i
171  const size_type dimension = basis.size();
172  std::vector< size_t > k_coord_work( dimension , (size_t) 0 );
173  size_type k_entry_count = 0 ;
174  for (typename Cijk_type::i_iterator i_it=Cijk.i_begin();
175  i_it!=Cijk.i_end(); ++i_it) {
176  OrdinalType i = index(i_it);
177  k_coord_work[i] = Cijk.num_k(i_it);
178  k_entry_count += Cijk.num_k(i_it);
179  }
180 
181  // Compute number of j's for each i and k
182  std::vector< size_t > j_coord_work( k_entry_count , (size_t) 0 );
183  size_type j_entry_count = 0 ;
184  size_type k_entry = 0 ;
185  for (typename Cijk_type::i_iterator i_it=Cijk.i_begin();
186  i_it!=Cijk.i_end(); ++i_it) {
187  for (typename Cijk_type::ik_iterator k_it = Cijk.k_begin(i_it);
188  k_it != Cijk.k_end(i_it); ++k_it, ++k_entry) {
189  OrdinalType k = index(k_it);
190  for (typename Cijk_type::ikj_iterator j_it = Cijk.j_begin(k_it);
191  j_it != Cijk.j_end(k_it); ++j_it) {
192  OrdinalType j = index(j_it);
193  if (j >= k) {
194  ++j_coord_work[k_entry];
195  ++j_entry_count;
196  }
197  }
198  }
199  }
200 
201  /*
202  // Pad each row to have size divisible by alignment size
203  enum { Align = std::is_same<ExecutionSpace,Kokkos::Cuda>::value ? 32 : 2 };
204  for ( size_type i = 0 ; i < dimension ; ++i ) {
205  const size_t rem = coord_work[i] % Align;
206  if (rem > 0) {
207  const size_t pad = Align - rem;
208  coord_work[i] += pad;
209  entry_count += pad;
210  }
211  }
212  */
213 
214  // Allocate tensor data
215  FlatSparse3Tensor tensor ;
216  tensor.m_k_coord = coord_array_type( "k_coord" , k_entry_count );
217  tensor.m_j_coord = coord_array_type( "j_coord" , j_entry_count );
218  tensor.m_value = value_array_type( "value" , j_entry_count );
219  tensor.m_num_k = entry_array_type( "num_k" , dimension );
220  tensor.m_num_j = entry_array_type( "num_j" , k_entry_count );
221  tensor.m_k_row_map = row_map_array_type( "k_row_map" , dimension+1 );
222  tensor.m_j_row_map = row_map_array_type( "j_row_map" , k_entry_count+1 );
223 
224  // Create mirror, is a view if is host memory
225  typename coord_array_type::HostMirror
226  host_k_coord = Kokkos::create_mirror_view( tensor.m_k_coord );
227  typename coord_array_type::HostMirror
228  host_j_coord = Kokkos::create_mirror_view( tensor.m_j_coord );
229  typename value_array_type::HostMirror
230  host_value = Kokkos::create_mirror_view( tensor.m_value );
231  typename entry_array_type::HostMirror
232  host_num_k = Kokkos::create_mirror_view( tensor.m_num_k );
233  typename entry_array_type::HostMirror
234  host_num_j = Kokkos::create_mirror_view( tensor.m_num_j );
235  typename entry_array_type::HostMirror
236  host_k_row_map = Kokkos::create_mirror_view( tensor.m_k_row_map );
237  typename entry_array_type::HostMirror
238  host_j_row_map = Kokkos::create_mirror_view( tensor.m_j_row_map );
239 
240  // Compute k row map
241  size_type sum = 0;
242  host_k_row_map(0) = 0;
243  for ( size_type i = 0 ; i < dimension ; ++i ) {
244  sum += k_coord_work[i];
245  host_k_row_map(i+1) = sum;
246  host_num_k(i) = 0;
247  }
248 
249  // Compute j row map
250  sum = 0;
251  host_j_row_map(0) = 0;
252  for ( size_type i = 0 ; i < k_entry_count ; ++i ) {
253  sum += j_coord_work[i];
254  host_j_row_map(i+1) = sum;
255  host_num_j(i) = 0;
256  }
257 
258  for ( size_type i = 0 ; i < dimension ; ++i ) {
259  k_coord_work[i] = host_k_row_map[i];
260  }
261  for ( size_type i = 0 ; i < k_entry_count ; ++i ) {
262  j_coord_work[i] = host_j_row_map[i];
263  }
264 
265  for (typename Cijk_type::i_iterator i_it=Cijk.i_begin();
266  i_it!=Cijk.i_end(); ++i_it) {
267  OrdinalType i = index(i_it);
268  for (typename Cijk_type::ik_iterator k_it = Cijk.k_begin(i_it);
269  k_it != Cijk.k_end(i_it); ++k_it) {
270  OrdinalType k = index(k_it);
271  const size_type kEntry = k_coord_work[i];
272  ++k_coord_work[i];
273  host_k_coord(kEntry) = k ;
274  ++host_num_k(i);
275  for (typename Cijk_type::ikj_iterator j_it = Cijk.j_begin(k_it);
276  j_it != Cijk.j_end(k_it); ++j_it) {
277  OrdinalType j = index(j_it);
278  ValueType c = Stokhos::value(j_it);
279  if (j >= k) {
280  const size_type jEntry = j_coord_work[kEntry];
281  ++j_coord_work[kEntry];
282  host_value(jEntry) = (j != k) ? c : 0.5*c;
283  host_j_coord(jEntry) = j ;
284  ++host_num_j(kEntry);
285  ++tensor.m_nnz;
286  }
287  }
288  }
289  }
290 
291  // Copy data to device if necessary
292  Kokkos::deep_copy( tensor.m_k_coord , host_k_coord );
293  Kokkos::deep_copy( tensor.m_j_coord , host_j_coord );
294  Kokkos::deep_copy( tensor.m_value , host_value );
295  Kokkos::deep_copy( tensor.m_num_k , host_num_k );
296  Kokkos::deep_copy( tensor.m_num_j , host_num_j );
297  Kokkos::deep_copy( tensor.m_k_row_map , host_k_row_map );
298  Kokkos::deep_copy( tensor.m_j_row_map , host_j_row_map );
299 
300  tensor.m_flops = 5*tensor.m_nnz + dimension;
301 
302  return tensor ;
303  }
304 };
305 
306 template< class Device , typename OrdinalType , typename ValueType >
307 FlatSparse3Tensor<ValueType, Device>
312 {
313  return FlatSparse3Tensor<ValueType, Device>::create( basis, Cijk, params );
314 }
315 
316 template <typename ValueType, typename Device>
317 class BlockMultiply< FlatSparse3Tensor< ValueType , Device > >
318 {
319 public:
320 
321  typedef typename Device::size_type size_type ;
323 
324  template< typename MatrixValue , typename VectorValue >
325  KOKKOS_INLINE_FUNCTION
326  static void apply( const tensor_type & tensor ,
327  const MatrixValue * const a ,
328  const VectorValue * const x ,
329  VectorValue * const y )
330  {
331 
332  const size_type nDim = tensor.dimension();
333 
334  // Loop over i
335  for ( size_type i = 0; i < nDim; ++i) {
336  VectorValue ytmp = 0;
337 
338  // Loop over k for this i
339  const size_type nk = tensor.num_k(i);
340  const size_type kBeg = tensor.k_begin(i);
341  const size_type kEnd = kBeg + nk;
342  for (size_type kEntry = kBeg; kEntry < kEnd; ++kEntry) {
343  const size_type k = tensor.k_coord(kEntry);
344  const MatrixValue ak = a[k];
345  const VectorValue xk = x[k];
346 
347  // Loop over j for this i,k
348  const size_type nj = tensor.num_j(kEntry);
349  const size_type jBeg = tensor.j_begin(kEntry);
350  const size_type jEnd = jBeg + nj;
351  for (size_type jEntry = jBeg; jEntry < jEnd; ++jEntry) {
352  const size_type j = tensor.j_coord(jEntry);
353  ytmp += tensor.value(jEntry) * ( a[j] * xk + ak * x[j] );
354  }
355  }
356 
357  y[i] += ytmp ;
358  }
359  }
360 
361  KOKKOS_INLINE_FUNCTION
362  static size_type matrix_size( const tensor_type & tensor )
363  { return tensor.dimension(); }
364 
365  KOKKOS_INLINE_FUNCTION
366  static size_type vector_size( const tensor_type & tensor )
367  { return tensor.dimension(); }
368 };
369 
370 } /* namespace Stokhos */
371 
372 //----------------------------------------------------------------------------
373 //----------------------------------------------------------------------------
374 
375 #endif /* #ifndef STOKHOS_FLAT_SPARSE_3_TENSOR_HPP */
KOKKOS_INLINE_FUNCTION size_type k_end(size_type i) const
End k entries with a coordinate &#39;i&#39;.
KOKKOS_INLINE_FUNCTION size_type j_end(size_type kEntry) const
End j entries with a k entry &#39;kEntry&#39;.
KOKKOS_INLINE_FUNCTION const size_type & j_coord(const size_type jEntry) const
j coordinate for j entry &#39;jEntry&#39;
k_iterator k_begin() const
Iterator pointing to first k entry.
Data structure storing a sparse 3-tensor C(i,j,k) in a a compressed format.
KOKKOS_INLINE_FUNCTION size_type entry_count() const
Number of sparse entries.
ordinal_type num_k() const
Number of k entries in C(i,j,k)
kj_iterator j_begin(const k_iterator &k) const
Iterator pointing to first j entry for given k.
KOKKOS_INLINE_FUNCTION size_type num_non_zeros() const
Number of non-zero&#39;s.
static KOKKOS_INLINE_FUNCTION size_type matrix_size(const tensor_type &tensor)
FlatSparse3Tensor< ValueType, Device > create_flat_sparse_3_tensor(const Stokhos::ProductBasis< OrdinalType, ValueType > &basis, const Stokhos::Sparse3Tensor< OrdinalType, ValueType > &Cijk, const Teuchos::ParameterList &params=Teuchos::ParameterList())
KOKKOS_INLINE_FUNCTION size_type k_begin(size_type i) const
Begin k entries with a coordinate &#39;i&#39;.
static KOKKOS_INLINE_FUNCTION void apply(const tensor_type &tensor, const MatrixValue *const a, const VectorValue *const x, VectorValue *const y)
KOKKOS_INLINE_FUNCTION size_type num_j(size_type kEntry) const
Number of j entries with a k entry &#39;kEntry&#39;.
kj_iterator j_end(const k_iterator &k) const
Iterator pointing to last j entry for given k.
execution_space::size_type size_type
Kokkos::View< value_type[], execution_space > value_array_type
KOKKOS_INLINE_FUNCTION const size_type & k_coord(const size_type kEntry) const
k coordinate for k entry &#39;kEntry&#39;
FlatSparse3Tensor & operator=(const FlatSparse3Tensor &rhs)
KOKKOS_INLINE_FUNCTION size_type num_flops() const
Number flop&#39;s per multiply-add.
void deep_copy(const Stokhos::CrsMatrix< ValueType, DstDevice, Layout > &dst, const Stokhos::CrsMatrix< ValueType, SrcDevice, Layout > &src)
static FlatSparse3Tensor create(const Stokhos::ProductBasis< OrdinalType, ValueType > &basis, const Stokhos::Sparse3Tensor< OrdinalType, ValueType > &Cijk, const Teuchos::ParameterList &params=Teuchos::ParameterList())
k_iterator k_end() const
Iterator pointing to last k entry.
static KOKKOS_INLINE_FUNCTION size_type vector_size(const tensor_type &tensor)
Stokhos::Sparse3Tensor< int, double > Cijk_type
KOKKOS_INLINE_FUNCTION size_type num_k(size_type i) const
Number of k entries with a coordinate &#39;i&#39;.
Kokkos::View< size_type[], execution_space > entry_array_type
KOKKOS_INLINE_FUNCTION const value_type & value(const size_type jEntry) const
Value for j entry &#39;jEntry&#39;.
KOKKOS_INLINE_FUNCTION size_type dimension() const
Dimension of the tensor.
Kokkos::View< size_type[], execution_space > coord_array_type
kji_iterator i_begin(const kj_iterator &j) const
Iterator pointing to first i entry for given j and k.
FlatSparse3Tensor(const FlatSparse3Tensor &rhs)
Sparse product tensor with replicated entries to provide subsets with a given coordinate.
kji_iterator i_end(const kj_iterator &j) const
Iterator pointing to last i entry for given j and k.
KOKKOS_INLINE_FUNCTION size_type j_begin(size_type kEntry) const
Begin j entries with a k entry &#39;kEntry&#39;.
Kokkos::View< size_type[], execution_space > row_map_array_type
std::enable_if< Kokkos::is_view_uq_pce< Kokkos::View< RD, RP...> >::value &&Kokkos::is_view_uq_pce< Kokkos::View< XD, XP...> >::value >::type sum(const Kokkos::View< RD, RP...> &r, const Kokkos::View< XD, XP...> &x)
virtual ordinal_type size() const =0
Return total size of basis.
Stokhos::CrsMatrix< ValueType, Device, Layout >::HostMirror create_mirror_view(const Stokhos::CrsMatrix< ValueType, Device, Layout > &A)