TiledArray  0.7.0
tensor.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  */
19 
20 #ifndef TILEDARRAY_TENSOR_TENSOR_H__INCLUDED
21 #define TILEDARRAY_TENSOR_TENSOR_H__INCLUDED
22 
24 #include <TiledArray/math/blas.h>
27 
28 namespace TiledArray {
29 
31 
34  template <typename T, typename A = Eigen::aligned_allocator<T> >
35  class Tensor {
36  public:
38  typedef Range range_type;
39  typedef typename range_type::size_type size_type;
40  typedef A allocator_type;
41  typedef typename allocator_type::value_type value_type;
42  typedef typename allocator_type::reference reference;
43  typedef typename allocator_type::const_reference const_reference;
44  typedef typename allocator_type::pointer pointer;
45  typedef typename allocator_type::const_pointer const_pointer;
46  typedef typename allocator_type::difference_type difference_type;
47  typedef pointer iterator;
53 
54  private:
55 
56  template <typename X>
57  using numeric_t = typename TiledArray::detail::numeric_type<X>::type;
58 
60 
62  class Impl : public allocator_type {
63  public:
64 
66 
68  Impl() : allocator_type(), range_(), data_(NULL) { }
69 
71 
73  explicit Impl(const range_type& range) :
74  allocator_type(), range_(range), data_(NULL)
75  {
76  data_ = allocator_type::allocate(range.volume());
77  }
78 
80 
82  explicit Impl(range_type&& range) :
83  allocator_type(), range_(range), data_(NULL)
84  {
85  data_ = allocator_type::allocate(range.volume());
86  }
87 
88  ~Impl() {
89  math::destroy_vector(range_.volume(), data_);
90  allocator_type::deallocate(data_, range_.volume());
91  data_ = NULL;
92  }
93 
94  range_type range_;
95  pointer data_;
96  }; // class Impl
97 
98  template <typename... Ts>
99  struct is_tensor {
100  static constexpr bool value =
101  detail::is_tensor<Ts...>::value || detail::is_tensor_of_tensor<Ts...>::value;
102  };
103 
104  template <typename U, typename std::enable_if<std::is_scalar<U>::value>::type* = nullptr>
105  static void default_init(size_type, U*) { }
106 
107  template <typename U, typename std::enable_if<! std::is_scalar<U>::value>::type* = nullptr>
108  static void default_init(size_type n, U* u) {
110  }
111 
112  std::shared_ptr<Impl> pimpl_;
113  static const range_type empty_range_;
114 
115  public:
116 
117  // Compiler generated functions
118  Tensor() : pimpl_() { }
119  Tensor(const Tensor_& other) : pimpl_(other.pimpl_) { }
120  Tensor(Tensor_&& other) : pimpl_(std::move(other.pimpl_)) { }
121  ~Tensor() { }
122  Tensor_& operator=(const Tensor_& other) {
123  pimpl_ = other.pimpl_;
124  return *this;
125  }
127  pimpl_ = std::move(other.pimpl_);
128  return *this;
129  }
130 
132 
137  pimpl_(std::make_shared<Impl>(range))
138  {
139  default_init(range.volume(), pimpl_->data_);
140  }
141 
142 
144 
147  template <typename Value,
148  typename std::enable_if<std::is_same<Value, value_type>::value &&
149  detail::is_tensor<Value>::value>::type* = nullptr>
150  Tensor(const range_type& range, const Value& value) :
151  pimpl_(std::make_shared<Impl>(range))
152  {
153  const size_type n = pimpl_->range_.volume();
154  pointer MADNESS_RESTRICT const data = pimpl_->data_;
155  for(size_type i = 0ul; i < n; ++i)
156  new(data + i) value_type(value.clone());
157  }
158 
160 
163  template <typename Value,
164  typename std::enable_if<detail::is_numeric<Value>::value>::type* = nullptr>
165  Tensor(const range_type& range, const Value& value) :
166  pimpl_(std::make_shared<Impl>(range))
167  {
168  detail::tensor_init([=] () -> Value { return value; }, *this);
169  }
170 
172  template <typename InIter,
173  typename std::enable_if<TiledArray::detail::is_input_iterator<InIter>::value &&
174  ! std::is_pointer<InIter>::value>::type* = nullptr>
175  Tensor(const range_type& range, InIter it) :
176  pimpl_(std::make_shared<Impl>(range))
177  {
178  size_type n = range.volume();
179  pointer MADNESS_RESTRICT const data = pimpl_->data_;
180  for(size_type i = 0ul; i < n; ++i)
181  data[i] = *it++;
182  }
183 
184  template <typename U>
185  Tensor(const Range& range, const U* u) :
186  pimpl_(std::make_shared<Impl>(range))
187  {
188  math::uninitialized_copy_vector(range.volume(), u, pimpl_->data_);
189  }
190 
192 
195  template <typename T1,
196  typename std::enable_if<is_tensor<T1>::value &&
197  ! std::is_same<T1, Tensor_>::value>::type* = nullptr>
198  Tensor(const T1& other) :
199  pimpl_(std::make_shared<Impl>(detail::clone_range(other)))
200  {
201  auto op =
202  [] (const numeric_t<T1> arg) -> numeric_t<T1>
203  { return arg; };
204 
205  detail::tensor_init(op, *this, other);
206  }
207 
209 
213  template <typename T1,
214  typename std::enable_if<is_tensor<T1>::value>::type* = nullptr>
215  Tensor(const T1& other, const Permutation& perm) :
216  pimpl_(std::make_shared<Impl>(perm * other.range()))
217  {
218  auto op =
219  [] (const numeric_t<T1> arg) -> numeric_t<T1>
220  { return arg; };
221 
222  detail::tensor_init(op, perm, *this, other);
223  }
224 
226 
231  template <typename T1, typename Op,
232  typename std::enable_if<is_tensor<T1>::value
233  && ! std::is_same<typename std::decay<Op>::type,
234  Permutation>::value>::type* = nullptr>
235  Tensor(const T1& other, Op&& op) :
236  pimpl_(std::make_shared<Impl>(detail::clone_range(other)))
237  {
238  detail::tensor_init(op, *this, other);
239  }
240 
242 
247  template <typename T1, typename Op,
248  typename std::enable_if<is_tensor<T1>::value>::type* = nullptr>
249  Tensor(const T1& other, Op&& op, const Permutation& perm) :
250  pimpl_(std::make_shared<Impl>(perm * other.range()))
251  {
252  detail::tensor_init(op, perm, *this, other);
253  }
254 
256 
263  template <typename T1, typename T2, typename Op,
264  typename std::enable_if<is_tensor<T1, T2>::value>::type* = nullptr>
265  Tensor(const T1& left, const T2& right, Op&& op) :
266  pimpl_(std::make_shared<Impl>(detail::clone_range(left)))
267  {
268  detail::tensor_init(op, *this, left, right);
269  }
270 
272 
280  template <typename T1, typename T2, typename Op,
281  typename std::enable_if<is_tensor<T1, T2>::value>::type* = nullptr>
282  Tensor(const T1& left, const T2& right, Op&& op, const Permutation& perm) :
283  pimpl_(std::make_shared<Impl>(perm * left.range()))
284  {
285  detail::tensor_init(op, perm, *this, left, right);
286  }
287 
288  Tensor_ clone() const {
289  Tensor_ result;
290  if(pimpl_) {
291  result = detail::tensor_op<Tensor_>(
292  [] (const numeric_type value) -> numeric_type { return value; },
293  *this);
294  }
295  return result;
296  }
297 
298  template <typename T1,
299  typename std::enable_if<is_tensor<T1>::value>::type* = nullptr>
300  Tensor_& operator=(const T1& other) {
301  detail::inplace_tensor_op([] (reference MADNESS_RESTRICT tr,
302  typename T1::const_reference MADNESS_RESTRICT t1) { tr = t1; }, *this, other);
303 
304  return *this;
305  }
306 
308 
310  const range_type& range() const {
311  return (pimpl_ ? pimpl_->range_ : empty_range_);
312  }
313 
315 
317  size_type size() const {
318  return (pimpl_ ? pimpl_->range_.volume() : 0ul);
319  }
320 
322 
325  TA_ASSERT(pimpl_);
326  TA_ASSERT(pimpl_->range_.includes(i));
327  return pimpl_->data_[i];
328  }
329 
331 
335  TA_ASSERT(pimpl_);
336  TA_ASSERT(pimpl_->range_.includes(i));
337  return pimpl_->data_[i];
338  }
339 
340 
342 
345  template <typename Index,
346  typename std::enable_if<
347  ! std::is_integral<Index>::value>::type* = nullptr>
348  const_reference operator[](const Index& i) const {
349  TA_ASSERT(pimpl_);
350  TA_ASSERT(pimpl_->range_.includes(i));
351  return pimpl_->data_[pimpl_->range_.ordinal(i)];
352  }
353 
355 
358  template <typename Index,
359  typename std::enable_if<
360  ! std::is_integral<Index>::value>::type* = nullptr>
361  reference operator[](const Index& i) {
362  TA_ASSERT(pimpl_);
363  TA_ASSERT(pimpl_->range_.includes(i));
364  return pimpl_->data_[pimpl_->range_.ordinal(i)];
365  }
366 
368 
371  template<typename... Index>
372  reference operator()(const Index&... idx) {
373  TA_ASSERT(pimpl_);
374  TA_ASSERT(pimpl_->range_.includes(idx...));
375  return pimpl_->data_[pimpl_->range_.ordinal(idx...)];
376  }
377 
379 
382  template<typename... Index>
383  const_reference operator()(const Index&... idx) const {
384  TA_ASSERT(pimpl_);
385  TA_ASSERT(pimpl_->range_.includes(idx...));
386  return pimpl_->data_[pimpl_->range_.ordinal(idx...)];
387  }
388 
390 
392  const_iterator begin() const { return (pimpl_ ? pimpl_->data_ : NULL); }
393 
395 
397  iterator begin() { return (pimpl_ ? pimpl_->data_ : NULL); }
398 
400 
402  const_iterator end() const {
403  return (pimpl_ ? pimpl_->data_ + pimpl_->range_.volume() : NULL);
404  }
405 
407 
410  return (pimpl_ ? pimpl_->data_ + pimpl_->range_.volume() : NULL);
411  }
412 
414 
416  const_pointer data() const { return (pimpl_ ? pimpl_->data_ : NULL); }
417 
419 
421  pointer data() { return (pimpl_ ? pimpl_->data_ : NULL); }
422 
424 
427  bool empty() const { return !pimpl_; }
428 
430 
434  template <typename Archive,
435  typename std::enable_if<
437  void serialize(Archive& ar) {
438  if(pimpl_) {
439  ar & pimpl_->range_.volume();
440  ar & madness::archive::wrap(pimpl_->data_, pimpl_->range_.volume());
441  ar & pimpl_->range_;
442  } else {
443  ar & size_type(0ul);
444  }
445  }
446 
448 
452  template <typename Archive,
453  typename std::enable_if<
455  void serialize(Archive& ar) {
456  size_type n = 0ul;
457  ar & n;
458  if(n) {
459  std::shared_ptr<Impl> temp = std::make_shared<Impl>();
460  temp->data_ = temp->allocate(n);
461  try {
462  // need to construct elements of data_ using placement new in case its default ctor is not trivial
463  // N.B. for fundamental types and standard alloc this incurs no overhead (Eigen::aligned_alloc OK also)
464  auto* data_ptr = temp->data_;
465  for(size_type i=0; i!=n; ++i, ++data_ptr)
466  new(static_cast<void*>(data_ptr)) value_type;
467 
468  ar & madness::archive::wrap(temp->data_, n);
469  ar & temp->range_;
470  } catch(...) {
471  temp->deallocate(temp->data_, n);
472  throw;
473  }
474 
475  pimpl_ = temp;
476  } else {
477  pimpl_.reset();
478  }
479  }
480 
482 
484  void swap(Tensor_& other) {
485  std::swap(pimpl_, other.pimpl_);
486  }
487 
488  template <typename Index>
490  block(const Index& lower_bound, const Index& upper_bound) {
491  TA_ASSERT(pimpl_);
493  lower_bound, upper_bound), pimpl_->data_);
494  }
495 
497  block(const std::initializer_list<size_type>& lower_bound,
498  const std::initializer_list<size_type>& upper_bound)
499  {
500  TA_ASSERT(pimpl_);
502  lower_bound, upper_bound), pimpl_->data_);
503  }
504 
505  template <typename Index>
507  block(const Index& lower_bound, const Index& upper_bound) const {
508  TA_ASSERT(pimpl_);
510  lower_bound, upper_bound), pimpl_->data_);
511  }
512 
514  block(const std::initializer_list<size_type>& lower_bound,
515  const std::initializer_list<size_type>& upper_bound) const
516  {
517  TA_ASSERT(pimpl_);
519  lower_bound, upper_bound), pimpl_->data_);
520  }
521 
523 
526  Tensor_ permute(const Permutation& perm) const {
527  return Tensor_(*this, perm);
528  }
529 
530 
532 
536  template <typename Index>
537  Tensor_& shift_to(const Index& bound_shift) {
538  TA_ASSERT(pimpl_);
539  pimpl_->range_.inplace_shift(bound_shift);
540  return *this;
541  }
542 
544 
548  template <typename Index>
549  Tensor_ shift(const Index& bound_shift) const {
550  TA_ASSERT(pimpl_);
551  Tensor_ result = clone();
552  result.shift_to(bound_shift);
553  return result;
554  }
555 
556  // Generic vector operations
557 
559 
566  template <typename Right, typename Op,
567  typename std::enable_if<is_tensor<Right>::value>::type* = nullptr>
568  Tensor_ binary(const Right& right, Op&& op) const {
569  return Tensor_(*this, right, op);
570  }
571 
573 
581  template <typename Right, typename Op,
582  typename std::enable_if<is_tensor<Right>::value>::type* = nullptr>
583  Tensor_ binary(const Right& right, Op&& op, const Permutation& perm) const {
584  return Tensor_(*this, right, op, perm);
585  }
586 
588 
599  template <typename Right, typename Op,
600  typename std::enable_if<is_tensor<Right>::value>::type* = nullptr>
601  Tensor_& inplace_binary(const Right& right, Op&& op) {
602  detail::inplace_tensor_op(op, *this, right);
603  return *this;
604  }
605 
607 
613  template <typename Op>
614  Tensor_ unary(Op&& op) const {
615  return Tensor_(*this, op);
616  }
617 
619 
627  template <typename Op>
628  Tensor_ unary(Op&& op, const Permutation& perm) const {
629  return Tensor_(*this, op, perm);
630  }
631 
633 
638  template <typename Op>
639  Tensor_& inplace_unary(Op&& op) {
640  detail::inplace_tensor_op(op, *this);
641  return *this;
642  }
643 
644  // Scale operation
645 
647 
652  template <typename Scalar,
653  typename std::enable_if<detail::is_numeric<Scalar>::value>::type* = nullptr>
654  Tensor_ scale(const Scalar factor) const {
655  return unary([=] (const numeric_type a) -> numeric_type
656  { return a * factor; });
657  }
658 
660 
666  template <typename Scalar,
667  typename std::enable_if<detail::is_numeric<Scalar>::value>::type* = nullptr>
668  Tensor_ scale(const Scalar factor, const Permutation& perm) const {
669  return unary([=] (const numeric_type a) -> numeric_type
670  { return a * factor; }, perm);
671  }
672 
674 
678  template <typename Scalar,
679  typename std::enable_if<detail::is_numeric<Scalar>::value>::type* = nullptr>
680  Tensor_& scale_to(const Scalar factor) {
681  return inplace_unary([=] (numeric_type& MADNESS_RESTRICT res) { res *= factor; });
682  }
683 
684  // Addition operations
685 
687 
692  template <typename Right,
693  typename std::enable_if<is_tensor<Right>::value>::type* = nullptr>
694  Tensor_ add(const Right& right) const {
695  return binary(right, [] (const numeric_type l,
696  const numeric_t<Right> r)
697  -> numeric_type { return l + r; });
698  }
699 
701 
707  template <typename Right,
708  typename std::enable_if<is_tensor<Right>::value>::type* = nullptr>
709  Tensor_ add(const Right& right, const Permutation& perm) const {
710  return binary(right, [] (const numeric_type l,
711  const numeric_t<Right> r)
712  -> numeric_type { return l + r; }, perm);
713  }
714 
716 
723  template <typename Right, typename Scalar,
724  typename std::enable_if<is_tensor<Right>::value &&
725  detail::is_numeric<Scalar>::value>::type* = nullptr>
726  Tensor_ add(const Right& right, const Scalar factor) const {
727  return binary(right, [=] (const numeric_type l,
728  const numeric_t<Right> r)
729  -> numeric_type { return (l + r) * factor; });
730  }
731 
733 
741  template <typename Right, typename Scalar,
742  typename std::enable_if<is_tensor<Right>::value &&
743  detail::is_numeric<Scalar>::value>::type* = nullptr>
744  Tensor_ add(const Right& right, const Scalar factor,
745  const Permutation& perm) const
746  {
747  return binary(right, [=] (const numeric_type l,
748  const numeric_t<Right> r) -> numeric_type
749  { return (l + r) * factor; }, perm);
750  }
751 
753 
757  Tensor_ add(const numeric_type value) const {
758  return unary([=] (const numeric_type a) -> numeric_type
759  { return a + value; });
760  }
761 
763 
768  Tensor_ add(const numeric_type value, const Permutation& perm) const {
769  return unary([=] (const numeric_type a) -> numeric_type
770  { return a + value; }, perm);
771  }
772 
774 
778  template <typename Right,
779  typename std::enable_if<is_tensor<Right>::value>::type* = nullptr>
780  Tensor_& add_to(const Right& right) {
781  return inplace_binary(right, [] (numeric_type& MADNESS_RESTRICT l,
782  const numeric_t<Right> r) { l += r; });
783  }
784 
786 
792  template <typename Right, typename Scalar,
793  typename std::enable_if<is_tensor<Right>::value &&
794  detail::is_numeric<Scalar>::value>::type* = nullptr>
795  Tensor_& add_to(const Right& right, const Scalar factor) {
796  return inplace_binary(right, [=] (numeric_type& MADNESS_RESTRICT l,
797  const numeric_t<Right> r)
798  { (l += r) *= factor; });
799  }
800 
802 
805  Tensor_& add_to(const numeric_type value) {
806  return inplace_unary([=] (numeric_type& MADNESS_RESTRICT res) { res += value; });
807  }
808 
809  // Subtraction operations
810 
812 
817  template <typename Right,
818  typename std::enable_if<is_tensor<Right>::value>::type* = nullptr>
819  Tensor_ subt(const Right& right) const {
820  return binary(right, [] (const numeric_type l,
821  const numeric_t<Right> r)
822  -> numeric_type { return l - r; });
823  }
824 
826 
832  template <typename Right,
833  typename std::enable_if<is_tensor<Right>::value>::type* = nullptr>
834  Tensor_ subt(const Right& right, const Permutation& perm) const {
835  return binary(right, [] (const numeric_type l,
836  const numeric_t<Right> r)
837  -> numeric_type { return l - r; }, perm);
838  }
839 
841 
848  template <typename Right, typename Scalar,
849  typename std::enable_if<is_tensor<Right>::value &&
850  detail::is_numeric<Scalar>::value>::type* = nullptr>
851  Tensor_ subt(const Right& right, const Scalar factor) const {
852  return binary(right, [=] (const numeric_type l,
853  const numeric_t<Right> r)
854  -> numeric_type { return (l - r) * factor; });
855  }
856 
858 
866  template <typename Right, typename Scalar,
867  typename std::enable_if<is_tensor<Right>::value &&
868  detail::is_numeric<Scalar>::value>::type* = nullptr>
869  Tensor_ subt(const Right& right, const Scalar factor,
870  const Permutation& perm) const
871  {
872  return binary(right, [=] (const numeric_type l,
873  const numeric_t<Right> r)
874  -> numeric_type { return (l - r) * factor; }, perm);
875  }
876 
878 
881  Tensor_ subt(const numeric_type value) const {
882  return add(-value);
883  }
884 
886 
891  Tensor_ subt(const numeric_type value, const Permutation& perm) const {
892  return add(-value, perm);
893  }
894 
896 
900  template <typename Right,
901  typename std::enable_if<is_tensor<Right>::value>::type* = nullptr>
902  Tensor_& subt_to(const Right& right) {
903  return inplace_binary(right, [] (numeric_type& MADNESS_RESTRICT l,
904  const numeric_t<Right> r)
905  { l -= r; });
906  }
907 
909 
915  template <typename Right, typename Scalar,
916  typename std::enable_if<is_tensor<Right>::value &&
917  detail::is_numeric<Scalar>::value>::type* = nullptr>
918  Tensor_& subt_to(const Right& right, const Scalar factor) {
919  return inplace_binary(right, [=] (numeric_type& MADNESS_RESTRICT l,
920  const numeric_t<Right> r)
921  { (l -= r) *= factor; });
922  }
923 
925 
927  Tensor_& subt_to(const numeric_type value) {
928  return add_to(-value);
929  }
930 
931  // Multiplication operations
932 
934 
939  template <typename Right,
940  typename std::enable_if<is_tensor<Right>::value>::type* = nullptr>
941  Tensor_ mult(const Right& right) const {
942  return binary(right, [] (const numeric_type l,
943  const numeric_t<Right> r)
944  -> numeric_type { return l * r; });
945  }
946 
948 
954  template <typename Right,
955  typename std::enable_if<is_tensor<Right>::value>::type* = nullptr>
956  Tensor_ mult(const Right& right, const Permutation& perm) const {
957  return binary(right, [] (const numeric_type l,
958  const numeric_t<Right> r)
959  -> numeric_type { return l * r; }, perm);
960  }
961 
963 
970  template <typename Right, typename Scalar,
971  typename std::enable_if<is_tensor<Right>::value &&
972  detail::is_numeric<Scalar>::value>::type* = nullptr>
973  Tensor_ mult(const Right& right, const Scalar factor) const {
974  return binary(right, [=] (const numeric_type l,
975  const numeric_t<Right> r)
976  -> numeric_type { return (l * r) * factor; });
977  }
978 
980 
988  template <typename Right, typename Scalar,
989  typename std::enable_if<is_tensor<Right>::value &&
990  detail::is_numeric<Scalar>::value>::type* = nullptr>
991  Tensor_ mult(const Right& right, const Scalar factor,
992  const Permutation& perm) const
993  {
994  return binary(right, [=] (const numeric_type l,
995  const numeric_t<Right> r)
996  -> numeric_type { return (l * r) * factor; }, perm);
997  }
998 
1000 
1004  template <typename Right,
1005  typename std::enable_if<is_tensor<Right>::value>::type* = nullptr>
1006  Tensor_& mult_to(const Right& right) {
1007  return inplace_binary(right, [] (numeric_type& MADNESS_RESTRICT l,
1008  const numeric_t<Right> r)
1009  { l *= r; });
1010  }
1011 
1013 
1019  template <typename Right, typename Scalar,
1020  typename std::enable_if<is_tensor<Right>::value &&
1021  detail::is_numeric<Scalar>::value>::type* = nullptr>
1022  Tensor_& mult_to(const Right& right, const Scalar factor) {
1023  return inplace_binary(right, [=] (numeric_type& MADNESS_RESTRICT l,
1024  const numeric_t<Right> r)
1025  { (l *= r) *= factor; });
1026  }
1027 
1028  // Negation operations
1029 
1031 
1033  Tensor_ neg() const {
1034  return unary([] (const numeric_type r) -> numeric_type { return -r; });
1035  }
1036 
1038 
1041  Tensor_ neg(const Permutation& perm) const {
1042  return unary([] (const numeric_type l) -> numeric_type { return -l; },
1043  perm);
1044  }
1045 
1047 
1050  return inplace_unary([] (numeric_type& MADNESS_RESTRICT l) { l = -l; });
1051  }
1052 
1053 
1055 
1058  Tensor_ conj() const {
1059  TA_ASSERT(pimpl_);
1060  return scale(detail::conj_op());
1061  }
1062 
1064 
1069  template <typename Scalar,
1070  typename std::enable_if<detail::is_numeric<Scalar>::value>::type* = nullptr>
1071  Tensor_ conj(const Scalar factor) const {
1072  TA_ASSERT(pimpl_);
1073  return scale(detail::conj_op(factor));
1074  }
1075 
1077 
1081  Tensor_ conj(const Permutation& perm) const {
1082  TA_ASSERT(pimpl_);
1083  return scale(detail::conj_op(), perm);
1084  }
1085 
1087 
1093  template <typename Scalar,
1094  typename std::enable_if<detail::is_numeric<Scalar>::value>::type* = nullptr>
1095  Tensor_ conj(const Scalar factor, const Permutation& perm) const {
1096  TA_ASSERT(pimpl_);
1097  return scale(detail::conj_op(factor), perm);
1098  }
1099 
1101 
1104  TA_ASSERT(pimpl_);
1105  return scale_to(detail::conj_op());
1106  }
1107 
1109 
1113  template <typename Scalar,
1114  typename std::enable_if<detail::is_numeric<Scalar>::value>::type* = nullptr>
1115  Tensor_& conj_to(const Scalar factor) {
1116  TA_ASSERT(pimpl_);
1117  return scale_to(detail::conj_op(factor));
1118  }
1119 
1120  // GEMM operations
1121 
1123 
1132  template <typename U, typename AU, typename V,
1133  typename std::enable_if<!detail::is_tensor_of_tensor<
1134  Tensor_, Tensor<U, AU>>::value>::type* = nullptr>
1135  Tensor_ gemm(const Tensor<U, AU>& other, const V factor,
1136  const math::GemmHelper& gemm_helper) const {
1137  // Check that this tensor is not empty and has the correct rank
1138  TA_ASSERT(pimpl_);
1139  TA_ASSERT(pimpl_->range_.rank() == gemm_helper.left_rank());
1140 
1141  // Check that the arguments are not empty and have the correct ranks
1142  TA_ASSERT(!other.empty());
1143  TA_ASSERT(other.range().rank() == gemm_helper.right_rank());
1144 
1145  // Construct the result Tensor
1146  Tensor_ result(gemm_helper.make_result_range<range_type>(pimpl_->range_, other.range()));
1147 
1148  // Check that the inner dimensions of left and right match
1149  TA_ASSERT(gemm_helper.left_right_congruent(pimpl_->range_.lobound_data(), other.range().lobound_data()));
1150  TA_ASSERT(gemm_helper.left_right_congruent(pimpl_->range_.upbound_data(), other.range().upbound_data()));
1151  TA_ASSERT(gemm_helper.left_right_congruent(pimpl_->range_.extent_data(), other.range().extent_data()));
1152 
1153 
1154  // Compute gemm dimensions
1155  integer m = 1, n = 1, k = 1;
1156  gemm_helper.compute_matrix_sizes(m, n, k, pimpl_->range_, other.range());
1157 
1158  // Get the leading dimension for left and right matrices.
1159  const integer lda = (gemm_helper.left_op() == madness::cblas::NoTrans ? k : m);
1160  const integer ldb = (gemm_helper.right_op() == madness::cblas::NoTrans ? n : k);
1161 
1162  math::gemm(gemm_helper.left_op(), gemm_helper.right_op(), m, n, k, factor,
1163  pimpl_->data_, lda, other.data(), ldb, numeric_type(0), result.data(), n);
1164 
1165  return result;
1166  }
1167 
1169 
1207  template <
1208  typename U, typename AU, typename V, typename AV, typename W,
1209  typename std::enable_if<!detail::is_tensor_of_tensor<
1210  Tensor_, Tensor<U, AU>, Tensor<V, AV>>::value>::type* = nullptr>
1211  Tensor_& gemm(const Tensor<U, AU>& left, const Tensor<V, AV>& right,
1212  const W factor, const math::GemmHelper& gemm_helper) {
1213  // Check that this tensor is not empty and has the correct rank
1214  TA_ASSERT(pimpl_);
1215  TA_ASSERT(pimpl_->range_.rank() == gemm_helper.result_rank());
1216 
1217  // Check that the arguments are not empty and have the correct ranks
1218  TA_ASSERT(!left.empty());
1219  TA_ASSERT(left.range().rank() == gemm_helper.left_rank());
1220  TA_ASSERT(!right.empty());
1221  TA_ASSERT(right.range().rank() == gemm_helper.right_rank());
1222 
1223  // Check that the outer dimensions of left match the corresponding
1224  // dimensions in result
1225  TA_ASSERT(gemm_helper.left_result_congruent(left.range().lobound_data(),
1226  pimpl_->range_.lobound_data()));
1227  TA_ASSERT(gemm_helper.left_result_congruent(left.range().upbound_data(),
1228  pimpl_->range_.upbound_data()));
1229  TA_ASSERT(gemm_helper.left_result_congruent(left.range().extent_data(),
1230  pimpl_->range_.extent_data()));
1231 
1232  // Check that the outer dimensions of right match the corresponding
1233  // dimensions in result
1234  TA_ASSERT(gemm_helper.right_result_congruent(right.range().lobound_data(),
1235  pimpl_->range_.lobound_data()));
1236  TA_ASSERT(gemm_helper.right_result_congruent(right.range().upbound_data(),
1237  pimpl_->range_.upbound_data()));
1238  TA_ASSERT(gemm_helper.right_result_congruent(right.range().extent_data(),
1239  pimpl_->range_.extent_data()));
1240 
1241  // Check that the inner dimensions of left and right match
1242  TA_ASSERT(gemm_helper.left_right_congruent(left.range().lobound_data(),
1243  right.range().lobound_data()));
1244  TA_ASSERT(gemm_helper.left_right_congruent(left.range().upbound_data(),
1245  right.range().upbound_data()));
1246  TA_ASSERT(gemm_helper.left_right_congruent(left.range().extent_data(),
1247  right.range().extent_data()));
1248 
1249  // Compute gemm dimensions
1250  integer m, n, k;
1251  gemm_helper.compute_matrix_sizes(m, n, k, left.range(), right.range());
1252 
1253  // Get the leading dimension for left and right matrices.
1254  const integer lda =
1255  (gemm_helper.left_op() == madness::cblas::NoTrans ? k : m);
1256  const integer ldb =
1257  (gemm_helper.right_op() == madness::cblas::NoTrans ? n : k);
1258 
1259  math::gemm(gemm_helper.left_op(), gemm_helper.right_op(), m, n, k, factor,
1260  left.data(), lda, right.data(), ldb, numeric_type(1), pimpl_->data_, n);
1261 
1262  return *this;
1263  }
1264 
1265  // Reduction operations
1266 
1268 
1273  value_type trace() const {
1274  TA_ASSERT(pimpl_);
1275 
1276  // Get pointers to the range data
1277  const size_type n = pimpl_->range_.rank();
1278  const size_type* MADNESS_RESTRICT const lower = pimpl_->range_.lobound_data();
1279  const size_type* MADNESS_RESTRICT const upper = pimpl_->range_.upbound_data();
1280  const size_type* MADNESS_RESTRICT const stride = pimpl_->range_.stride_data();
1281 
1282  // Search for the largest lower bound and the smallest upper bound
1283  size_type lower_max = 0ul, upper_min =
1285  for(size_type i = 0ul; i < n; ++i) {
1286  const size_type lower_i = lower[i];
1287  const size_type upper_i = upper[i];
1288 
1289  lower_max = std::max(lower_max, lower_i);
1290  upper_min = std::min(upper_min, upper_i);
1291  }
1292 
1293  value_type result = 0;
1294 
1295  if(lower_max < upper_min) {
1296  // Compute the first and last ordinal index
1297  size_type first = 0ul, last = 0ul, trace_stride = 0ul;
1298  for(size_type i = 0ul; i < n; ++i) {
1299  const size_type lower_i = lower[i];
1300  const size_type stride_i = stride[i];
1301 
1302  first += (lower_max - lower_i) * stride_i;
1303  last += (upper_min - lower_i) * stride_i;
1304  trace_stride += stride_i;
1305  }
1306 
1307  // Compute the trace
1308  const value_type* MADNESS_RESTRICT const data = pimpl_->data_;
1309  for(; first < last; first += trace_stride)
1310  result += data[first];
1311  }
1312 
1313  return result;
1314  }
1315 
1317 
1329  template <typename ReduceOp, typename JoinOp, typename Scalar>
1330  decltype(auto) reduce(ReduceOp&& reduce_op, JoinOp&& join_op,
1331  Scalar identity) const
1332  {
1333  return detail::tensor_reduce(reduce_op, join_op, identity, *this);
1334  }
1335 
1337 
1351  template <typename Right, typename ReduceOp, typename JoinOp, typename Scalar,
1352  typename std::enable_if<is_tensor<Right>::value>::type* = nullptr>
1353  decltype(auto) reduce(const Right& other, ReduceOp&& reduce_op, JoinOp&& join_op,
1354  Scalar identity) const
1355  {
1356  return detail::tensor_reduce(reduce_op, join_op, identity, *this, other);
1357  }
1358 
1360 
1362  numeric_type sum() const {
1363  auto sum_op = [] (numeric_type& MADNESS_RESTRICT res, const numeric_type arg)
1364  { res += arg; };
1365  return reduce(sum_op, sum_op, numeric_type(0));
1366  }
1367 
1369 
1372  auto mult_op = [] (numeric_type& MADNESS_RESTRICT res, const numeric_type arg)
1373  { res *= arg; };
1374  return reduce(mult_op, mult_op, numeric_type(1));
1375  }
1376 
1378 
1381  auto square_op = [] (scalar_type& MADNESS_RESTRICT res, const numeric_type arg)
1382  { res += TiledArray::detail::norm(arg); };
1383  auto sum_op = [] (scalar_type& MADNESS_RESTRICT res, const scalar_type arg)
1384  { res += arg; };
1385  return reduce(square_op, sum_op, scalar_type(0));
1386  }
1387 
1389 
1391  scalar_type norm() const {
1392  return std::sqrt(squared_norm());
1393  }
1394 
1396 
1398  template <typename Numeric = numeric_type>
1399  numeric_type min(typename std::enable_if<
1401  nullptr) const {
1402  auto min_op = [](numeric_type& MADNESS_RESTRICT res, const numeric_type arg) {
1403  res = std::min(res, arg);
1404  };
1405  return reduce(min_op, min_op, std::numeric_limits<numeric_type>::max());
1406  }
1407 
1409 
1411  template <typename Numeric = numeric_type>
1412  numeric_type max(typename std::enable_if<
1414  nullptr) const {
1415  auto max_op = [](numeric_type& MADNESS_RESTRICT res, const numeric_type arg) {
1416  res = std::max(res, arg);
1417  };
1418  return reduce(max_op, max_op, std::numeric_limits<scalar_type>::min());
1419  }
1420 
1422 
1425  auto abs_min_op = [] (scalar_type& MADNESS_RESTRICT res, const numeric_type arg)
1426  { res = std::min(res, std::abs(arg)); };
1427  auto min_op = [] (scalar_type& MADNESS_RESTRICT res, const scalar_type arg)
1428  { res = std::min(res, arg); };
1429  return reduce(abs_min_op, min_op, std::numeric_limits<scalar_type>::max());
1430  }
1431 
1433 
1436  auto abs_max_op = [] (scalar_type& MADNESS_RESTRICT res, const numeric_type arg)
1437  { res = std::max(res, std::abs(arg)); };
1438  auto max_op = [] (scalar_type& MADNESS_RESTRICT res, const scalar_type arg)
1439  { res = std::max(res, arg); };
1440  return reduce(abs_max_op, max_op, scalar_type(0));
1441  }
1442 
1444 
1450  template <typename Right,
1451  typename std::enable_if<is_tensor<Right>::value>::type* = nullptr>
1452  numeric_type dot(const Right& other) const {
1453  auto mult_add_op = [] (numeric_type& res, const numeric_type l,
1454  const numeric_t<Right> r)
1455  { res += l * r; };
1456  auto add_op = [] (numeric_type& MADNESS_RESTRICT res, const numeric_type value)
1457  { res += value; };
1458  return reduce(other, mult_add_op, add_op, numeric_type(0));
1459  }
1460 
1462 
1468  template <typename Right,
1469  typename std::enable_if<is_tensor<Right>::value>::type* = nullptr>
1470  numeric_type inner_product(const Right& other) const {
1471  auto mult_add_op = [] (numeric_type& res, const numeric_type l,
1472  const numeric_t<Right> r)
1473  { res += TiledArray::detail::inner_product(l, r); };
1474  auto add_op = [] (numeric_type& MADNESS_RESTRICT res, const numeric_type value)
1475  { res += value; };
1476  return reduce(other, mult_add_op, add_op, numeric_type(0));
1477  }
1478 
1479  }; // class Tensor
1480 
1481  template <typename T, typename A>
1482  const typename Tensor<T, A>::range_type Tensor<T, A>::empty_range_;
1483 
1484  template <typename T, typename A>
1485  bool operator==(const Tensor<T,A>& a, const Tensor<T,A>& b) {
1486  return a.range() == b.range() && std::equal(a.data(), a.data() + a.size(), b.data());
1487  }
1488  template <typename T, typename A>
1489  bool operator!=(const Tensor<T,A>& a, const Tensor<T,A>& b) {
1490  return !(a == b);
1491  }
1492 
1493  // specialize TiledArray::detail::transform for Tensor
1494  namespace detail {
1495  template <typename T, typename A>
1496  struct transform<Tensor<T, A>> {
1497  template <typename Op, typename T1>
1498  Tensor<T, A> operator()(Op&& op, T1&& t1) const {
1499  return Tensor<T, A>(std::forward<T1>(t1), std::forward<Op>(op));
1500  }
1501  template <typename Op, typename T1>
1502  Tensor<T, A> operator()(Op&& op, const Permutation& perm, T1&& t1) const {
1503  return Tensor<T, A>(std::forward<T1>(t1), std::forward<Op>(op), perm);
1504  }
1505  template <typename Op, typename T1, typename T2>
1506  Tensor<T, A> operator()(Op&& op, T1&& t1, T2&& t2) const {
1507  return Tensor<T, A>(std::forward<T1>(t1), std::forward<T2>(t2),
1508  std::forward<Op>(op));
1509  }
1510  template <typename Op, typename T1, typename T2>
1512  const Permutation& perm, T1&& t1, T2&& t2) const {
1513  return Tensor<T, A>(std::forward<T1>(t1), std::forward<T2>(t2),
1514  std::forward<Op>(op), perm);
1515  }
1516  };
1517  } // namespace detail
1518 
1519 #ifndef TILEDARRAY_HEADER_ONLY
1520 
1521  extern template
1522  class Tensor<double, Eigen::aligned_allocator<double> >;
1523  extern template
1524  class Tensor<float, Eigen::aligned_allocator<float> >;
1525  extern template
1526  class Tensor<int, Eigen::aligned_allocator<int> >;
1527  extern template
1528  class Tensor<long, Eigen::aligned_allocator<long> >;
1529 // extern template
1530 // class Tensor<std::complex<double>, Eigen::aligned_allocator<std::complex<double> > >;
1531 // extern template
1532 // class Tensor<std::complex<float>, Eigen::aligned_allocator<std::complex<float> > >;
1533 
1534 #endif // TILEDARRAY_HEADER_ONLY
1535 
1536 } // namespace TiledArray
1537 
1538 #endif // TILEDARRAY_TENSOR_TENSOR_H__INCLUDED
detail::TensorInterface< T, BlockRange > block(const Index &lower_bound, const Index &upper_bound)
Definition: tensor.h:490
allocator_type::const_pointer const_pointer
Element const pointer type.
Definition: tensor.h:45
allocator_type::value_type value_type
Array element type.
Definition: tensor.h:41
constexpr bool operator==(const DenseShape &a, const DenseShape &b)
Definition: dense_shape.h:178
pointer data()
Data direct access.
Definition: tensor.h:421
A (hyperrectangular) interval on , space of integer n-indices.
Definition: range.h:39
void compute_matrix_sizes(integer &m, integer &n, 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:252
void inplace_tensor_op(Op &&op, TR &result, const Ts &... tensors)
In-place tensor operations with contiguous data.
Definition: kernels.h:163
Tensor< T, A > operator()(Op &&op, const Permutation &perm, T1 &&t1) const
Definition: tensor.h:1502
allocator_type::const_reference const_reference
Element reference type.
Definition: tensor.h:43
bool left_result_congruent(const Left &left, const Result &result) const
Test that the outer dimensions of left are congruent (have equal extent) with that of the result tens...
Definition: gemm_helper.h:205
allocator_type::reference reference
Element reference type.
Definition: tensor.h:42
allocator_type::difference_type difference_type
Difference type.
Definition: tensor.h:46
Tensor_ neg(const Permutation &perm) const
Create a negated and permuted copy of this tensor.
Definition: tensor.h:1041
reference operator[](const size_type i)
Element accessor.
Definition: tensor.h:334
const_pointer const_iterator
Element const iterator type.
Definition: tensor.h:48
Tensor_ & add_to(const Right &right)
Add other to this tensor.
Definition: tensor.h:780
An N-dimensional tensor object.
Definition: foreach.h:40
bool right_result_congruent(const Right &right, const Result &result) const
Test that the outer dimensions of right are congruent (have equal extent) with that of the result ten...
Definition: gemm_helper.h:220
void swap(Bitset< B > &b0, Bitset< B > &b1)
Definition: bitset.h:593
Tensor_ permute(const Permutation &perm) const
Create a permuted copy of this tensor.
Definition: tensor.h:526
madness::cblas::CBLAS_TRANSPOSE right_op() const
Definition: gemm_helper.h:274
bool left_right_congruent(const Left &left, const Right &right) const
Test that the inner dimensions of left are congruent (have equal extent) with that of right...
Definition: gemm_helper.h:236
Tensor< T, A > operator()(Op &&op, const Permutation &perm, T1 &&t1, T2 &&t2) const
Definition: tensor.h:1511
std::enable_if<!(std::is_scalar< Arg >::value &&std::is_scalar< Result >::value)>::type uninitialized_copy_vector(const std::size_t n, const Arg *const arg, Result *const result)
Definition: vector_op.h:688
const range_type & range() const
Tensor range object accessor.
Definition: tensor.h:310
Tensor_ scale(const Scalar factor) const
Construct a scaled copy of this tensor.
Definition: tensor.h:654
numeric_type inner_product(const Right &other) const
Vector inner product.
Definition: tensor.h:1470
TiledArray::detail::numeric_type< T >::type numeric_type
the numeric type that supports T
Definition: tensor.h:50
Tensor_ add(const Right &right, const Permutation &perm) const
Add this and other to construct a new, permuted tensor.
Definition: tensor.h:709
TILEDARRAY_FORCE_INLINE R norm(const R r)
Wrapper function for std::norm
Definition: complex.h:89
Tensor_ & add_to(const Right &right, const Scalar factor)
Add other to this tensor, and scale the result.
Definition: tensor.h:795
unsigned int result_rank() const
Result rank accessor.
Definition: gemm_helper.h:134
Tensor_ conj(const Scalar factor, const Permutation &perm) const
Create a complex conjugated, scaled, and permuted copy of this tensor.
Definition: tensor.h:1095
STL namespace.
Type trait for extracting the numeric type of tensors and arrays.
Definition: type_traits.h:479
Tensor(const T1 &other, const Permutation &perm)
Construct a permuted tensor copy.
Definition: tensor.h:215
Tensor_ conj() const
Create a complex conjugated copy of this tensor.
Definition: tensor.h:1058
Tensor_ add(const numeric_type value, const Permutation &perm) const
Add a constant to a permuted copy of this tensor.
Definition: tensor.h:768
Tensor_ subt(const numeric_type value, const Permutation &perm) const
Subtract a constant from a permuted copy of this tensor.
Definition: tensor.h:891
KroneckerDeltaTile< _N >::numeric_type max(const KroneckerDeltaTile< _N > &arg)
Tensor_ mult(const Right &right, const Scalar factor) const
Scale and multiply this by right to create a new tensor.
Definition: tensor.h:973
scalar_type abs_max() const
Absolute maximum element.
Definition: tensor.h:1435
Tensor_ & operator=(const Tensor_ &other)
Definition: tensor.h:122
constexpr bool operator!=(const DenseShape &a, const DenseShape &b)
Definition: dense_shape.h:179
void tensor_init(Op &&op, TR &result, const Ts &... tensors)
Initialize tensor with contiguous tensor arguments.
Definition: kernels.h:366
auto clone_range(const T &tensor)
Create a copy of the range of the tensor.
Definition: utility.h:46
auto abs(const ComplexConjugate< T > &a)
Definition: complex.h:247
Type trait for extracting the scalar type of tensors and arrays.
Definition: type_traits.h:539
Tensor(const Range &range, const U *u)
Definition: tensor.h:185
const_iterator end() const
Iterator factory.
Definition: tensor.h:402
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:166
Tensor_ & inplace_binary(const Right &right, Op &&op)
Use a binary, element wise operation to modify this tensor.
Definition: tensor.h:601
Tensor(const Tensor_ &other)
Definition: tensor.h:119
bool empty() const
Test if the tensor is empty.
Definition: tensor.h:427
customization point transform functionality to tensor class T, useful for nonintrusive extension of T...
Definition: kernels.h:41
Tensor_ mult(const Right &right) const
Multiply this by right to create a new tensor.
Definition: tensor.h:941
std::enable_if<! std::is_scalar< Arg >::value >::type destroy_vector(const std::size_t n, Arg *const arg)
Definition: vector_op.h:720
Tensor_ subt(const Right &right, const Scalar factor, const Permutation &perm) const
Subtract right from this and return the result scaled by a scaling factor and permuted by perm...
Definition: tensor.h:869
TiledArray::detail::scalar_type< T >::type scalar_type
the scalar type that supports T
Definition: tensor.h:52
Tensor_ & mult_to(const Right &right)
Multiply this tensor by right.
Definition: tensor.h:1006
const_pointer data() const
Data direct access.
Definition: tensor.h:416
Tensor_ & gemm(const Tensor< U, AU > &left, const Tensor< V, AV > &right, const W factor, const math::GemmHelper &gemm_helper)
Contract two tensors and accumulate the scaled result to this tensor.
Definition: tensor.h:1211
ordinal_type volume() const
Range volume accessor.
Definition: range.h:642
Tensor_ & operator=(Tensor_ &&other)
Definition: tensor.h:126
const_reference operator[](const Index &i) const
Element accessor.
Definition: tensor.h:348
numeric_type product() const
Product of elements.
Definition: tensor.h:1371
Tensor(const T1 &other, Op &&op, const Permutation &perm)
Copy, modify, and permute the data from other.
Definition: tensor.h:249
const_iterator begin() const
Iterator factory.
Definition: tensor.h:392
const_reference operator[](const size_type i) const
Element accessor.
Definition: tensor.h:324
Tensor(const T1 &left, const T2 &right, Op &&op, const Permutation &perm)
Copy, modify, and permute the data from left, and right.
Definition: tensor.h:282
Tensor_ unary(Op &&op, const Permutation &perm) const
Use a unary, element wise operation to construct a new, permuted tensor.
Definition: tensor.h:628
#define TA_ASSERT(a)
Definition: error.h:107
Tensor_ binary(const Right &right, Op &&op) const
Use a binary, element wise operation to construct a new tensor.
Definition: tensor.h:568
T identity()
identity for group of objects of type T
scalar_type norm() const
Vector 2-norm.
Definition: tensor.h:1391
Tensor_ & subt_to(const Right &right, const Scalar factor)
Subtract right from and scale this tensor.
Definition: tensor.h:918
Tensor_ add(const Right &right) const
Add this and other to construct a new tensors.
Definition: tensor.h:694
Tensor_ subt(const Right &right, const Scalar factor) const
Subtract right from this and return the result scaled by a scaling factor.
Definition: tensor.h:851
Tensor< T, A > operator()(Op &&op, T1 &&t1) const
Definition: tensor.h:1498
Tensor_ add(const Right &right, const Scalar factor, const Permutation &perm) const
Scale and add this and other to construct a new, permuted tensor.
Definition: tensor.h:744
numeric_type max(typename std::enable_if< detail::is_strictly_ordered< Numeric >::value >::type *=nullptr) const
Maximum element.
Definition: tensor.h:1412
Tensor(Tensor_ &&other)
Definition: tensor.h:120
Tensor_ mult(const Right &right, const Permutation &perm) const
Multiply this by right to create a new, permuted tensor.
Definition: tensor.h:956
Tensor< T, A > operator()(Op &&op, T1 &&t1, T2 &&t2) const
Definition: tensor.h:1506
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:640
Tensor(const T1 &other, Op &&op)
Copy and modify the data from other.
Definition: tensor.h:235
Tensor interface for external data.
scalar_type abs_min() const
Absolute minimum element.
Definition: tensor.h:1424
reference operator[](const Index &i)
Element accessor.
Definition: tensor.h:361
Tensor_ conj(const Scalar factor) const
Create a complex conjugated and scaled copy of this tensor.
Definition: tensor.h:1071
Tensor< T, A > Tensor_
This class type.
Definition: tensor.h:37
Tensor_ & scale_to(const Scalar factor)
Scale this tensor.
Definition: tensor.h:680
iterator begin()
Iterator factory.
Definition: tensor.h:397
iterator end()
Iterator factory.
Definition: tensor.h:409
Tensor_ & mult_to(const Right &right, const Scalar factor)
Scale and multiply this tensor by right.
Definition: tensor.h:1022
detail::TensorInterface< T, BlockRange > block(const std::initializer_list< size_type > &lower_bound, const std::initializer_list< size_type > &upper_bound)
Definition: tensor.h:497
Tensor_ & conj_to()
Complex conjugate this tensor.
Definition: tensor.h:1103
Tensor_ subt(const Right &right, const Permutation &perm) const
Subtract right from this and return the result permuted by perm.
Definition: tensor.h:834
numeric_type dot(const Right &other) const
Vector dot (not inner!) product.
Definition: tensor.h:1452
Tensor_ gemm(const Tensor< U, AU > &other, const V factor, const math::GemmHelper &gemm_helper) const
Contract this tensor with other.
Definition: tensor.h:1135
Tensor_ add(const numeric_type value) const
Add a constant to a copy of this tensor.
Definition: tensor.h:757
Range range_type
Tensor range type.
Definition: tensor.h:38
range_type::size_type size_type
size type
Definition: tensor.h:39
detail::TensorInterface< const T, BlockRange > block(const std::initializer_list< size_type > &lower_bound, const std::initializer_list< size_type > &upper_bound) const
Definition: tensor.h:514
Tensor_ scale(const Scalar factor, const Permutation &perm) const
Construct a scaled and permuted copy of this tensor.
Definition: tensor.h:668
unsigned int right_rank() const
Right-hand argument rank accessor.
Definition: gemm_helper.h:144
Tensor_ binary(const Right &right, Op &&op, const Permutation &perm) const
Use a binary, element wise operation to construct a new, permuted tensor.
Definition: tensor.h:583
std::size_t size_type
Size type.
Definition: range.h:42
void serialize(Archive &ar)
Output serialization function.
Definition: tensor.h:437
void gemm(madness::cblas::CBLAS_TRANSPOSE op_a, madness::cblas::CBLAS_TRANSPOSE op_b, const integer m, const integer n, const integer k, const S1 alpha, const T1 *a, const integer lda, const T2 *b, const integer ldb, const S2 beta, T3 *c, const integer ldc)
Definition: blas.h:39
Contraction to *GEMM helper.
Definition: gemm_helper.h:39
size_type size() const
Tensor dimension size accessor.
Definition: tensor.h:317
Permutation of a sequence of objects indexed by base-0 indices.
Definition: permutation.h:119
ComplexConjugate< S > conj_op(const S factor)
ComplexConjugate operator factory function.
Definition: complex.h:181
Tensor_ neg() const
Create a negated copy of this tensor.
Definition: tensor.h:1033
A allocator_type
Allocator type.
Definition: tensor.h:40
Range that references a subblock of another range.
Definition: block_range.h:34
Tensor_ subt(const Right &right) const
Subtract right from this and return the result.
Definition: tensor.h:819
Tensor_ shift(const Index &bound_shift) const
Shift the lower and upper bound of this range.
Definition: tensor.h:549
Tensor_ & operator=(const T1 &other)
Definition: tensor.h:300
pointer iterator
Element iterator type.
Definition: tensor.h:47
value_type trace() const
Generalized tensor trace.
Definition: tensor.h:1273
madness::cblas::CBLAS_TRANSPOSE left_op() const
Definition: gemm_helper.h:273
Tensor_ & inplace_unary(Op &&op)
Use a unary, element wise operation to modify this tensor.
Definition: tensor.h:639
Tensor(const range_type &range)
Construct tensor.
Definition: tensor.h:136
reference operator()(const Index &... idx)
Element accessor.
Definition: tensor.h:372
Tensor_ subt(const numeric_type value) const
Subtract a constant from a copy of this tensor.
Definition: tensor.h:881
Tensor_ & shift_to(const Index &bound_shift)
Shift the lower and upper bound of this tensor.
Definition: tensor.h:537
void swap(Tensor_ &other)
Swap tensor data.
Definition: tensor.h:484
numeric_type sum() const
Sum of elements.
Definition: tensor.h:1362
decltype(auto) reduce(ReduceOp &&reduce_op, JoinOp &&join_op, Scalar identity) const
Unary reduction operation.
Definition: tensor.h:1330
Tensor(const range_type &range, const Value &value)
Construct a tensor with a fill value.
Definition: tensor.h:150
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:579
Tensor(const T1 &left, const T2 &right, Op &&op)
Copy and modify the data from left, and right.
Definition: tensor.h:265
Tensor_ clone() const
Definition: tensor.h:288
allocator_type::pointer pointer
Element pointer type.
Definition: tensor.h:44
scalar_type squared_norm() const
Square of vector 2-norm.
Definition: tensor.h:1380
numeric_type min(typename std::enable_if< detail::is_strictly_ordered< Numeric >::value >::type *=nullptr) const
Minimum element.
Definition: tensor.h:1399
const_reference operator()(const Index &... idx) const
Element accessor.
Definition: tensor.h:383
Tensor(const T1 &other)
Construct a copy of a tensor interface object.
Definition: tensor.h:198
KroneckerDeltaTile< _N >::numeric_type min(const KroneckerDeltaTile< _N > &arg)
Tensor_ & neg_to()
Negate elements of this tensor.
Definition: tensor.h:1049
unsigned int left_rank() const
Left-hand argument rank accessor.
Definition: gemm_helper.h:139
Tensor_ mult(const Right &right, const Scalar factor, const Permutation &perm) const
Scale and multiply this by right to create a new, permuted tensor.
Definition: tensor.h:991
Tensor_ & add_to(const numeric_type value)
Add a constant to this tensor.
Definition: tensor.h:805
Tensor(const range_type &range, InIter it)
Construct an evaluated tensor.
Definition: tensor.h:175
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:65
Tensor_ conj(const Permutation &perm) const
Create a complex conjugated and permuted copy of this tensor.
Definition: tensor.h:1081
detail::TensorInterface< const T, BlockRange > block(const Index &lower_bound, const Index &upper_bound) const
Definition: tensor.h:507
std::enable_if<!(std::is_scalar< Arg >::value &&std::is_scalar< Result >::value)>::type uninitialized_fill_vector(const std::size_t n, const Arg &arg, Result *const result)
Definition: vector_op.h:703
Tensor_ & conj_to(const Scalar factor)
Complex conjugate and scale this tensor.
Definition: tensor.h:1115
Tensor_ unary(Op &&op) const
Use a unary, element wise operation to construct a new tensor.
Definition: tensor.h:614
Tensor_ & subt_to(const Right &right)
Subtract right from this tensor.
Definition: tensor.h:902
Tensor_ add(const Right &right, const Scalar factor) const
Scale and add this and other to construct a new tensor.
Definition: tensor.h:726
Tensor_ & subt_to(const numeric_type value)
Subtract a constant from this tensor.
Definition: tensor.h:927