tensor_interface.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  * Justus Calvin
19  * Department of Chemistry, Virginia Tech
20  *
21  * tensor_interface.h
22  * May 29, 2015
23  *
24  */
25 
26 #ifndef TILEDARRAY_TENSOR_TENSOR_VIEW_H__INCLUDED
27 #define TILEDARRAY_TENSOR_TENSOR_VIEW_H__INCLUDED
28 
32 #include <TiledArray/type_traits.h>
33 
34 namespace TiledArray {
35 
36 // Forward declarations
37 template <typename T, typename A>
38 class Tensor;
39 class Range;
40 namespace detail {
41 template <typename T, typename Range, typename OpResult>
42 class TensorInterface;
43 }
44 
45 template <typename T, typename Range_, typename OpResult, typename Index1,
46  typename Index2>
47 void remap(detail::TensorInterface<T, Range_, OpResult>&, T* const,
48  const Index1&, const Index2&);
49 template <typename T, typename Range_, typename OpResult, typename Index1,
50  typename Index2>
52  const Index1&, const Index2&);
53 template <typename T, typename Range_, typename OpResult, typename Index1,
54  typename Index2>
56  const std::initializer_list<Index1>&,
57  const std::initializer_list<Index2>&);
58 template <typename T, typename Range_, typename OpResult, typename Index1,
59  typename Index2>
61  const std::initializer_list<Index1>&,
62  const std::initializer_list<Index2>&);
63 
64 namespace detail {
65 
67 
81 template <typename T, typename R, typename OpResult>
83  public:
86  typedef R range_type;
87  typedef typename range_type::index1_type index1_type;
88  typedef typename range_type::ordinal_type ordinal_type;
90  typedef
91  typename std::remove_const<T>::type value_type;
92  typedef typename std::add_lvalue_reference<T>::type
94  typedef
95  typename std::add_lvalue_reference<typename std::add_const<T>::type>::type
97  typedef typename std::add_pointer<T>::type pointer;
98  typedef typename std::add_pointer<typename std::add_const<T>::type>::type
100  typedef typename std::ptrdiff_t difference_type;
105 
106  typedef OpResult result_tensor;
108 
109  private:
110  template <typename X>
111  using numeric_t = typename TiledArray::detail::numeric_type<X>::type;
112 
113  template <typename, typename, typename>
114  friend class TensorInterface;
115 
116  template <typename U, typename Range_, typename OpResult_, typename Index1,
117  typename Index2>
119  U* const, const Index1&, const Index2&);
120  template <typename U, typename Range_, typename OpResult_, typename Index1,
121  typename Index2>
122  friend void TiledArray::remap(
124  const Index1&, const Index2&);
125  template <typename U, typename Range_, typename OpResult_, typename Index1,
126  typename Index2>
128  U* const, const std::initializer_list<Index1>&,
129  const std::initializer_list<Index2>&);
130  template <typename U, typename Range_, typename OpResult_, typename Index1,
131  typename Index2>
132  friend void TiledArray::remap(
134  const std::initializer_list<Index1>&,
135  const std::initializer_list<Index2>&);
136 
137  range_type range_;
138  pointer data_;
139 
140  public:
142  TensorInterface() = delete;
143  ~TensorInterface() = default;
148 
150 
153  template <typename U, typename UOpResult,
154  typename std::enable_if<std::is_convertible<
156  pointer>::value>::type* = nullptr>
158  : range_(other.range_), data_(other.data_) {}
159 
161 
164  template <typename U, typename UOpResult,
165  typename std::enable_if<std::is_convertible<
167  pointer>::value>::type* = nullptr>
169  : range_(std::move(other.range_)), data_(other.data_) {
170  other.data_ = nullptr;
171  }
172 
174 
178  : range_(range), data_(data) {
179  TA_ASSERT(data);
180  }
181 
183 
187  : range_(std::move(range)), data_(data) {
188  TA_ASSERT(data);
189  }
190 
191  template <typename T1, typename std::enable_if<
192  detail::is_tensor<T1>::value>::type* = nullptr>
193  TensorInterface_& operator=(const T1& other) {
194  TA_ASSERT(data_ != other.data());
195 
196  detail::inplace_tensor_op([](numeric_type& MADNESS_RESTRICT result,
197  const numeric_t<T1> arg) { result = arg; },
198  *this, other);
199 
200  return *this;
201  }
202 
204 
206  const range_type& range() const { return range_; }
207 
209 
211  ordinal_type size() const { return range_.volume(); }
212 
214 
216  pointer data() const { return data_; }
217 
219 
223  TA_ASSERT(range_.includes(index));
224  return data_[range_.ordinal(index)];
225  }
226 
228 
232  TA_ASSERT(range_.includes(index));
233  return data_[range_.ordinal(index)];
234  }
235 
237 
240  template <typename... Index>
241  reference operator()(const Index&... idx) {
242  TA_ASSERT(range_.includes(idx...));
243  return data_[range_.ordinal(idx...)];
244  }
245 
247 
250  template <typename... Index>
251  const_reference operator()(const Index&... idx) const {
252  TA_ASSERT(range_.includes(idx...));
253  return data_[range_.ordinal(idx...)];
254  }
255 
257 
259  constexpr bool empty() const { return false; }
260 
262 
264  void swap(TensorInterface_& other) {
265  range_.swap(other.range_);
266  std::swap(data_, other.data_);
267  }
268 
270 
274  template <typename Index,
275  typename = std::enable_if_t<detail::is_integral_range_v<Index>>>
276  TensorInterface_& shift_to(const Index& bound_shift) {
277  range_.inplace_shift(bound_shift);
278  return *this;
279  }
280 
282 
286  template <typename Index,
287  typename = std::enable_if_t<std::is_integral_v<Index>>>
288  TensorInterface_& shift_to(const std::initializer_list<Index>& bound_shift) {
289  range_.inplace_shift(bound_shift);
290  return *this;
291  }
292 
294 
298  template <typename Index,
299  typename = std::enable_if_t<detail::is_integral_range_v<Index>>>
300  result_tensor shift(const Index& bound_shift) const {
301  return result_tensor(range_.shift(bound_shift), data_);
302  }
303 
305 
309  template <typename Index,
310  typename = std::enable_if_t<std::is_integral_v<Index>>>
311  result_tensor shift(const std::initializer_list<Index>& bound_shift) const {
312  return result_tensor(range_.shift(bound_shift), data_);
313  }
314 
315  // Generic vector operations
316 
318 
325  template <typename Right, typename Op,
326  typename std::enable_if<is_tensor<Right>::value>::type* = nullptr>
327  result_tensor binary(const Right& right, Op&& op) const {
328  // return result_tensor(*this, right, op);
329  result_tensor new_tensor(detail::clone_range(*this));
330  detail::tensor_init(std::forward<Op>(op), new_tensor, *this, right);
331  return new_tensor;
332  }
333 
335 
343  template <
344  typename Right, typename Op, typename Perm,
345  typename std::enable_if<is_tensor<Right>::value &&
346  detail::is_permutation_v<Perm>>::type* = nullptr>
347  result_tensor binary(const Right& right, Op&& op, const Perm& perm) const {
348  // return result_tensor(*this, right, op, perm);
349  result_tensor new_tensor(outer(perm) * this->range());
350  detail::tensor_init(std::forward<Op>(op), outer(perm), new_tensor, *this,
351  right);
352 
353  // If we actually have a ToT the inner permutation was not applied above so
354  // we do that now
355  constexpr bool is_tot = detail::is_tensor_of_tensor_v<TensorInterface>;
356  constexpr bool is_bperm = detail::is_bipartite_permutation_v<Perm>;
357  if constexpr (is_tot && is_bperm) {
358  if (inner_size(perm) != 0) {
359  auto inner_perm = inner(perm);
360  Permute<T, T> p;
361  for (auto& x : new_tensor) x = p(x, inner_perm);
362  }
363  }
364 
365  return new_tensor;
366  }
367 
369 
380  template <typename Right, typename Op,
381  typename std::enable_if<is_tensor<Right>::value>::type* = nullptr>
382  TensorInterface_& inplace_binary(const Right& right, Op&& op) {
383  detail::inplace_tensor_op(std::forward<Op>(op), *this, right);
384  return *this;
385  }
386 
388 
394  template <typename Op>
395  result_tensor unary(Op&& op) const {
396  // return result_tensor(*this, op);
397  result_tensor new_tensor(detail::clone_range(*this));
398  detail::tensor_init(std::forward<Op>(op), new_tensor, *this);
399  return new_tensor;
400  }
401 
403 
411  template <typename Op, typename Perm,
412  typename = std::enable_if_t<detail::is_permutation_v<Perm>>>
413  result_tensor unary(Op&& op, const Perm& perm) const {
414  result_tensor new_tensor(outer(perm) * this->range());
415  detail::tensor_init(std::forward<Op>(op), outer(perm), new_tensor, *this);
416 
417  // If we actually have a ToT the inner permutation was not applied above so
418  // we do that now
419  constexpr bool is_tot = detail::is_tensor_of_tensor_v<TensorInterface>;
420  constexpr bool is_bperm = detail::is_bipartite_permutation_v<Perm>;
421  if constexpr (is_tot && is_bperm) {
422  if (inner_size(perm) != 0) {
423  auto inner_perm = inner(perm);
424  Permute<T, T> p;
425  for (auto& x : new_tensor) x = p(x, inner_perm);
426  }
427  }
428 
429  return new_tensor;
430  }
431 
433 
438  template <typename Op>
440  detail::inplace_tensor_op(std::forward<Op>(op), *this);
441  return *this;
442  }
443 
444  // permute operation
445  // construct a permuted copy of this tensor
446  template <typename Perm,
447  typename = std::enable_if_t<detail::is_permutation_v<Perm>>>
448  result_tensor permute(const Perm& perm) const {
449  auto op = [](const T& arg) { return arg; };
450  result_tensor new_tensor(outer(perm) * this->range());
451  TiledArray::detail::tensor_init(op, outer(perm), new_tensor, *this);
452 
453  // If we actually have a ToT the inner permutation was not applied above so
454  // we do that now
455  constexpr bool is_tot = detail::is_tensor_of_tensor_v<TensorInterface>;
456  constexpr bool is_bperm = detail::is_bipartite_permutation_v<Perm>;
457  if constexpr (is_tot && is_bperm) {
458  if (inner_size(perm) != 0) {
459  auto inner_perm = inner(perm);
460  Permute<T, T> p;
461  for (auto& x : new_tensor) x = p(x, inner_perm);
462  }
463  }
464 
465  return new_tensor;
466  }
467 
468  // Scale operation
469 
471 
476  template <typename Scalar, typename std::enable_if<
477  detail::is_numeric_v<Scalar>>::type* = nullptr>
478  result_tensor scale(const Scalar factor) const {
479  return unary(
480  [factor](const numeric_type a) -> numeric_type { return a * factor; });
481  }
482 
484 
490  template <
491  typename Scalar, typename Perm,
492  typename std::enable_if<detail::is_numeric_v<Scalar> &&
493  detail::is_permutation_v<Perm>>::type* = nullptr>
494  result_tensor scale(const Scalar factor, const Perm& perm) const {
495  return unary(
496  [factor](const numeric_type a) -> numeric_type { return a * factor; },
497  perm);
498  }
499 
501 
505  template <typename Scalar, typename std::enable_if<
506  detail::is_numeric_v<Scalar>>::type* = nullptr>
507  TensorInterface_& scale_to(const Scalar factor) {
508  return inplace_unary(
509  [factor](numeric_type& MADNESS_RESTRICT res) { res *= factor; });
510  }
511 
512  // Addition operations
513 
515 
520  template <typename Right,
521  typename std::enable_if<is_tensor<Right>::value>::type* = nullptr>
522  result_tensor add(const Right& right) const {
523  return binary(
524  right,
525  [](const numeric_type l, const numeric_t<Right> r) -> numeric_type {
526  return l + r;
527  });
528  }
529 
531 
537  template <
538  typename Right, typename Perm,
539  typename std::enable_if<is_tensor<Right>::value &&
540  detail::is_permutation_v<Perm>>::type* = nullptr>
541  result_tensor add(const Right& right, const Perm& perm) const {
542  return binary(
543  right,
544  [](const numeric_type l, const numeric_t<Right> r) -> numeric_type {
545  return l + r;
546  },
547  perm);
548  }
549 
551 
558  template <
559  typename Right, typename Scalar,
560  typename std::enable_if<is_tensor<Right>::value &&
561  detail::is_numeric_v<Scalar>>::type* = nullptr>
562  result_tensor add(const Right& right, const Scalar factor) const {
563  return binary(right,
564  [factor](const numeric_type l, const numeric_t<Right> r)
565  -> numeric_type { return (l + r) * factor; });
566  }
567 
569 
577  template <typename Right, typename Scalar, typename Perm,
578  typename std::enable_if<
579  is_tensor<Right>::value && detail::is_numeric_v<Scalar> &&
580  detail::is_permutation_v<Perm>>::type* = nullptr>
581  result_tensor add(const Right& right, const Scalar factor,
582  const Perm& perm) const {
583  return binary(
584  right,
585  [factor](const numeric_type l, const numeric_t<Right> r)
586  -> numeric_type { return (l + r) * factor; },
587  perm);
588  }
589 
591 
595  result_tensor add(const numeric_type value) const {
596  return unary(
597  [value](const numeric_type a) -> numeric_type { return a + value; });
598  }
599 
601 
606  template <typename Perm,
607  typename = std::enable_if_t<detail::is_permutation_v<Perm>>>
608  result_tensor add(const numeric_type value, const Perm& perm) const {
609  return unary(
610  [value](const numeric_type a) -> numeric_type { return a + value; },
611  perm);
612  }
613 
615 
619  template <typename Right,
620  typename std::enable_if<is_tensor<Right>::value>::type* = nullptr>
621  TensorInterface_& add_to(const Right& right) {
622  return inplace_binary(right, [](numeric_type& MADNESS_RESTRICT l,
623  const numeric_t<Right> r) { l += r; });
624  }
625 
627 
633  template <
634  typename Right, typename Scalar,
635  typename std::enable_if<is_tensor<Right>::value &&
636  detail::is_numeric_v<Scalar>>::type* = nullptr>
637  TensorInterface_& add_to(const Right& right, const Scalar factor) {
638  return inplace_binary(
639  right, [factor](numeric_type& MADNESS_RESTRICT l,
640  const numeric_t<Right> r) { (l += r) *= factor; });
641  }
642 
644 
648  return inplace_unary(
649  [value](numeric_type& MADNESS_RESTRICT res) { res += value; });
650  }
651 
652  // Subtraction operations
653 
655 
660  template <typename Right,
661  typename std::enable_if<is_tensor<Right>::value>::type* = nullptr>
662  result_tensor subt(const Right& right) const {
663  return binary(
664  right,
665  [](const numeric_type l, const numeric_t<Right> r) -> numeric_type {
666  return l - r;
667  });
668  }
669 
671 
677  template <
678  typename Right, typename Perm,
679  typename std::enable_if<is_tensor<Right>::value &&
680  detail::is_permutation_v<Perm>>::type* = nullptr>
681  result_tensor subt(const Right& right, const Perm& perm) const {
682  return binary(
683  right,
684  [](const numeric_type l, const numeric_t<Right> r) -> numeric_type {
685  return l - r;
686  },
687  perm);
688  }
689 
691 
698  template <
699  typename Right, typename Scalar,
700  typename std::enable_if<is_tensor<Right>::value &&
701  detail::is_numeric_v<Scalar>>::type* = nullptr>
702  result_tensor subt(const Right& right, const Scalar factor) const {
703  return binary(right,
704  [factor](const numeric_type l, const numeric_t<Right> r)
705  -> numeric_type { return (l - r) * factor; });
706  }
707 
709 
717  template <typename Right, typename Scalar, typename Perm,
718  typename std::enable_if<
719  is_tensor<Right>::value && detail::is_numeric_v<Scalar> &&
720  detail::is_permutation_v<Perm>>::type* = nullptr>
721  result_tensor subt(const Right& right, const Scalar factor,
722  const Perm& perm) const {
723  return binary(
724  right,
725  [factor](const numeric_type l, const numeric_t<Right> r)
726  -> numeric_type { return (l - r) * factor; },
727  perm);
728  }
729 
731 
734  result_tensor subt(const numeric_type value) const { return add(-value); }
735 
737 
742  template <typename Perm,
743  typename = std::enable_if_t<detail::is_permutation_v<Perm>>>
744  result_tensor subt(const numeric_type value, const Perm& perm) const {
745  return add(-value, perm);
746  }
747 
749 
753  template <typename Right,
754  typename std::enable_if<is_tensor<Right>::value>::type* = nullptr>
755  TensorInterface_& subt_to(const Right& right) {
756  return inplace_binary(right, [](numeric_type& MADNESS_RESTRICT l,
757  const numeric_t<Right> r) { l -= r; });
758  }
759 
761 
767  template <
768  typename Right, typename Scalar,
769  typename std::enable_if<is_tensor<Right>::value &&
770  detail::is_numeric_v<Scalar>>::type* = nullptr>
771  TensorInterface_& subt_to(const Right& right, const Scalar factor) {
772  return inplace_binary(
773  right, [factor](numeric_type& MADNESS_RESTRICT l,
774  const numeric_t<Right> r) { (l -= r) *= factor; });
775  }
776 
778 
780  TensorInterface_& subt_to(const numeric_type value) { return add_to(-value); }
781 
782  // Multiplication operations
783 
785 
790  template <typename Right,
791  typename std::enable_if<is_tensor<Right>::value>::type* = nullptr>
792  result_tensor mult(const Right& right) const {
793  return binary(
794  right,
795  [](const numeric_type l, const numeric_t<Right> r) -> numeric_type {
796  return l * r;
797  });
798  }
799 
801 
807  template <
808  typename Right, typename Perm,
809  typename std::enable_if<is_tensor<Right>::value &&
810  detail::is_permutation_v<Perm>>::type* = nullptr>
811  result_tensor mult(const Right& right, const Perm& perm) const {
812  return binary(
813  right,
814  [](const numeric_type l, const numeric_t<Right> r) -> numeric_type {
815  return l * r;
816  },
817  perm);
818  }
819 
821 
828  template <
829  typename Right, typename Scalar,
830  typename std::enable_if<is_tensor<Right>::value &&
831  detail::is_numeric_v<Scalar>>::type* = nullptr>
832  result_tensor mult(const Right& right, const Scalar factor) const {
833  return binary(right,
834  [factor](const numeric_type l, const numeric_t<Right> r)
835  -> numeric_type { return (l * r) * factor; });
836  }
837 
839 
847  template <typename Right, typename Scalar, typename Perm,
848  typename std::enable_if<
849  is_tensor<Right>::value && detail::is_numeric_v<Scalar> &&
850  detail::is_permutation_v<Perm>>::type* = nullptr>
851  result_tensor mult(const Right& right, const Scalar factor,
852  const Perm& perm) const {
853  return binary(
854  right,
855  [factor](const numeric_type l, const numeric_t<Right> r)
856  -> numeric_type { return (l * r) * factor; },
857  perm);
858  }
859 
861 
865  template <typename Right,
866  typename std::enable_if<is_tensor<Right>::value>::type* = nullptr>
867  TensorInterface_& mult_to(const Right& right) {
868  return inplace_binary(right, [](numeric_type& MADNESS_RESTRICT l,
869  const numeric_t<Right> r) { l *= r; });
870  }
871 
873 
879  template <
880  typename Right, typename Scalar,
881  typename std::enable_if<is_tensor<Right>::value &&
882  detail::is_numeric_v<Scalar>>::type* = nullptr>
883  TensorInterface_& mult_to(const Right& right, const Scalar factor) {
884  return inplace_binary(
885  right, [factor](numeric_type& MADNESS_RESTRICT l,
886  const numeric_t<Right> r) { (l *= r) *= factor; });
887  }
888 
889  // Negation operations
890 
892 
894  result_tensor neg() const {
895  return unary([](const numeric_type r) -> numeric_type { return -r; });
896  }
897 
899 
902  template <typename Perm,
903  typename = std::enable_if_t<detail::is_permutation_v<Perm>>>
904  result_tensor neg(const Perm& perm) const {
905  return unary([](const numeric_type l) -> numeric_type { return -l; }, perm);
906  }
907 
909 
912  return inplace_unary([](numeric_type& MADNESS_RESTRICT l) { l = -l; });
913  }
914 
916 
919  result_tensor conj() const { return scale(conj_op()); }
920 
922 
927  template <typename Scalar, typename std::enable_if<
928  detail::is_numeric_v<Scalar>>::type* = nullptr>
929  result_tensor conj(const Scalar factor) const {
930  return scale(conj_op(factor));
931  }
932 
934 
938  template <typename Perm,
939  typename = std::enable_if_t<detail::is_permutation_v<Perm>>>
940  result_tensor conj(const Perm& perm) const {
941  return scale(conj_op(), perm);
942  }
943 
945 
951  template <
952  typename Scalar, typename Perm,
953  typename std::enable_if<detail::is_numeric_v<Scalar> &&
954  detail::is_permutation_v<Perm>>::type* = nullptr>
955  result_tensor conj(const Scalar factor, const Perm& perm) const {
956  return scale(conj_op(factor), perm);
957  }
958 
960 
963 
965 
969  template <typename Scalar, typename std::enable_if<
970  detail::is_numeric_v<Scalar>>::type* = nullptr>
971  TensorInterface_& conj_to(const Scalar factor) {
972  return scale_to(conj_op(factor));
973  }
974 
976 
987  template <typename ReduceOp, typename JoinOp>
988  numeric_type reduce(ReduceOp&& reduce_op, JoinOp&& join_op,
989  const numeric_type identity) const {
990  return detail::tensor_reduce(std::forward<ReduceOp>(reduce_op),
991  std::forward<JoinOp>(join_op), identity,
992  *this);
993  }
994 
996 
1008  template <typename Right, typename ReduceOp, typename JoinOp,
1009  typename std::enable_if<is_tensor<Right>::value>::type* = nullptr>
1010  numeric_type reduce(const Right& other, ReduceOp&& reduce_op,
1011  JoinOp&& join_op, const numeric_type identity) const {
1012  return detail::tensor_reduce(std::forward<ReduceOp>(reduce_op),
1013  std::forward<JoinOp>(join_op), identity, *this,
1014  other);
1015  }
1016 
1018 
1020  numeric_type sum() const {
1021  auto sum_op = [](numeric_type& MADNESS_RESTRICT res,
1022  const numeric_type arg) { res += arg; };
1023  return reduce(sum_op, sum_op, numeric_type(0));
1024  }
1025 
1027 
1030  auto mult_op = [](numeric_type& MADNESS_RESTRICT res,
1031  const numeric_type arg) { res *= arg; };
1032  return reduce(mult_op, mult_op, numeric_type(1));
1033  }
1034 
1036 
1039  auto square_op = [](scalar_type& MADNESS_RESTRICT res,
1040  const numeric_type arg) {
1041  res += TiledArray::detail::norm(arg);
1042  };
1043  auto sum_op = [](scalar_type& MADNESS_RESTRICT res, const scalar_type arg) {
1044  res += arg;
1045  };
1046  return reduce(square_op, sum_op, numeric_type(0));
1047  }
1048 
1050 
1054  template <typename ResultType = numeric_type>
1055  ResultType norm() const {
1056  return std::sqrt(static_cast<ResultType>(squared_norm()));
1057  }
1058 
1060 
1062  numeric_type min() const {
1063  auto min_op = [](numeric_type& MADNESS_RESTRICT res,
1064  const numeric_type arg) { res = std::min(res, arg); };
1065  return reduce(min_op, min_op, std::numeric_limits<numeric_type>::max());
1066  }
1067 
1069 
1071  numeric_type max() const {
1072  auto max_op = [](numeric_type& MADNESS_RESTRICT res,
1073  const numeric_type arg) { res = std::max(res, arg); };
1074  return reduce(max_op, max_op, std::numeric_limits<numeric_type>::min());
1075  }
1076 
1078 
1081  auto abs_min_op = [](numeric_type& MADNESS_RESTRICT res,
1082  const numeric_type arg) {
1083  res = std::min(res, std::abs(arg));
1084  };
1085  auto min_op = [](numeric_type& MADNESS_RESTRICT res,
1086  const numeric_type arg) { res = std::min(res, arg); };
1087  return reduce(abs_min_op, min_op, std::numeric_limits<numeric_type>::max());
1088  }
1089 
1091 
1094  auto abs_max_op = [](numeric_type& MADNESS_RESTRICT res,
1095  const numeric_type arg) {
1096  res = std::max(res, std::abs(arg));
1097  };
1098  auto max_op = [](numeric_type& MADNESS_RESTRICT res,
1099  const numeric_type arg) { res = std::max(res, arg); };
1100  return reduce(abs_max_op, max_op, numeric_type(0));
1101  }
1102 
1104 
1108  template <typename Right,
1109  typename std::enable_if<is_tensor<Right>::value>::type* = nullptr>
1110  numeric_type dot(const Right& other) const {
1111  auto mult_add_op = [](numeric_type& res, const numeric_type l,
1112  const numeric_t<Right> r) { res += l * r; };
1113  auto add_op = [](numeric_type& MADNESS_RESTRICT res,
1114  const numeric_type value) { res += value; };
1115  return reduce(other, mult_add_op, add_op, numeric_type(0));
1116  }
1117 
1124  template <typename Right,
1125  typename std::enable_if<is_tensor<Right>::value>::type* = nullptr>
1126  numeric_type inner_product(const Right& other) const {
1127  auto mult_add_op = [](numeric_type& res, const numeric_type l,
1128  const numeric_t<Right> r) {
1129  res += TiledArray::detail::inner_product(l, r);
1130  };
1131  auto add_op = [](numeric_type& MADNESS_RESTRICT res,
1132  const numeric_type value) { res += value; };
1133  return reduce(other, mult_add_op, add_op, numeric_type(0));
1134  }
1135 
1136 }; // class TensorInterface
1137 
1139 
1142 template <typename T, typename Range, typename OpResult>
1144  const TensorInterface<T, Range, OpResult>& second) {
1145  return first.data() == second.data() && first.range() == second.range();
1146 }
1147 
1148 } // namespace detail
1149 } // namespace TiledArray
1150 
1151 #endif // TILEDARRAY_TENSOR_TENSOR_VIEW_H__INCLUDED
numeric_type max() const
Maximum element.
Scalar tensor_reduce(ReduceOp &&reduce_op, JoinOp &&join_op, Scalar identity, const T1 &tensor1, const Ts &... tensors)
Reduction operation for contiguous tensors.
Definition: kernels.h:665
ordinal_type size() const
Tensor dimension size accessor.
std::add_pointer< T >::type pointer
Element pointer type.
auto clone_range(const T &tensor)
Create a copy of the range of the tensor.
Definition: utility.h:47
::blas::Op Op
Definition: blas.h:46
numeric_type product() const
Product of elements.
result_tensor scale(const Scalar factor) const
Construct a scaled copy of this tensor.
result_tensor neg() const
Create a negated copy of this tensor.
void swap(TensorInterface_ &other)
Swap tensor views.
result_tensor add(const Right &right, const Scalar factor, const Perm &perm) const
Scale and add this and other to construct a new, permuted tensor.
TensorInterface_ & mult_to(const Right &right, const Scalar factor)
Scale and multiply this tensor by right.
void swap(Bitset< B > &b0, Bitset< B > &b1)
Definition: bitset.h:565
TensorInterface_ & neg_to()
Negate elements of this tensor.
result_tensor binary(const Right &right, Op &&op) const
Use a binary, element wise operation to construct a new tensor.
numeric_type min() const
Minimum element.
std::ptrdiff_t difference_type
Difference type.
TensorInterface_ & add_to(const Right &right)
Add other to this tensor.
void reduce_op(ReduceOp &&reduce_op, JoinOp &&join_op, const Result &identity, const std::size_t n, Result &result, const Args *const ... args)
Definition: vector_op.h:628
result_tensor scale(const Scalar factor, const Perm &perm) const
Construct a scaled and permuted copy of this tensor.
TensorInterface_ & operator=(TensorInterface_ &&)=delete
Type trait for extracting the scalar type of tensors and arrays.
Definition: type_traits.h:744
numeric_type sum() const
Sum of elements.
TensorInterface_ & inplace_binary(const Right &right, Op &&op)
Use a binary, element wise operation to modify this tensor.
result_tensor add(const Right &right, const Scalar factor) const
Scale and add this and other to construct a new tensor.
range_type::index1_type index1_type
1-index type
result_tensor add(const Right &right) const
Add this and other to construct a new tensors.
result_tensor add(const numeric_type value, const Perm &perm) const
Add a constant to a permuted copy of this tensor.
TensorInterface_ & shift_to(const Index &bound_shift)
Shift the lower and upper bound of this tensor view.
KroneckerDeltaTile< _N >::numeric_type min(const KroneckerDeltaTile< _N > &arg)
TensorInterface_ & mult_to(const Right &right)
Multiply this tensor by right.
std::add_pointer< typename std::add_const< T >::type >::type const_pointer
Element pointer type.
ResultType norm() const
Vector 2-norm.
result_tensor subt(const numeric_type value) const
Subtract a constant from a copy of this tensor.
TensorInterface_ & inplace_unary(Op &&op)
Use a unary, element wise operation to modify this tensor.
numeric_type reduce(ReduceOp &&reduce_op, JoinOp &&join_op, const numeric_type identity) const
Unary reduction operation.
TensorInterface(const TensorInterface< U, R, UOpResult > &other)
Type conversion copy constructor.
std::remove_const< T >::type value_type
Array element type.
result_tensor add(const Right &right, const Perm &perm) const
Add this and other to construct a new, permuted tensor.
TensorInterface_ & subt_to(const Right &right)
Subtract right from this tensor.
result_tensor subt(const Right &right, const Scalar factor, const Perm &perm) const
Scale and subtract this and right to construct a new, permuted tensor.
TILEDARRAY_FORCE_INLINE auto inner_product(const L l, const R r)
Inner product of a real value and a numeric value.
Definition: complex.h:67
auto outer(const Permutation &p)
Definition: permutation.h:820
T1::size_type inner_size(const T1 &tensor1, const T2 &)
Get the inner size of two tensors.
Definition: utility.h:260
numeric_type abs_min() const
Absolute minimum element.
result_tensor mult(const Right &right) const
Multiply this by right to create a new tensor.
result_tensor subt(const Right &right, const Perm &perm) const
Subtract this and right to construct a new, permuted tensor.
TensorInterface_ & conj_to(const Scalar factor)
Complex conjugate and scale this tensor.
scalar_type squared_norm() const
Square of vector 2-norm.
#define TA_ASSERT(EXPR,...)
Definition: error.h:39
result_tensor mult(const Right &right, const Scalar factor) const
Scale and multiply this by right to create a new tensor.
detail::numeric_type< value_type >::type numeric_type
the numeric type that supports T
TensorInterface_ & add_to(const Right &right, const Scalar factor)
Add other to this tensor, and scale the result.
constexpr bool empty() const
Check for empty view.
result_tensor unary(Op &&op) const
Use a unary, element wise operation to construct a new tensor.
TensorInterface_ & subt_to(const numeric_type value)
Subtract a constant from this tensor.
result_tensor unary(Op &&op, const Perm &perm) const
Use a unary, element wise operation to construct a new, permuted tensor.
range_type::ordinal_type ordinal_type
Ordinal type.
KroneckerDeltaTile< _N >::numeric_type max(const KroneckerDeltaTile< _N > &arg)
bool operator==(const TileReference< Impl > &a, const TileReference< Impl > &b)
comparison operator for TileReference objects
Definition: array_impl.h:120
TensorInterface_ & scale_to(const Scalar factor)
Scale this tensor.
result_tensor conj(const Perm &perm) const
Create a complex conjugated and permuted copy of this tensor.
TensorInterface(TensorInterface< U, R, UOpResult > &&other)
Type conversion move constructor.
TensorInterface< T, R, OpResult > TensorInterface_
This class type.
reference operator()(const Index &... idx)
Element accessor.
numeric_type inner_product(const Right &other) const
Permute a tile.
Definition: permute.h:134
TensorInterface_ & operator=(const T1 &other)
result_tensor shift(const std::initializer_list< Index > &bound_shift) const
Make a copy of this view shited by bound_shift.
numeric_type dot(const Right &other) const
Vector dot product.
result_tensor permute(const Perm &perm) const
Tensor interface for external data.
result_tensor subt(const numeric_type value, const Perm &perm) const
Subtract a constant from a permuted copy of this tensor.
result_tensor neg(const Perm &perm) const
Create a negated and permuted copy of this tensor.
numeric_type abs_max() const
Absolute maximum element.
const_reference operator()(const Index &... idx) const
Element accessor.
reference operator[](const ordinal_type index)
Element subscript accessor.
std::add_lvalue_reference< T >::type reference
Element reference type.
std::add_lvalue_reference< typename std::add_const< T >::type >::type const_reference
Element reference type.
result_tensor conj(const Scalar factor, const Perm &perm) const
Create a complex conjugated, scaled, and permuted copy of this tensor.
auto abs(const ComplexConjugate< T > &a)
Definition: complex.h:270
const range_type & range() const
Tensor range object accessor.
TensorInterface(const range_type &range, pointer data)
Construct a new view of tensor.
result_tensor add(const numeric_type value) const
Add a constant to a copy of this tensor.
ComplexConjugate< S > conj_op(const S factor)
ComplexConjugate operator factory function.
Definition: complex.h:204
result_tensor subt(const Right &right) const
Subtract this and right to construct a new tensor.
TILEDARRAY_FORCE_INLINE R norm(const R r)
Wrapper function for std::norm
Definition: complex.h:93
TensorInterface_ & operator=(const TensorInterface_ &)=delete
pointer data() const
Data pointer accessor.
result_tensor mult(const Right &right, const Scalar factor, const Perm &perm) const
Scale and multiply this by right to create a new, permuted tensor.
TensorInterface_ & conj_to()
Complex conjugate this tensor.
TensorInterface(const TensorInterface_ &)=default
numeric_type reduce(const Right &other, ReduceOp &&reduce_op, JoinOp &&join_op, const numeric_type identity) const
Binary reduction operation.
Type trait for extracting the numeric type of tensors and arrays.
Definition: type_traits.h:709
TensorInterface_ & add_to(const numeric_type value)
Add a constant to this tensor.
const_reference operator[](const ordinal_type index) const
Element subscript accessor.
result_tensor binary(const Right &right, Op &&op, const Perm &perm) const
Use a binary, element wise operation to construct a new, permuted tensor.
result_tensor conj() const
Create a complex conjugated copy of this tensor.
void inplace_tensor_op(Op &&op, TR &result, const Ts &... tensors)
In-place tensor operations with contiguous data.
Definition: kernels.h:197
TensorInterface_ & subt_to(const Right &right, const Scalar factor)
Subtract right from and scale this tensor.
void tensor_init(Op &&op, TR &result, const Ts &... tensors)
Initialize tensor with contiguous tensor arguments.
Definition: kernels.h:421
result_tensor subt(const Right &right, const Scalar factor) const
Scale and subtract this and right to construct a new tensor.
result_tensor conj(const Scalar factor) const
Create a complex conjugated and scaled copy of this tensor.
OpResult result_tensor
Tensor type used as the return type from operations that produce a tensor.
T identity()
identity for group of objects of type T
TensorInterface()=delete
Compiler generated functions.
detail::scalar_type< value_type >::type scalar_type
the scalar type that supports T
result_tensor shift(const Index &bound_shift) const
Make a copy of this view shited by bound_shift.
TensorInterface(TensorInterface_ &&)=default
result_tensor mult(const Right &right, const Perm &perm) const
Multiply this by right to create a new, permuted tensor.
TensorInterface(range_type &&range, pointer data)
Construct a new view of tensor.
TensorInterface_ & shift_to(const std::initializer_list< Index > &bound_shift)
Shift the lower and upper bound of this tensor view.
void remap(detail::TensorInterface< T, Range_, OpResult > &, T *const, const Index1 &, const Index2 &)
Definition: tensor_map.h:154
auto inner(const Permutation &p)
Definition: permutation.h:813