kronecker_delta.h
Go to the documentation of this file.
1 /*
2  * This file is a part of TiledArray.
3  * Copyright (C) 2015 Virginia Tech
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  *
18  */
19 
20 #ifndef TILEDARRAY_SPECIAL_KRONECKER_DELTA_H__INCLUDED
21 #define TILEDARRAY_SPECIAL_KRONECKER_DELTA_H__INCLUDED
22 
23 #include <memory>
24 #include <tuple>
25 
26 #include <tiledarray_fwd.h>
27 
29 
30 // Array class
31 #include <TiledArray/permutation.h>
32 #include <TiledArray/tensor.h>
33 #include <TiledArray/tile.h>
35 
36 // Array policy classes
39 
41 
51 template <unsigned _N = 1>
53  public:
54  // Constants
55  static constexpr unsigned N = _N;
56  // Concept typedefs
57  typedef TiledArray::Range range_type; // range type
58  typedef int value_type; // Element type
59  typedef value_type
60  numeric_type; // The scalar type that is compatible with value_type
61  typedef size_t size_type; // Size type
62 
63  private:
64  range_type range_;
65  bool empty_;
66 
67  public:
69  KroneckerDeltaTile() : empty_(true) {}
70 
73  : range_(range), empty_(is_empty(range_)) {}
74 
77 
80 
83  KroneckerDeltaTile result(*this);
84  return result;
85  }
86 
87  range_type range() const { return range_; }
88 
89  bool empty() const { return empty_; }
90 
92  template <typename Archive>
93  void serialize(Archive& ar) {
94  std::cout << "KroneckerDelta::serialize not implemented by design!"
95  << std::endl;
96  abort(); // should never travel
97  }
98 
99  private:
101  static bool is_empty(const range_type& range) {
102  bool empty = false;
103  TA_ASSERT(range.rank() == 2 * N);
104  auto lobound = range.lobound_data();
105  auto upbound = range.upbound_data();
106  for (auto i = 0; i != 2 * N && not empty; i += 2)
107  empty = (upbound[i] > lobound[i + 1] && upbound[i + 1] > lobound[i])
108  ? true
109  : false; // assumes extents > 0
110  return empty;
111  }
112 
113 }; // class KroneckerDeltaTile
114 
115 // these are to satisfy interfaces, but not needed, actually
116 
117 // Sum of hyper diagonal elements
118 template <unsigned _N>
120  const KroneckerDeltaTile<_N>& arg);
121 // foreach(i) result += arg[i]
122 template <unsigned _N>
124  const KroneckerDeltaTile<_N>& arg);
125 // foreach(i) result *= arg[i]
126 template <unsigned _N>
128  const KroneckerDeltaTile<_N>& arg);
129 // foreach(i) result += arg[i] * arg[i]
130 template <unsigned _N>
132  const KroneckerDeltaTile<_N>& arg);
133 // foreach(i) result = min(result, arg[i])
134 template <unsigned _N>
136  const KroneckerDeltaTile<_N>& arg);
137 // foreach(i) result = max(result, arg[i])
138 template <unsigned _N>
140  const KroneckerDeltaTile<_N>& arg);
141 // foreach(i) result = abs_min(result, arg[i])
142 template <unsigned _N>
144  const KroneckerDeltaTile<_N>& arg);
145 // foreach(i) result = abs_max(result, arg[i])
146 template <unsigned _N>
148  const KroneckerDeltaTile<_N>& arg);
149 
150 // Permutation operation
151 
152 // returns a tile for which result[perm ^ i] = tile[i]
153 template <
154  unsigned N, typename Perm,
155  typename = std::enable_if_t<TiledArray::detail::is_permutation_v<Perm>>>
157  const Perm& perm) {
158  abort();
159 }
160 
161 // dense_result[i] = dense_arg1[i] * sparse_arg2[i]
162 template <typename T, unsigned _N>
164  const TiledArray::Tensor<T>& arg2) {
165  abort();
166 }
167 // dense_result[perm ^ i] = dense_arg1[i] * sparse_arg2[i]
168 template <
169  typename T, unsigned _N, typename Perm,
170  typename = std::enable_if_t<TiledArray::detail::is_permutation_v<Perm>>>
172  const TiledArray::Tensor<T>& arg2,
173  const Perm& perm) {
174  abort();
175 }
176 
177 // dense_result[i] *= sparse_arg1[i]
178 template <typename T, unsigned N>
180  const KroneckerDeltaTile<N>& arg1) {
181  abort();
182  return result;
183 }
184 
185 // dense_result[i] = binary(dense_arg1[i], sparse_arg2[i], op)
186 template <typename T, unsigned _N, typename Op>
188  const TiledArray::Tensor<T>& arg2, Op&& op) {
189  abort();
190 }
191 // dense_result[perm ^ i] = binary(dense_arg1[i], sparse_arg2[i], op)
192 template <
193  typename T, unsigned _N, typename Op, typename Perm,
194  typename = std::enable_if_t<TiledArray::detail::is_permutation_v<Perm>>>
196  const TiledArray::Tensor<T>& arg2, Op&& op,
197  const Perm& perm) {
198  abort();
199 }
200 
201 // Contraction operation
202 
203 // GEMM operation with fused indices as defined by gemm_config:
204 // dense_result[i,j] = dense_arg1[i,k] * sparse_arg2[k,j]
205 template <typename T, unsigned N>
207  const KroneckerDeltaTile<N>& arg1, const TiledArray::Tensor<T>& arg2,
208  const typename TiledArray::Tensor<T>::numeric_type factor,
209  const TiledArray::math::GemmHelper& gemm_config) {
210  // preconditions:
211  // 1. implemented only outer product
212  assert(gemm_config.result_rank() ==
213  gemm_config.left_rank() + gemm_config.right_rank());
214 
215  auto arg1_range = arg1.range();
216  auto arg2_range = arg2.range();
217  auto result_range =
218  gemm_config.make_result_range<TiledArray::Range>(arg1_range, arg2_range);
219  TiledArray::Tensor<T> result(result_range, 0);
220 
221  auto result_data = result.data();
222  auto arg1_extents = arg1_range.extent_data();
223  auto arg2_data = arg2.data();
224  auto arg2_volume = arg2_range.volume();
225 
226  if (not arg1.empty()) {
227  switch (N) {
228  case 1: {
229  auto i0_range = std::min(arg1_extents[0], arg1_extents[1]);
230  for (decltype(i0_range) i0 = 0; i0 != i0_range; ++i0) {
231  auto result_i0i0_ptr =
232  result_data + (i0 * arg1_extents[1] + i0) * arg2_volume;
233  std::copy(arg2_data, arg2_data + arg2_volume, result_i0i0_ptr);
234  }
235  } break;
236  case 2: {
237  auto i0_range = std::min(arg1_extents[0], arg1_extents[1]);
238  auto i1_range = std::min(arg1_extents[2], arg1_extents[3]);
239  auto ndim23 = arg1_extents[2] * arg1_extents[3];
240  for (decltype(i0_range) i0 = 0; i0 != i0_range; ++i0) {
241  auto result_i0i0i1i1_ptr_offset =
242  result_data + (i0 * arg1_extents[1] + i0) * ndim23 * arg2_volume;
243  for (decltype(i1_range) i1 = 0; i1 != i1_range; ++i1) {
244  auto result_i0i0i1i1_ptr =
245  result_i0i0i1i1_ptr_offset +
246  (i1 * arg1_extents[3] + i1) * arg2_volume;
247  std::copy(arg2_data, arg2_data + arg2_volume, result_i0i0i1i1_ptr);
248  }
249  }
250  } break;
251 
252  default:
253  abort(); // not implemented
254  }
255  }
256 
257  return result;
258 }
259 // GEMM operation with fused indices as defined by gemm_config:
260 // dense_result[i,j] += dense_arg1[i,k] * sparse_arg2[k,j]
261 template <typename T, unsigned N>
263  const TiledArray::Tensor<T>& arg2,
264  const typename TiledArray::Tensor<T>::numeric_type factor,
265  const TiledArray::math::GemmHelper& gemm_config) {
266  abort();
267 }
268 
269 #endif // TILEDARRAY_TEST_SPARSE_TILE_H__INCLUDED
R make_result_range(const Left &left, const Right &right) const
Construct a result range based on left and right ranges.
Definition: gemm_helper.h:165
TiledArray::detail::numeric_type< T >::type numeric_type
the numeric type that supports T
Definition: tensor.h:79
const index1_type * lobound_data() const
Range lower bound data accessor.
Definition: range.h:685
Contraction to *GEMM helper.
Definition: gemm_helper.h:40
::blas::Op Op
Definition: blas.h:46
unsigned int left_rank() const
Left-hand argument rank accessor.
Definition: gemm_helper.h:138
KroneckerDeltaTile< _N >::numeric_type trace(const KroneckerDeltaTile< _N > &arg)
const range_type & range() const
Tensor range object accessor.
Definition: tensor.h:384
range_type range() const
KroneckerDeltaTile< _N >::numeric_type min(const KroneckerDeltaTile< _N > &arg)
static constexpr unsigned N
generalized (asymmetric) Kronecker delta
value_type numeric_type
const index1_type * upbound_data() const
Range upper bound data accessor.
Definition: range.h:710
KroneckerDeltaTile(const KroneckerDeltaTile &)=default
copy constructor (= deep copy)
TiledArray::Tensor< T > gemm(const KroneckerDeltaTile< N > &arg1, const TiledArray::Tensor< T > &arg2, const typename TiledArray::Tensor< T >::numeric_type factor, const TiledArray::math::GemmHelper &gemm_config)
TiledArray::Tensor< T > mult(const KroneckerDeltaTile< _N > &arg1, const TiledArray::Tensor< T > &arg2)
const_pointer data() const
Data direct access.
Definition: tensor.h:609
KroneckerDeltaTile< N > permute(const KroneckerDeltaTile< N > &tile, const Perm &perm)
KroneckerDeltaTile< _N >::numeric_type squared_norm(const KroneckerDeltaTile< _N > &arg)
void serialize(Archive &ar)
MADNESS compliant serialization.
#define TA_ASSERT(EXPR,...)
Definition: error.h:39
unsigned int result_rank() const
Result rank accessor.
Definition: gemm_helper.h:133
KroneckerDeltaTile< _N >::numeric_type product(const KroneckerDeltaTile< _N > &arg)
bool empty() const
KroneckerDeltaTile< _N >::numeric_type max(const KroneckerDeltaTile< _N > &arg)
TiledArray::Tensor< T > & mult_to(TiledArray::Tensor< T > &result, const KroneckerDeltaTile< N > &arg1)
TiledArray::Tensor< T > binary(const KroneckerDeltaTile< _N > &arg1, const TiledArray::Tensor< T > &arg2, Op &&op)
KroneckerDeltaTile(const range_type &range)
Productive ctor 1.
KroneckerDeltaTile clone() const
clone = copy
unsigned int right_rank() const
Right-hand argument rank accessor.
Definition: gemm_helper.h:143
KroneckerDeltaTile< _N >::numeric_type sum(const KroneckerDeltaTile< _N > &arg)
TiledArray::Range range_type
KroneckerDeltaTile< _N >::numeric_type abs_max(const KroneckerDeltaTile< _N > &arg)
KroneckerDeltaTile< _N >::numeric_type abs_min(const KroneckerDeltaTile< _N > &arg)
An N-dimensional tensor object.
Definition: tensor.h:50
KroneckerDeltaTile()
default constructor makes an empty tile
KroneckerDeltaTile & operator=(const KroneckerDeltaTile &other)=default
assignment
const index1_type * extent_data() const
Range extent data accessor.
Definition: range.h:735
unsigned int rank() const
Rank accessor.
Definition: range.h:669
A (hyperrectangular) interval on , space of integer -indices.
Definition: range.h:46