sparse_shape.h
Go to the documentation of this file.
1 /*
2  * This file is a part of TiledArray.
3  * Copyright (C) 2013 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  * Justus Calvin
19  * Department of Chemistry, Virginia Tech
20  *
21  * sparse_shape.h
22  * Jul 9, 2013
23  *
24  */
25 
26 #ifndef TILEDARRAY_SPARSE_SHAPE_H__INCLUDED
27 #define TILEDARRAY_SPARSE_SHAPE_H__INCLUDED
28 
29 #include <TiledArray/tensor.h>
32 #include <TiledArray/tiled_range.h>
33 #include <TiledArray/val_array.h>
34 #include <typeinfo>
35 
36 namespace TiledArray {
37 
39 
73 template <typename T>
74 class SparseShape {
75  public:
77  typedef T value_type;
78  using index1_type = TA_1INDEX_TYPE;
79  static_assert(TiledArray::detail::is_scalar_v<T>,
80  "SparseShape<T> only supports scalar numeric types for T");
82 
83  private:
84  // T must be a numeric type
85  static_assert(std::is_floating_point<T>::value,
86  "SparseShape template type T must be a floating point type");
87 
88  // Internal typedefs
90 
91  Tensor<value_type> tile_norms_;
92  mutable std::unique_ptr<Tensor<value_type>> tile_norms_unscaled_ =
93  nullptr;
94  std::shared_ptr<vector_type>
95  size_vectors_;
96  size_type zero_tile_count_;
98  static value_type threshold_;
99 
100  template <typename Op>
101  static vector_type recursive_outer_product(
102  const vector_type* const size_vectors, const unsigned int dim,
103  const Op& op) {
104  vector_type result;
105 
106  if (dim == 1u) {
107  // Construct a modified copy of size_vector[0]
108  result = op(*size_vectors);
109  } else {
110  // Compute split the range and compute the outer products
111  const unsigned int middle = (dim >> 1u) + (dim & 1u);
112  const vector_type left =
113  recursive_outer_product(size_vectors, middle, op);
114  const vector_type right =
115  recursive_outer_product(size_vectors + middle, dim - middle, op);
116 
117  // Compute the outer product of left and right
118 
119  result = vector_type(left.size() * right.size());
120  result.outer_fill(left, right,
121  [](const value_type left, const value_type right) {
122  return left * right;
123  });
124  }
125 
126  return result;
127  }
128 
129  enum class ScaleBy { Volume, InverseVolume };
130 
133 
144  template <ScaleBy ScaleBy_, bool Screen = true>
145  static size_type scale_tile_norms(
146  Tensor<T>& tile_norms,
147  const vector_type* MADNESS_RESTRICT const size_vectors) {
148  const unsigned int dim = tile_norms.range().rank();
149  const value_type threshold = threshold_;
150  madness::AtomicInt zero_tile_count;
151  zero_tile_count = 0;
152 
153  if (dim == 1u) {
154  // This is the easy case where the data is a vector and can be
155  // normalized directly.
157  [threshold, &zero_tile_count](value_type& norm,
158  const value_type size) {
159  if (ScaleBy_ == ScaleBy::Volume)
160  norm *= size;
161  else
162  norm /= size;
163  if (Screen && norm < threshold) {
164  norm = value_type(0);
165  ++zero_tile_count;
166  }
167  },
168  size_vectors[0].size(), tile_norms.data(), size_vectors[0].data());
169  } else {
170  // Here the normalization constants are computed and multiplied by the
171  // norm data using a recursive, outer algorithm. This is done to
172  // minimize temporary memory requirements, memory bandwidth, and work.
173 
175  auto noop = [](const vector_type& size_vector) -> const vector_type& {
176  return size_vector;
177  };
179  auto inv_vec_op = [](const vector_type& size_vector) {
180  return vector_type(size_vector, [](const value_type size) {
181  return value_type(1) / size;
182  });
183  };
184 
185  // Compute the left and right outer products
186  const unsigned int middle = (dim >> 1u) + (dim & 1u);
187  const vector_type left =
188  ScaleBy_ == ScaleBy::Volume
189  ? recursive_outer_product(size_vectors, middle, noop)
190  : recursive_outer_product(size_vectors, middle, inv_vec_op);
191  const vector_type right =
192  ScaleBy_ == ScaleBy::Volume
193  ? recursive_outer_product(size_vectors + middle, dim - middle,
194  noop)
195  : recursive_outer_product(size_vectors + middle, dim - middle,
196  inv_vec_op);
197 
198  math::outer(
199  left.size(), right.size(), left.data(), right.data(),
200  tile_norms.data(),
201  [threshold, &zero_tile_count](value_type& norm, const value_type x,
202  const value_type y) {
203  norm *= x * y;
204  if (Screen && norm < threshold) {
205  norm = value_type(0);
206  ++zero_tile_count;
207  }
208  });
209  }
210 
211  return Screen ? zero_tile_count : 0;
212  }
213 
214  static std::shared_ptr<vector_type> initialize_size_vectors(
215  const TiledRange& trange) {
216  // Allocate memory for size vectors
217  const unsigned int dim = trange.tiles_range().rank();
218  std::shared_ptr<vector_type> size_vectors(
219  new vector_type[dim], std::default_delete<vector_type[]>());
220 
221  // Initialize the size vectors
222  for (unsigned int i = 0ul; i != dim; ++i) {
223  const size_type n = trange.data()[i].tiles_range().second -
224  trange.data()[i].tiles_range().first;
225 
226  size_vectors.get()[i] =
227  vector_type(n, &(*trange.data()[i].begin()),
228  [](const TiledRange1::range_type& tile) {
229  return value_type(tile.second - tile.first);
230  });
231  }
232 
233  return size_vectors;
234  }
235 
236  std::shared_ptr<vector_type> perm_size_vectors(
237  const Permutation& perm) const {
238  const unsigned int n = tile_norms_.range().rank();
239 
240  // Allocate memory for the contracted size vectors
241  std::shared_ptr<vector_type> result_size_vectors(
242  new vector_type[n], std::default_delete<vector_type[]>());
243 
244  // Initialize the size vectors
245  for (unsigned int i = 0u; i < n; ++i) {
246  const unsigned int perm_i = perm[i];
247  result_size_vectors.get()[perm_i] = size_vectors_.get()[i];
248  }
249 
250  return result_size_vectors;
251  }
252 
253  decltype(zero_tile_count_) compute_zero_tile_count() {
254  decltype(zero_tile_count_) zero_tile_count = 0;
255  for (auto&& n : tile_norms_) {
256  if (n < threshold()) {
257  ++zero_tile_count;
258  }
259  }
260  return zero_tile_count;
261  }
262 
263  SparseShape(const Tensor<T>& tile_norms,
264  const std::shared_ptr<vector_type>& size_vectors,
265  const size_type zero_tile_count)
266  : tile_norms_(tile_norms),
267  size_vectors_(size_vectors),
268  zero_tile_count_(zero_tile_count) {}
269 
270  public:
272 
274  SparseShape() : tile_norms_(), size_vectors_(), zero_tile_count_(0ul) {}
275 
277 
284  SparseShape(const value_type& tile_norm, const TiledRange& trange)
285  : tile_norms_(trange.tiles_range(),
286  (tile_norm < threshold_ ? 0 : tile_norm)),
287  size_vectors_(initialize_size_vectors(trange)),
288  zero_tile_count_(tile_norm < threshold_ ? trange.tiles_range().area()
289  : 0ul) {}
290 
292 
299  SparseShape(const Tensor<value_type>& tile_norms, const TiledRange& trange,
300  bool do_not_scale = false)
301  : tile_norms_(tile_norms.clone()),
302  size_vectors_(initialize_size_vectors(trange)),
303  zero_tile_count_(0ul) {
304  TA_ASSERT(!tile_norms_.empty());
305  TA_ASSERT(tile_norms_.range() == trange.tiles_range());
306 
307  if (!do_not_scale) {
308  zero_tile_count_ = scale_tile_norms<ScaleBy::InverseVolume>(
309  tile_norms_, size_vectors_.get());
310  } else {
311  zero_tile_count_ = compute_zero_tile_count();
312  }
313  }
314 
316 
327  template <typename SparseNormSequence,
328  typename = std::enable_if_t<
329  TiledArray::detail::has_member_function_begin_anyreturn<
330  std::decay_t<SparseNormSequence>>::value &&
331  TiledArray::detail::has_member_function_end_anyreturn<
332  std::decay_t<SparseNormSequence>>::value>>
333  SparseShape(const SparseNormSequence& tile_norms, const TiledRange& trange,
334  bool do_not_scale = false)
335  : tile_norms_(trange.tiles_range(), value_type(0)),
336  size_vectors_(initialize_size_vectors(trange)),
337  zero_tile_count_(trange.tiles_range().volume()) {
338  const auto dim = tile_norms_.range().rank();
339  for (const auto& pair_idx_norm : tile_norms) {
340  auto compute_tile_volume = [dim, this, pair_idx_norm]() -> uint64_t {
341  uint64_t tile_volume = 1;
342  for (size_t d = 0; d != dim; ++d)
343  tile_volume *= size_vectors_.get()[d].at(pair_idx_norm.first[d]);
344  return tile_volume;
345  };
346  auto norm_per_element =
347  do_not_scale ? pair_idx_norm.second
348  : (pair_idx_norm.second / compute_tile_volume());
349  if (norm_per_element >= threshold()) {
350  tile_norms_[pair_idx_norm.first] = norm_per_element;
351  --zero_tile_count_;
352  }
353  }
354  }
355 
357 
369  SparseShape(World& world, const Tensor<value_type>& tile_norms,
370  const TiledRange& trange, bool do_not_scale = false)
371  : tile_norms_(tile_norms.clone()),
372  size_vectors_(initialize_size_vectors(trange)),
373  zero_tile_count_(0ul) {
374  TA_ASSERT(!tile_norms_.empty());
375  TA_ASSERT(tile_norms_.range() == trange.tiles_range());
376 
377  // reduce norm data from all processors
378  world.gop.max(tile_norms_.data(), tile_norms_.size());
379 
380  if (!do_not_scale) {
381  zero_tile_count_ = scale_tile_norms<ScaleBy::InverseVolume>(
382  tile_norms_, size_vectors_.get());
383  ;
384  } else {
385  zero_tile_count_ = compute_zero_tile_count();
386  }
387  }
388 
390 
404  template <typename SparseNormSequence>
405  SparseShape(World& world, const SparseNormSequence& tile_norms,
406  const TiledRange& trange)
407  : SparseShape(tile_norms, trange) {
408  world.gop.max(tile_norms_.data(), tile_norms_.size());
409  zero_tile_count_ = compute_zero_tile_count();
410  }
411 
413 
417  : tile_norms_(other.tile_norms_),
418  tile_norms_unscaled_(
419  other.tile_norms_unscaled_
420  ? std::make_unique<decltype(tile_norms_)>(
421  other.tile_norms_unscaled_.get()->clone())
422  : nullptr),
423  size_vectors_(other.size_vectors_),
424  zero_tile_count_(other.zero_tile_count_) {}
425 
427 
432  tile_norms_ = other.tile_norms_;
433  tile_norms_unscaled_ = other.tile_norms_unscaled_
434  ? std::make_unique<decltype(tile_norms_)>(
435  other.tile_norms_unscaled_.get()->clone())
436  : nullptr;
437  size_vectors_ = other.size_vectors_;
438  zero_tile_count_ = other.zero_tile_count_;
439  return *this;
440  }
441 
443 
445  bool validate(const Range& range) const {
446  if (tile_norms_.empty()) return false;
447  return (range == tile_norms_.range());
448  }
449 
451 
454  template <typename Index>
455  bool is_zero(const Index& i) const {
456  TA_ASSERT(!tile_norms_.empty());
457  return tile_norms_[i] < threshold_;
458  }
459 
461 
463  static constexpr bool is_dense() { return false; }
464 
466 
468  float sparsity() const {
469  TA_ASSERT(!tile_norms_.empty());
470  return float(zero_tile_count_) / float(tile_norms_.size());
471  }
472 
474 
476  static value_type threshold() { return threshold_; }
477 
479 
481  static void threshold(const value_type thresh) { threshold_ = thresh; }
482 
484 
488  template <typename Index>
489  value_type operator[](const Index& index) const {
490  TA_ASSERT(!tile_norms_.empty());
491  return tile_norms_[index];
492  }
493 
495 
503  template <typename Op>
504  SparseShape_ transform(Op&& op) const {
505  Tensor<T> new_norms = op(tile_norms_);
506  madness::AtomicInt zero_tile_count;
507  zero_tile_count = 0;
508 
509  const value_type threshold = threshold_;
510  auto apply_threshold = [threshold, &zero_tile_count](value_type& norm) {
511  TA_ASSERT(norm >= value_type(0));
512  if (norm < threshold) {
513  norm = value_type(0);
514  ++zero_tile_count;
515  }
516  };
517 
518  math::inplace_vector_op(apply_threshold, new_norms.range().volume(),
519  new_norms.data());
520 
521  return SparseShape_(std::move(new_norms), size_vectors_, zero_tile_count);
522  }
523 
525 
528  const Tensor<value_type>& data() const { return tile_norms_; }
529 
531 
535  if (tile_norms_unscaled_ == nullptr) {
536  tile_norms_unscaled_ =
537  std::make_unique<decltype(tile_norms_)>(tile_norms_.clone());
538  [[maybe_unused]] auto should_be_zero =
539  scale_tile_norms<ScaleBy::Volume, false>(*tile_norms_unscaled_,
540  size_vectors_.get());
541  TA_ASSERT(should_be_zero == 0);
542  }
543  return *(tile_norms_unscaled_.get());
544  }
545 
547 
549  bool empty() const { return tile_norms_.empty(); }
550 
552 
555  SparseShape_ mask(const SparseShape_& mask_shape) const {
556  TA_ASSERT(!tile_norms_.empty());
557  TA_ASSERT(!mask_shape.empty());
558  TA_ASSERT(tile_norms_.range() == mask_shape.tile_norms_.range());
559 
560  const value_type threshold = threshold_;
561  madness::AtomicInt zero_tile_count;
562  zero_tile_count = zero_tile_count_;
563  auto op = [threshold, &zero_tile_count](value_type left,
564  const value_type right) {
565  if (left >= threshold && right < threshold) {
566  left = value_type(0);
567  ++zero_tile_count;
568  }
569 
570  return left;
571  };
572 
573  Tensor<value_type> result_tile_norms =
574  tile_norms_.binary(mask_shape.tile_norms_, op);
575 
576  return SparseShape_(result_tile_norms, size_vectors_, zero_tile_count);
577  }
578 
579  // clang-format off
581 
589  // clang-format on
590  template <typename Index1, typename Index2,
591  typename = std::enable_if_t<detail::is_integral_range_v<Index1> &&
592  detail::is_integral_range_v<Index2>>>
593  SparseShape update_block(const Index1& lower_bound, const Index2& upper_bound,
594  const SparseShape& other) const {
595  Tensor<value_type> result_tile_norms = tile_norms_.clone();
596 
597  auto result_tile_norms_blk =
598  result_tile_norms.block(lower_bound, upper_bound);
599  const value_type threshold = threshold_;
600  madness::AtomicInt zero_tile_count;
601  zero_tile_count = zero_tile_count_;
602  result_tile_norms_blk.inplace_binary(
603  other.tile_norms_,
604  [threshold, &zero_tile_count](value_type& l, const value_type r) {
605  // Update the zero tile count for the result
606  if ((l < threshold) && (r >= threshold))
607  ++zero_tile_count;
608  else if ((l >= threshold) && (r < threshold))
609  --zero_tile_count;
610 
611  // Update the tile norm value
612  l = r;
613  });
614 
615  return SparseShape_(result_tile_norms, size_vectors_, zero_tile_count);
616  }
617 
618  // clang-format off
620 
628  // clang-format on
629  template <typename Index1, typename Index2,
630  typename = std::enable_if_t<std::is_integral_v<Index1> &&
631  std::is_integral_v<Index2>>>
632  SparseShape update_block(const std::initializer_list<Index1>& lower_bound,
633  const std::initializer_list<Index2>& upper_bound,
634  const SparseShape& other) const {
635  return update_block<std::initializer_list<Index1>,
636  std::initializer_list<Index2>>(lower_bound, upper_bound,
637  other);
638  }
639 
640  // clang-format off
642 
648  // clang-format on
649  template <typename PairRange,
650  typename = std::enable_if_t<detail::is_gpair_range_v<PairRange>>>
651  SparseShape update_block(const PairRange& bounds,
652  const SparseShape& other) const {
653  Tensor<value_type> result_tile_norms = tile_norms_.clone();
654 
655  auto result_tile_norms_blk = result_tile_norms.block(bounds);
656  const value_type threshold = threshold_;
657  madness::AtomicInt zero_tile_count;
658  zero_tile_count = zero_tile_count_;
659  result_tile_norms_blk.inplace_binary(
660  other.tile_norms_,
661  [threshold, &zero_tile_count](value_type& l, const value_type r) {
662  // Update the zero tile count for the result
663  if ((l < threshold) && (r >= threshold))
664  ++zero_tile_count;
665  else if ((l >= threshold) && (r < threshold))
666  --zero_tile_count;
667 
668  // Update the tile norm value
669  l = r;
670  });
671 
672  return SparseShape_(result_tile_norms, size_vectors_, zero_tile_count);
673  }
674 
675  // clang-format off
677 
683  // clang-format on
684  template <typename Index,
685  typename = std::enable_if_t<std::is_integral_v<Index>>>
687  const std::initializer_list<std::initializer_list<Index>>& bounds,
688  const SparseShape& other) const {
689  return update_block<std::initializer_list<std::initializer_list<Index>>>(
690  bounds, other);
691  }
692 
694 
697  inline bool operator==(const SparseShape<T>& other) const {
698  bool equal = this->zero_tile_count_ == other.zero_tile_count_;
699  if (equal) {
700  const unsigned int dim = tile_norms_.range().rank();
701  for (unsigned d = 0; d != dim && equal; ++d) {
702  equal =
703  equal && (size_vectors_.get()[d] == other.size_vectors_.get()[d]);
704  }
705  if (equal) {
706  equal = equal && (tile_norms_ == other.tile_norms_);
707  }
708  }
709  return equal;
710  }
711 
712  private:
714 
719  template <typename Index1, typename Index2,
720  typename = std::enable_if_t<detail::is_integral_range_v<Index1> &&
721  detail::is_integral_range_v<Index2>>>
722  std::shared_ptr<vector_type> block_range(const Index1& lower_bound,
723  const Index2& upper_bound) const {
724  // Get the number dimensions of the shape
725  const auto rank = tile_norms_.range().rank();
726  std::shared_ptr<vector_type> size_vectors(
727  new vector_type[rank], std::default_delete<vector_type[]>());
728 
729  int d = 0;
730  using std::begin;
731  using std::end;
732  auto lower_it = begin(lower_bound);
733  auto upper_it = begin(upper_bound);
734  const auto lower_end = end(lower_bound);
735  const auto upper_end = end(upper_bound);
736  for (; lower_it != lower_end && upper_it != upper_end;
737  ++d, ++lower_it, ++upper_it) {
738  // Get the new range size
739  const auto lower_d = *lower_it;
740  const auto upper_d = *upper_it;
741  const auto extent_d = upper_d - lower_d;
742 
743  // Check that the input indices are in range
744  TA_ASSERT(lower_d >= tile_norms_.range().lobound(d));
745  TA_ASSERT(lower_d < upper_d);
746  TA_ASSERT(upper_d <= tile_norms_.range().upbound(d));
747 
748  // Construct the size vector for rank i
749  size_vectors.get()[d] =
750  vector_type(extent_d, size_vectors_.get()[d].data() + lower_d);
751  }
752  TA_ASSERT(d == rank);
753 
754  return size_vectors;
755  }
756 
758 
762  template <typename PairRange,
763  typename = std::enable_if_t<detail::is_gpair_range_v<PairRange>>>
764  std::shared_ptr<vector_type> block_range(const PairRange& bounds) const {
765  // Get the number dimensions of the shape
766  const auto rank = tile_norms_.range().rank();
767  std::shared_ptr<vector_type> size_vectors(
768  new vector_type[rank], std::default_delete<vector_type[]>());
769 
770  int d = 0;
771  for (auto&& bound_d : bounds) {
772  // Get the new range size
773  const auto lower_d = detail::at(bound_d, 0);
774  const auto upper_d = detail::at(bound_d, 1);
775  const auto extent_d = upper_d - lower_d;
776 
777  // Check that the input indices are in range
778  TA_ASSERT(lower_d >= tile_norms_.range().lobound(d));
779  TA_ASSERT(lower_d < upper_d);
780  TA_ASSERT(upper_d <= tile_norms_.range().upbound(d));
781 
782  // Construct the size vector for rank i
783  size_vectors.get()[d] =
784  vector_type(extent_d, size_vectors_.get()[d].data() + lower_d);
785 
786  ++d;
787  }
788  TA_ASSERT(d == rank);
789 
790  return size_vectors;
791  }
792 
794  template <typename Op>
795  static SparseShape_ make_block(
796  const std::shared_ptr<vector_type>& size_vectors,
797  const TensorConstView<value_type>& block_view, const Op& op) {
798  // Copy the data from arg to result
799  const value_type threshold = threshold_;
800  madness::AtomicInt zero_tile_count;
801  zero_tile_count = 0;
802  auto copy_op = [threshold, &zero_tile_count, &op](
803  value_type& MADNESS_RESTRICT result,
804  const value_type arg) {
805  result = op(arg);
806  if (result < threshold) {
807  ++zero_tile_count;
808  result = value_type(0);
809  }
810  };
811 
812  // Construct the result norms tensor
813  Tensor<value_type> result_norms(Range(block_view.range().extent()));
814  result_norms.inplace_binary(shift(block_view), copy_op);
815 
816  return SparseShape(result_norms, size_vectors, zero_tile_count);
817  }
818 
819  public:
821 
826  template <typename Index1, typename Index2,
827  typename = std::enable_if_t<detail::is_integral_range_v<Index1> &&
828  detail::is_integral_range_v<Index2>>>
829  SparseShape block(const Index1& lower_bound,
830  const Index2& upper_bound) const {
831  return make_block(block_range(lower_bound, upper_bound),
832  tile_norms_.block(lower_bound, upper_bound),
833  [](auto&& arg) { return arg; });
834  }
835 
837 
842  template <typename Index1, typename Index2,
843  typename = std::enable_if_t<std::is_integral_v<Index1> &&
844  std::is_integral_v<Index2>>>
845  SparseShape block(const std::initializer_list<Index1>& lower_bound,
846  const std::initializer_list<Index2>& upper_bound) const {
847  return this
848  ->block<std::initializer_list<Index1>, std::initializer_list<Index2>>(
849  lower_bound, upper_bound);
850  }
851 
853 
857  template <typename PairRange,
858  typename = std::enable_if_t<detail::is_gpair_range_v<PairRange>>>
859  SparseShape block(const PairRange& bounds) const {
860  return make_block(block_range(bounds), tile_norms_.block(bounds),
861  [](auto&& arg) { return arg; });
862  }
863 
865 
868  template <typename Index,
869  typename = std::enable_if_t<std::is_integral_v<Index>>>
871  const std::initializer_list<std::initializer_list<Index>>& bounds) const {
872  return make_block(block_range(bounds), tile_norms_.block(bounds),
873  [](auto&& arg) { return arg; });
874  }
875 
877 
886  template <typename Index1, typename Index2, typename Scalar,
887  typename = std::enable_if_t<detail::is_integral_range_v<Index1> &&
888  detail::is_integral_range_v<Index2> &&
889  detail::is_numeric_v<Scalar>>>
890  SparseShape block(const Index1& lower_bound, const Index2& upper_bound,
891  const Scalar factor) const {
892  const value_type abs_factor = to_abs_factor(factor);
893  return make_block(block_range(lower_bound, upper_bound),
894  tile_norms_.block(lower_bound, upper_bound),
895  [&abs_factor](auto&& arg) { return abs_factor * arg; });
896  }
897 
899 
907  template <typename Index1, typename Index2, typename Scalar,
908  typename = std::enable_if_t<std::is_integral_v<Index1> &&
909  std::is_integral_v<Index2> &&
910  detail::is_numeric_v<Scalar>>>
911  SparseShape block(const std::initializer_list<Index1>& lower_bound,
912  const std::initializer_list<Index2>& upper_bound,
913  const Scalar factor) const {
914  return this->block<std::initializer_list<Index1>,
915  std::initializer_list<Index2>, Scalar>(
916  lower_bound, upper_bound, factor);
917  }
918 
920 
926  template <typename PairRange, typename Scalar,
927  typename = std::enable_if_t<detail::is_numeric_v<Scalar> &&
928  detail::is_gpair_range_v<PairRange>>>
929  SparseShape block(const PairRange& bounds, const Scalar factor) const {
930  const value_type abs_factor = to_abs_factor(factor);
931  return make_block(block_range(bounds), tile_norms_.block(bounds),
932  [&abs_factor](auto&& arg) { return abs_factor * arg; });
933  }
934 
936 
943  template <typename Index, typename Scalar,
944  typename = std::enable_if_t<detail::is_numeric_v<Scalar> &&
945  std::is_integral_v<Index>>>
947  const std::initializer_list<std::initializer_list<Index>>& bounds,
948  const Scalar factor) const {
949  const value_type abs_factor = to_abs_factor(factor);
950  return make_block(block_range(bounds), tile_norms_.block(bounds),
951  [&abs_factor](auto&& arg) { return abs_factor * arg; });
952  }
953 
955 
962  template <typename Index1, typename Index2,
963  typename = std::enable_if_t<detail::is_integral_range_v<Index1> &&
964  detail::is_integral_range_v<Index2>>>
965  SparseShape block(const Index1& lower_bound, const Index2& upper_bound,
966  const Permutation& perm) const {
967  return block(lower_bound, upper_bound).perm(perm);
968  }
969 
971 
978  template <typename Index1, typename Index2,
979  typename = std::enable_if_t<std::is_integral_v<Index1> &&
980  std::is_integral_v<Index2>>>
981  SparseShape block(const std::initializer_list<Index1>& lower_bound,
982  const std::initializer_list<Index2>& upper_bound,
983  const Permutation& perm) const {
984  return block(lower_bound, upper_bound).perm(perm);
985  }
986 
988 
993  template <typename PairRange,
994  typename = std::enable_if_t<detail::is_gpair_range_v<PairRange>>>
995  SparseShape block(const PairRange& bounds, const Permutation& perm) const {
996  return block(bounds).perm(perm);
997  }
998 
1000 
1005  template <typename Index,
1006  typename = std::enable_if_t<std::is_integral_v<Index>>>
1008  const std::initializer_list<std::initializer_list<Index>>& bounds,
1009  const Permutation& perm) const {
1010  return block(bounds).perm(perm);
1011  }
1012 
1014 
1025  template <typename Index1, typename Index2, typename Scalar,
1026  typename = std::enable_if_t<detail::is_integral_range_v<Index1> &&
1027  detail::is_integral_range_v<Index2> &&
1028  detail::is_numeric_v<Scalar>>>
1029  SparseShape block(const Index1& lower_bound, const Index2& upper_bound,
1030  const Scalar factor, const Permutation& perm) const {
1031  return block(lower_bound, upper_bound, factor).perm(perm);
1032  }
1033 
1035 
1046  template <typename Index1, typename Index2, typename Scalar,
1047  typename = std::enable_if_t<std::is_integral_v<Index1> &&
1048  std::is_integral_v<Index2> &&
1049  detail::is_numeric_v<Scalar>>>
1050  SparseShape block(const std::initializer_list<Index1>& lower_bound,
1051  const std::initializer_list<Index2>& upper_bound,
1052  const Scalar factor, const Permutation& perm) const {
1053  return block(lower_bound, upper_bound, factor).perm(perm);
1054  }
1055 
1057 
1065  template <typename PairRange, typename Scalar,
1066  typename = std::enable_if_t<detail::is_numeric_v<Scalar> &&
1067  detail::is_gpair_range_v<PairRange>>>
1068  SparseShape block(const PairRange& bounds, const Scalar factor,
1069  const Permutation& perm) const {
1070  const value_type abs_factor = to_abs_factor(factor);
1071  return make_block(block_range(bounds), tile_norms_.block(bounds),
1072  [&abs_factor](auto&& arg) { return abs_factor * arg; })
1073  .perm(perm);
1074  }
1075 
1077 
1086  template <typename Index, typename Scalar,
1087  typename = std::enable_if_t<detail::is_numeric_v<Scalar> &&
1088  std::is_integral_v<Index>>>
1090  const std::initializer_list<std::initializer_list<Index>>& bounds,
1091  const Scalar factor, const Permutation& perm) const {
1092  const value_type abs_factor = to_abs_factor(factor);
1093  return make_block(block_range(bounds), tile_norms_.block(bounds),
1094  [&abs_factor](auto&& arg) { return abs_factor * arg; })
1095  .perm(perm);
1096  }
1097 
1099 
1102  SparseShape_ perm(const Permutation& perm) const {
1103  return SparseShape_(tile_norms_.permute(perm), perm_size_vectors(perm),
1104  zero_tile_count_);
1105  }
1106 
1108 
1118  template <typename Scalar,
1119  typename = std::enable_if_t<detail::is_numeric_v<Scalar>>>
1120  SparseShape_ scale(const Scalar factor) const {
1121  TA_ASSERT(!tile_norms_.empty());
1122  const value_type threshold = threshold_;
1123  const value_type abs_factor = to_abs_factor(factor);
1124  madness::AtomicInt zero_tile_count;
1125  zero_tile_count = 0;
1126  auto op = [threshold, &zero_tile_count, abs_factor](value_type value) {
1127  value *= abs_factor;
1128  if (value < threshold) {
1129  value = value_type(0);
1130  ++zero_tile_count;
1131  }
1132  return value;
1133  };
1134 
1135  Tensor<value_type> result_tile_norms = tile_norms_.unary(op);
1136 
1137  return SparseShape_(result_tile_norms, size_vectors_, zero_tile_count);
1138  }
1139 
1141 
1149  template <typename Factor>
1150  SparseShape_ scale(const Factor factor, const Permutation& perm) const {
1151  TA_ASSERT(!tile_norms_.empty());
1152  const value_type threshold = threshold_;
1153  const value_type abs_factor = to_abs_factor(factor);
1154  madness::AtomicInt zero_tile_count;
1155  zero_tile_count = 0;
1156  auto op = [threshold, &zero_tile_count, abs_factor](value_type value) {
1157  value *= abs_factor;
1158  if (value < threshold) {
1159  value = value_type(0);
1160  ++zero_tile_count;
1161  }
1162  return value;
1163  };
1164 
1165  Tensor<value_type> result_tile_norms = tile_norms_.unary(op, perm);
1166 
1167  return SparseShape_(result_tile_norms, perm_size_vectors(perm),
1168  zero_tile_count);
1169  }
1170 
1172 
1179  SparseShape_ add(const SparseShape_& other) const {
1180  TA_ASSERT(!tile_norms_.empty());
1181  const value_type threshold = threshold_;
1182  madness::AtomicInt zero_tile_count;
1183  zero_tile_count = 0;
1184  auto op = [threshold, &zero_tile_count](value_type left,
1185  const value_type right) {
1186  left += right;
1187  if (left < threshold) {
1188  left = value_type(0);
1189  ++zero_tile_count;
1190  }
1191  return left;
1192  };
1193 
1194  Tensor<value_type> result_tile_norms =
1195  tile_norms_.binary(other.tile_norms_, op);
1196 
1197  return SparseShape_(result_tile_norms, size_vectors_, zero_tile_count);
1198  }
1199 
1201 
1208  SparseShape_ add(const SparseShape_& other, const Permutation& perm) const {
1209  TA_ASSERT(!tile_norms_.empty());
1210  const value_type threshold = threshold_;
1211  madness::AtomicInt zero_tile_count;
1212  zero_tile_count = 0;
1213  auto op = [threshold, &zero_tile_count](value_type left,
1214  const value_type right) {
1215  left += right;
1216  if (left < threshold) {
1217  left = value_type(0);
1218  ++zero_tile_count;
1219  }
1220  return left;
1221  };
1222 
1223  Tensor<value_type> result_tile_norms =
1224  tile_norms_.binary(other.tile_norms_, op, perm);
1225 
1226  return SparseShape_(result_tile_norms, perm_size_vectors(perm),
1227  zero_tile_count);
1228  }
1229 
1231 
1239  template <typename Factor>
1240  SparseShape_ add(const SparseShape_& other, const Factor factor) const {
1241  TA_ASSERT(!tile_norms_.empty());
1242  const value_type threshold = threshold_;
1243  const value_type abs_factor = to_abs_factor(factor);
1244  madness::AtomicInt zero_tile_count;
1245  zero_tile_count = 0;
1246  auto op = [threshold, &zero_tile_count, abs_factor](
1247  value_type left, const value_type right) {
1248  left += right;
1249  left *= abs_factor;
1250  if (left < threshold) {
1251  left = value_type(0);
1252  ++zero_tile_count;
1253  }
1254  return left;
1255  };
1256 
1257  Tensor<value_type> result_tile_norms =
1258  tile_norms_.binary(other.tile_norms_, op);
1259 
1260  return SparseShape_(result_tile_norms, size_vectors_, zero_tile_count);
1261  }
1262 
1264 
1273  template <typename Factor>
1274  SparseShape_ add(const SparseShape_& other, const Factor factor,
1275  const Permutation& perm) const {
1276  TA_ASSERT(!tile_norms_.empty());
1277  const value_type threshold = threshold_;
1278  const value_type abs_factor = to_abs_factor(factor);
1279  madness::AtomicInt zero_tile_count;
1280  zero_tile_count = 0;
1281  auto op = [threshold, &zero_tile_count, abs_factor](
1282  value_type left, const value_type right) {
1283  left += right;
1284  left *= abs_factor;
1285  if (left < threshold) {
1286  left = value_type(0);
1287  ++zero_tile_count;
1288  }
1289  return left;
1290  };
1291 
1292  Tensor<value_type> result_tile_norms =
1293  tile_norms_.binary(other.tile_norms_, op, perm);
1294 
1295  return SparseShape_(result_tile_norms, perm_size_vectors(perm),
1296  zero_tile_count);
1297  }
1298 
1299  SparseShape_ add(value_type value) const {
1300  TA_ASSERT(!tile_norms_.empty());
1301  const value_type threshold = threshold_;
1302  madness::AtomicInt zero_tile_count;
1303  zero_tile_count = 0;
1304 
1305  Tensor<T> result_tile_norms(tile_norms_.range());
1306 
1307  value = std::abs(value);
1308  const unsigned int dim = tile_norms_.range().rank();
1309  const vector_type* MADNESS_RESTRICT const size_vectors =
1310  size_vectors_.get();
1311 
1312  if (dim == 1u) {
1313  auto add_const_op = [threshold, &zero_tile_count, value](
1314  value_type norm, const value_type size) {
1315  norm += value / std::sqrt(size);
1316  if (norm < threshold) {
1317  norm = 0;
1318  ++zero_tile_count;
1319  }
1320  return norm;
1321  };
1322 
1323  // This is the easy case where the data is a vector and can be
1324  // normalized directly.
1325  math::vector_op(add_const_op, size_vectors[0].size(),
1326  result_tile_norms.data(), tile_norms_.data(),
1327  size_vectors[0].data());
1328 
1329  } else {
1330  // Here the normalization constants are computed and multiplied by the
1331  // norm data using a recursive, outer algorithm. This is done to
1332  // minimize temporary memory requirements, memory bandwidth, and work.
1333 
1334  auto inv_sqrt_vec_op = [](const vector_type size_vector) {
1335  return vector_type(size_vector, [](const value_type size) {
1336  return value_type(1) / std::sqrt(size);
1337  });
1338  };
1339 
1340  // Compute the left and right outer products
1341  const unsigned int middle = (dim >> 1u) + (dim & 1u);
1342  const vector_type left =
1343  recursive_outer_product(size_vectors, middle, inv_sqrt_vec_op);
1344  const vector_type right = recursive_outer_product(
1345  size_vectors + middle, dim - middle, inv_sqrt_vec_op);
1346 
1348  left.size(), right.size(), left.data(), right.data(),
1349  tile_norms_.data(), result_tile_norms.data(),
1350  [threshold, &zero_tile_count, value](
1351  value_type& norm, const value_type x, const value_type y) {
1352  norm += value * x * y;
1353  if (norm < threshold) {
1354  norm = value_type(0);
1355  ++zero_tile_count;
1356  }
1357  });
1358  }
1359 
1360  return SparseShape_(result_tile_norms, size_vectors_, zero_tile_count);
1361  }
1362 
1363  SparseShape_ add(const value_type value, const Permutation& perm) const {
1364  // TODO: Optimize this function so it does the permutation at the same
1365  // time as the addition.
1366  return add(value).perm(perm);
1367  }
1368 
1369  SparseShape_ subt(const SparseShape_& other) const { return add(other); }
1370 
1371  SparseShape_ subt(const SparseShape_& other, const Permutation& perm) const {
1372  return add(other, perm);
1373  }
1374 
1375  template <typename Factor>
1376  SparseShape_ subt(const SparseShape_& other, const Factor factor) const {
1377  return add(other, factor);
1378  }
1379 
1380  template <typename Factor>
1381  SparseShape_ subt(const SparseShape_& other, const Factor factor,
1382  const Permutation& perm) const {
1383  return add(other, factor, perm);
1384  }
1385 
1386  SparseShape_ subt(const value_type value) const { return add(value); }
1387 
1388  SparseShape_ subt(const value_type value, const Permutation& perm) const {
1389  return add(value, perm);
1390  }
1391 
1392  SparseShape_ mult(const SparseShape_& other) const {
1393  // TODO: Optimize this function so that the tensor arithmetic and
1394  // scale_tile_norms operations are performed in one step instead of two.
1395 
1396  TA_ASSERT(!tile_norms_.empty());
1397  Tensor<T> result_tile_norms = tile_norms_.mult(other.tile_norms_);
1398  const size_type zero_tile_count = scale_tile_norms<ScaleBy::Volume>(
1399  result_tile_norms, size_vectors_.get());
1400 
1401  return SparseShape_(result_tile_norms, size_vectors_, zero_tile_count);
1402  }
1403 
1404  SparseShape_ mult(const SparseShape_& other, const Permutation& perm) const {
1405  // TODO: Optimize this function so that the tensor arithmetic and
1406  // scale_tile_norms operations are performed in one step instead of two.
1407 
1408  TA_ASSERT(!tile_norms_.empty());
1409  Tensor<T> result_tile_norms = tile_norms_.mult(other.tile_norms_, perm);
1410  std::shared_ptr<vector_type> result_size_vector = perm_size_vectors(perm);
1411  const size_type zero_tile_count = scale_tile_norms<ScaleBy::Volume>(
1412  result_tile_norms, result_size_vector.get());
1413 
1414  return SparseShape_(result_tile_norms, result_size_vector, zero_tile_count);
1415  }
1416 
1420  template <typename Factor>
1421  SparseShape_ mult(const SparseShape_& other, const Factor factor) const {
1422  // TODO: Optimize this function so that the tensor arithmetic and
1423  // scale_tile_norms operations are performed in one step instead of two.
1424 
1425  TA_ASSERT(!tile_norms_.empty());
1426  const value_type abs_factor = to_abs_factor(factor);
1427  Tensor<T> result_tile_norms =
1428  tile_norms_.mult(other.tile_norms_, abs_factor);
1429  const size_type zero_tile_count = scale_tile_norms<ScaleBy::Volume>(
1430  result_tile_norms, size_vectors_.get());
1431 
1432  return SparseShape_(result_tile_norms, size_vectors_, zero_tile_count);
1433  }
1434 
1438  template <typename Factor>
1439  SparseShape_ mult(const SparseShape_& other, const Factor factor,
1440  const Permutation& perm) const {
1441  // TODO: Optimize this function so that the tensor arithmetic and
1442  // scale_tile_norms operations are performed in one step instead of two.
1443 
1444  TA_ASSERT(!tile_norms_.empty());
1445  const value_type abs_factor = to_abs_factor(factor);
1446  Tensor<T> result_tile_norms =
1447  tile_norms_.mult(other.tile_norms_, abs_factor, perm);
1448  std::shared_ptr<vector_type> result_size_vector = perm_size_vectors(perm);
1449  const size_type zero_tile_count = scale_tile_norms<ScaleBy::Volume>(
1450  result_tile_norms, result_size_vector.get());
1451 
1452  return SparseShape_(result_tile_norms, result_size_vector, zero_tile_count);
1453  }
1454 
1458  template <typename Factor>
1459  SparseShape_ gemm(const SparseShape_& other, const Factor factor,
1460  const math::GemmHelper& gemm_helper) const {
1461  TA_ASSERT(!tile_norms_.empty());
1462 
1463  const value_type abs_factor = to_abs_factor(factor);
1464  const value_type threshold = threshold_;
1465  madness::AtomicInt zero_tile_count;
1466  zero_tile_count = 0;
1468  integer M = 0, N = 0, K = 0;
1469  gemm_helper.compute_matrix_sizes(M, N, K, tile_norms_.range(),
1470  other.tile_norms_.range());
1471 
1472  // Allocate memory for the contracted size vectors
1473  std::shared_ptr<vector_type> result_size_vectors(
1474  new vector_type[gemm_helper.result_rank()],
1475  std::default_delete<vector_type[]>());
1476 
1477  // Initialize the result size vectors
1478  unsigned int x = 0ul;
1479  for (unsigned int i = gemm_helper.left_outer_begin();
1480  i < gemm_helper.left_outer_end(); ++i, ++x)
1481  result_size_vectors.get()[x] = size_vectors_.get()[i];
1482  for (unsigned int i = gemm_helper.right_outer_begin();
1483  i < gemm_helper.right_outer_end(); ++i, ++x)
1484  result_size_vectors.get()[x] = other.size_vectors_.get()[i];
1485 
1486  // Compute the number of inner ranks
1487  const unsigned int k_rank =
1488  gemm_helper.left_inner_end() - gemm_helper.left_inner_begin();
1489 
1490  // Construct the result norm tensor
1491  Tensor<value_type> result_norms(
1492  gemm_helper.make_result_range<typename Tensor<T>::range_type>(
1493  tile_norms_.range(), other.tile_norms_.range()),
1494  0);
1495 
1496  if (k_rank > 0u) {
1497  // Compute size vector
1498  const vector_type k_sizes = recursive_outer_product(
1499  size_vectors_.get() + gemm_helper.left_inner_begin(), k_rank,
1500  [](const vector_type& size_vector) -> const vector_type& {
1501  return size_vector;
1502  });
1503 
1504  // TODO: Make this faster. It can be done without using temporaries
1505  // for the arguments, but requires a custom matrix multiply.
1506 
1507  Tensor<value_type> left(tile_norms_.range());
1508  const size_type mk = M * K;
1509  auto left_op = [](const value_type left, const value_type right) {
1510  return left * right;
1511  };
1512  for (size_type i = 0ul; i < mk; i += K)
1513  math::vector_op(left_op, K, left.data() + i, tile_norms_.data() + i,
1514  k_sizes.data());
1515 
1516  Tensor<value_type> right(other.tile_norms_.range());
1517  for (integer i = 0ul, k = 0; k < K; i += N, ++k) {
1518  const value_type factor = k_sizes[k];
1519  auto right_op = [=](const value_type arg) { return arg * factor; };
1520  math::vector_op(right_op, N, right.data() + i,
1521  other.tile_norms_.data() + i);
1522  }
1523 
1524  result_norms = left.gemm(right, abs_factor, gemm_helper);
1525 
1526  // Hard zero tiles that are below the zero threshold.
1527  result_norms.inplace_unary(
1528  [threshold, &zero_tile_count](value_type& value) {
1529  if (value < threshold) {
1530  value = value_type(0);
1531  ++zero_tile_count;
1532  }
1533  });
1534 
1535  } else {
1536  // This is an outer product, so the inputs can be used directly
1537  math::outer_fill(M, N, tile_norms_.data(), other.tile_norms_.data(),
1538  result_norms.data(),
1539  [threshold, &zero_tile_count, abs_factor](
1540  const value_type left, const value_type right) {
1541  value_type norm = left * right * abs_factor;
1542  if (norm < threshold) {
1543  norm = value_type(0);
1544  ++zero_tile_count;
1545  }
1546  return norm;
1547  });
1548  }
1549 
1550  return SparseShape_(result_norms, result_size_vectors, zero_tile_count);
1551  }
1552 
1556  template <typename Factor>
1557  SparseShape_ gemm(const SparseShape_& other, const Factor factor,
1558  const math::GemmHelper& gemm_helper,
1559  const Permutation& perm) const {
1560  return gemm(other, factor, gemm_helper).perm(perm);
1561  }
1562 
1563  template <typename Archive,
1564  typename std::enable_if<madness::archive::is_input_archive<
1565  Archive>::value>::type* = nullptr>
1566  void serialize(const Archive& ar) {
1567  ar& tile_norms_;
1568  const unsigned int dim = tile_norms_.range().rank();
1569  // allocate size_vectors_
1570  size_vectors_ = std::move(std::shared_ptr<vector_type>(
1571  new vector_type[dim], std::default_delete<vector_type[]>()));
1572  for (unsigned d = 0; d != dim; ++d) ar& size_vectors_.get()[d];
1573  ar& zero_tile_count_;
1574  }
1575 
1576  template <typename Archive,
1577  typename std::enable_if<madness::archive::is_output_archive<
1578  Archive>::value>::type* = nullptr>
1579  void serialize(const Archive& ar) const {
1580  ar& tile_norms_;
1581  const unsigned int dim = tile_norms_.range().rank();
1582  for (unsigned d = 0; d != dim; ++d) ar& size_vectors_.get()[d];
1583  ar& zero_tile_count_;
1584  }
1585 
1586  private:
1587  template <typename Factor>
1588  static value_type to_abs_factor(const Factor factor) {
1589  using std::abs;
1590  const auto cast_abs_factor = static_cast<value_type>(abs(factor));
1591  TA_ASSERT(std::isfinite(cast_abs_factor));
1592  return cast_abs_factor;
1593  }
1594 
1595 }; // class SparseShape
1596 
1597 // Static member initialization
1598 template <typename T>
1599 typename SparseShape<T>::value_type SparseShape<T>::threshold_ =
1600  std::numeric_limits<T>::epsilon();
1601 
1603 
1608 template <typename T>
1609 inline std::ostream& operator<<(std::ostream& os, const SparseShape<T>& shape) {
1610  os << "SparseShape<" << typeid(T).name() << ">:" << std::endl
1611  << shape.data() << std::endl;
1612  return os;
1613 }
1614 
1616 
1621 template <typename T>
1622 bool is_replicated(World& world, const SparseShape<T>& shape) {
1623  const auto volume = shape.data().size();
1624  std::vector<T> data(shape.data().data(), shape.data().data() + volume);
1625  world.gop.max(data.data(), volume);
1626  for (size_t i = 0; i != data.size(); ++i) {
1627  if (data[i] != shape.data()[i]) return false;
1628  }
1629  return true;
1630 }
1631 
1632 #ifndef TILEDARRAY_HEADER_ONLY
1633 
1634 extern template class SparseShape<float>;
1635 
1636 #endif // TILEDARRAY_HEADER_ONLY
1637 
1638 } // namespace TiledArray
1639 
1640 #endif // TILEDARRAY_SPASE_SHAPE_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
void serialize(const Archive &ar)
unsigned int right_outer_begin() const
Definition: gemm_helper.h:152
Contraction to *GEMM helper.
Definition: gemm_helper.h:40
void outer_fill(const std::size_t m, const std::size_t n, const X *const x, const Y *const y, A *a, const Op &op)
Compute and store outer of x and y in a.
Definition: outer.h:175
SparseShape block(const Index1 &lower_bound, const Index2 &upper_bound, const Scalar factor) const
Create a scaled sub-block of the shape.
Definition: sparse_shape.h:890
detail::TensorInterface< T, BlockRange > block(const Index1 &lower_bound, const Index2 &upper_bound)
Constructs a view of the block defined by lower_bound and upper_bound.
Definition: tensor.h:704
float sparsity() const
Sparsity of the shape.
Definition: sparse_shape.h:468
::blas::Op Op
Definition: blas.h:46
unsigned int left_inner_end() const
Definition: gemm_helper.h:146
value_type operator[](const Index &index) const
Tile norm accessor.
Definition: sparse_shape.h:489
SparseShape_ add(const SparseShape_ &other, const Factor factor, const Permutation &perm) const
Add, scale, and permute shapes.
SparseShape update_block(const std::initializer_list< Index1 > &lower_bound, const std::initializer_list< Index2 > &upper_bound, const SparseShape &other) const
Creates a copy of this with a sub-block updated with contents of another shape.
Definition: sparse_shape.h:632
SparseShape_ mult(const SparseShape_ &other, const Factor factor, const Permutation &perm) const
const range_type & range() const
Tensor range object accessor.
Definition: tensor.h:384
SparseShape< T > & operator=(const SparseShape< T > &other)
Copy assignment operator.
Definition: sparse_shape.h:431
unsigned int left_outer_end() const
Definition: gemm_helper.h:148
void outer(const std::size_t m, const std::size_t n, const X *const x, const Y *const y, A *a, const Op &op)
Compute the outer of x and y to modify a.
Definition: outer.h:239
unsigned int right_outer_end() const
Definition: gemm_helper.h:153
const range_type & tiles_range() const
Access the tile range.
Definition: tiled_range.h:147
SparseShape_ add(const value_type value, const Permutation &perm) const
int64_t integer
Definition: blas.h:44
detail::ShiftWrapper< T > shift(T &tensor)
Shift a tensor from one range to another.
Permutation of a sequence of objects indexed by base-0 indices.
Definition: permutation.h:130
auto get(T &&t)
Definition: type_traits.h:858
SparseShape(World &world, const SparseNormSequence &tile_norms, const TiledRange &trange)
Collective "sparse" constructor.
Definition: sparse_shape.h:405
void vector_op(Op &&op, const std::size_t n, Result *const result, const Args *const ... args)
Definition: vector_op.h:472
SparseShape_ mult(const SparseShape_ &other, const Factor factor) const
SparseShape block(const Index1 &lower_bound, const Index2 &upper_bound, const Scalar factor, const Permutation &perm) const
Create a permuted scaled sub-block of the shape.
Tensor_ gemm(const Tensor< U, AU > &other, const V factor, const math::GemmHelper &gemm_helper) const
Contract this tensor with other.
Definition: tensor.h:1609
SparseShape_ mult(const SparseShape_ &other) const
Tensor_ binary(const Right &right, Op &&op) const
Use a binary, element wise operation to construct a new tensor.
Definition: tensor.h:950
Tensor_ clone() const
Definition: tensor.h:359
DistArray< Tile, Policy > clone(const DistArray< Tile, Policy > &arg)
Create a deep copy of an array.
Definition: clone.h:43
bool is_zero(const Index &i) const
Check that a tile is zero.
Definition: sparse_shape.h:455
SparseShape block(const std::initializer_list< std::initializer_list< Index >> &bounds, const Scalar factor) const
Create a scaled sub-block of the shape.
Definition: sparse_shape.h:946
std::ostream & operator<<(std::ostream &os, const SparseShape< T > &shape)
Add the shape to an output stream.
SparseShape update_block(const PairRange &bounds, const SparseShape &other) const
Creates a copy of this with a sub-block updated with contents of another shape.
Definition: sparse_shape.h:651
SparseShape block(const std::initializer_list< Index1 > &lower_bound, const std::initializer_list< Index2 > &upper_bound, const Scalar factor, const Permutation &perm) const
Create a permuted scaled sub-block of the shape.
Tensor_ & inplace_unary(Op &&op)
Use a unary, element wise operation to modify this tensor.
Definition: tensor.h:1062
SparseShape update_block(const std::initializer_list< std::initializer_list< Index >> &bounds, const SparseShape &other) const
Creates a copy of this with a sub-block updated with contents of another shape.
Definition: sparse_shape.h:686
SparseShape block(const std::initializer_list< std::initializer_list< Index >> &bounds, const Scalar factor, const Permutation &perm) const
Create a permuted scaled sub-block of the shape.
void inplace_vector_op(Op &&op, const std::size_t n, Result *const result, const Args *const ... args)
Definition: vector_op.h:391
unsigned int left_inner_begin() const
Definition: gemm_helper.h:145
decltype(auto) norm(const Tile< Arg > &arg)
Vector 2-norm of a tile.
Definition: tile.h:1527
SparseShape< T > SparseShape_
This object type.
Definition: sparse_shape.h:76
auto rank(const DistArray< Tile, Policy > &a)
Definition: dist_array.h:1617
SparseShape block(const Index1 &lower_bound, const Index2 &upper_bound, const Permutation &perm) const
Create a permuted sub-block of the shape.
Definition: sparse_shape.h:965
const_pointer data() const
Data direct access.
Definition: tensor.h:609
Tensor_ mult(const Right &right) const
Multiply this by right to create a new tensor.
Definition: tensor.h:1398
SparseShape_ subt(const SparseShape_ &other) const
static constexpr bool is_dense()
Check density.
Definition: sparse_shape.h:463
SparseShape(const Tensor< value_type > &tile_norms, const TiledRange &trange, bool do_not_scale=false)
"Dense" constructor
Definition: sparse_shape.h:299
SparseShape(World &world, const Tensor< value_type > &tile_norms, const TiledRange &trange, bool do_not_scale=false)
Collective "dense" constructor.
Definition: sparse_shape.h:369
SparseShape block(const std::initializer_list< Index1 > &lower_bound, const std::initializer_list< Index2 > &upper_bound, const Scalar factor) const
Create a scaled sub-block of the shape.
Definition: sparse_shape.h:911
#define TA_ASSERT(EXPR,...)
Definition: error.h:39
SparseShape block(const std::initializer_list< Index1 > &lower_bound, const std::initializer_list< Index2 > &upper_bound, const Permutation &perm) const
Create a permuted sub-block of the shape.
Definition: sparse_shape.h:981
SparseShape_ add(const SparseShape_ &other, const Permutation &perm) const
Add and permute shapes.
unsigned int result_rank() const
Result rank accessor.
Definition: gemm_helper.h:133
TA_1INDEX_TYPE index1_type
Definition: sparse_shape.h:78
SparseShape block(const std::initializer_list< std::initializer_list< Index >> &bounds) const
Create a copy of a sub-block of the shape.
Definition: sparse_shape.h:870
std::pair< index1_type, index1_type > range_type
Definition: tiled_range1.h:56
SparseShape block(const std::initializer_list< Index1 > &lower_bound, const std::initializer_list< Index2 > &upper_bound) const
Create a copy of a sub-block of the shape.
Definition: sparse_shape.h:845
SparseShape_ subt(const SparseShape_ &other, const Factor factor, const Permutation &perm) const
SparseShape_ perm(const Permutation &perm) const
Create a permuted shape of this shape.
Range data of a tiled array.
Definition: tiled_range.h:32
SparseShape_ gemm(const SparseShape_ &other, const Factor factor, const math::GemmHelper &gemm_helper) const
SparseShape block(const std::initializer_list< std::initializer_list< Index >> &bounds, const Permutation &perm) const
Create a permuted sub-block of the shape.
SparseShape block(const PairRange &bounds, const Scalar factor) const
Create a scaled sub-block of the shape.
Definition: sparse_shape.h:929
SparseShape_ subt(const value_type value, const Permutation &perm) const
SparseShape_ add(value_type value) const
SparseShape_ subt(const value_type value) const
SparseShape_ mask(const SparseShape_ &mask_shape) const
Compute union of two shapes.
Definition: sparse_shape.h:555
SparseShape_ add(const SparseShape_ &other) const
Add shapes.
SparseShape block(const PairRange &bounds, const Permutation &perm) const
Create a permuted sub-block of the shape.
Definition: sparse_shape.h:995
bool operator==(const SparseShape< T > &other) const
Bitwise comparison.
Definition: sparse_shape.h:697
bool empty() const
Initialization check.
Definition: sparse_shape.h:549
SparseShape_ mult(const SparseShape_ &other, const Permutation &perm) const
void compute_matrix_sizes(blas::integer &m, blas::integer &n, blas::integer &k, const Left &left, const Right &right) const
Compute the matrix dimension that can be used in a *GEMM call.
Definition: gemm_helper.h:254
SparseShape_ scale(const Scalar factor) const
Scale shape.
Tensor< value_type >::size_type size_type
Size type.
Definition: sparse_shape.h:80
bool is_replicated(World &world, const SparseShape< T > &shape)
collective bitwise-compare-reduce for SparseShape objects
btas::Tensor< T, Range, Storage > add(const btas::Tensor< T, Range, Storage > &arg1, const btas::Tensor< T, Range, Storage > &arg2)
result[i] = arg1[i] + arg2[i]
Definition: btas.h:218
SparseShape update_block(const Index1 &lower_bound, const Index2 &upper_bound, const SparseShape &other) const
Creates a copy of this with a sub-block updated with contents of another shape.
Definition: sparse_shape.h:593
SparseShape_ subt(const SparseShape_ &other, const Permutation &perm) const
SparseShape block(const PairRange &bounds, const Scalar factor, const Permutation &perm) const
Create a permuted scaled sub-block of the shape.
auto abs(const ComplexConjugate< T > &a)
Definition: complex.h:270
const Tensor< value_type > & data() const
Data accessor.
Definition: sparse_shape.h:528
btas::Tensor< T, Range, Storage > gemm(const btas::Tensor< T, Range, Storage > &left, const btas::Tensor< T, Range, Storage > &right, Scalar factor, const TiledArray::math::GemmHelper &gemm_helper)
Definition: btas.h:596
size_t volume(const DistArray< Tile, Policy > &a)
Definition: dist_array.h:1622
Tensor_ unary(Op &&op) const
Use a unary, element wise operation to construct a new tensor.
Definition: tensor.h:1018
SparseShape_ subt(const SparseShape_ &other, const Factor factor) const
SparseShape(const value_type &tile_norm, const TiledRange &trange)
"Dense" Constructor
Definition: sparse_shape.h:284
ordinal_type size() const
Tensor dimension size accessor.
Definition: tensor.h:400
const Tensor< value_type > & tile_norms() const
Data accessor.
Definition: sparse_shape.h:534
SparseShape_ add(const SparseShape_ &other, const Factor factor) const
Add and scale shapes.
SparseShape block(const Index1 &lower_bound, const Index2 &upper_bound) const
Create a copy of a sub-block of the shape.
Definition: sparse_shape.h:829
static value_type threshold()
Threshold accessor.
Definition: sparse_shape.h:476
bool validate(const Range &range) const
Validate shape range.
Definition: sparse_shape.h:445
decltype(auto) at(GeneralizedPair &&v, std::size_t idx)
at(pair, i) extracts i-th element from gpair
Definition: type_traits.h:1268
T value_type
The norm value type.
Definition: sparse_shape.h:77
Frobenius-norm-based sparse shape.
Definition: sparse_shape.h:74
void outer_fill(const ValArray< U > &left, const ValArray< V > &right, const Op &op)
Outer fill operation.
Definition: val_array.h:402
An N-dimensional tensor object.
Definition: tensor.h:50
SparseShape()
Default constructor.
Definition: sparse_shape.h:274
SparseShape_ transform(Op &&op) const
Transform the norm tensor with an operation.
Definition: sparse_shape.h:504
unsigned int left_outer_begin() const
Definition: gemm_helper.h:147
void serialize(const Archive &ar) const
T norm(const btas::Tensor< T, Range, Storage > &arg)
Definition: btas.h:753
SparseShape(const SparseShape< T > &other)
Copy constructor.
Definition: sparse_shape.h:416
unsigned int rank() const
Rank accessor.
Definition: range.h:669
SparseShape_ scale(const Factor factor, const Permutation &perm) const
Scale and permute shape.
SparseShape(const SparseNormSequence &tile_norms, const TiledRange &trange, bool do_not_scale=false)
"Sparse" constructor
Definition: sparse_shape.h:333
A (hyperrectangular) interval on , space of integer -indices.
Definition: range.h:46
SparseShape_ gemm(const SparseShape_ &other, const Factor factor, const math::GemmHelper &gemm_helper, const Permutation &perm) const
SparseShape block(const PairRange &bounds) const
Create a copy of a sub-block of the shape.
Definition: sparse_shape.h:859
static void threshold(const value_type thresh)
Set threshold to thresh.
Definition: sparse_shape.h:481