MADNESS 0.10.1
tensor.h
Go to the documentation of this file.
1/*
2 This file is part of MADNESS.
3
4 Copyright (C) 2007,2010 Oak Ridge National Laboratory
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20 For more information please contact:
21
22 Robert J. Harrison
23 Oak Ridge National Laboratory
24 One Bethel Valley Road
25 P.O. Box 2008, MS-6367
26
27 email: harrisonrj@ornl.gov
28 tel: 865-241-3937
29 fax: 865-572-0680
30*/
31
32#ifndef MADNESS_TENSOR_TENSOR_H__INCLUDED
33#define MADNESS_TENSOR_TENSOR_H__INCLUDED
34
36#include <madness/misc/ran.h>
39
40#include <memory>
41#include <complex>
42#include <vector>
43#include <array>
44#include <cmath>
45#include <cstdlib>
46#include <cstddef>
47
49// #include <madness/world/print.h>
50//
51// typedef std::complex<float> float_complex;
52// typedef std::complex<double> double_complex;
53//
54// // These probably have to be included in this order
55// #include <madness/tensor/tensor_macros.h>
56// #include <madness/tensor/type_data.h>
57// #include <madness/tensor/slice.h>
58// #include <madness/tensor/vector_factory.h>
61#include <madness/tensor/mxm.h>
64
65
66
67/*!
68 \file tensor.h
69 \brief Defines and implements most of Tensor
70 \ingroup tensor
71 \addtogroup tensor
72
73 \par Introduction
74
75 A tensor is a multi-dimensional array and does not incorporate any concepts
76 of covariance and contravariance.
77
78 When a new tensor is created, the underlying data is also allocated.
79 E.g.,
80 \code
81 Tensor<double> a(3,4,5)
82 \endcode
83 creates a new 3-dimensional tensor and allocates a contiguous
84 block of 60 doubles which are initialized to zero. The dimensions
85 (numbered from the left starting at 0) are in C or row-major
86 order. Thus, for the tensor \c a , the stride between successive
87 elements of the right-most dimension is 1. For the middle
88 dimension it is 5. For the left-most dimension it is 20. Thus,
89 the loops
90 \code
91 for (i=0; i<3; ++i)
92 for (j=0; j<4; ++j)
93 for (k=0; k<5; ++k)
94 a(i,j,k) = ...
95 \endcode
96 will go sequentially (and thus efficiently) through memory.
97 If the dimensions have been reordered (e.g., with \c swapdim()
98 or \c map() ), or if the tensor is actually a slice of another
99 tensor, then the layout in memory may be more complex and
100 may not reflect a contiguous block of memory.
101
102 Multiple tensors may be used to provide multiple identical or
103 distinct views of the same data. E.g., in the following
104 \code
105 Tensor<double> a(2,3); // A new tensor initialized to zero
106 Tensor<double> b = a;
107 \endcode
108 \c a and \c b provide identical views of the same data, thus
109 \code
110 b(1,2) = 99;
111 cout << a(1,2) << endl; // Outputs 99
112 cout << b(1,2) << endl; // Outputs 99
113 \endcode
114
115 \par Shallow copy and assignment
116
117 It is important to appreciate that the views and the data are
118 quite independent. In particular, the default copy constructor
119 and assignment operations only copy the tensor (the view) and not
120 the data --- <em> i.e., the copy constructor and assigment operations
121 only take shallow copies</em>. This is for both consistency and
122 efficiency. Thus, assigning one tensor to another generates another
123 view of the same data, replacing any previous view and not moving
124 or copying any of the data.
125 E.g.,
126 \code
127 Tensor<double> a(2,3); // A new tensor initialized to zero
128 Tensor<double> c(3,3,3); // Another new tensor
129 Tensor<double> b = a; // b is a view of the same data as a
130 a = c; // a is now a view of c's data
131 b = c // b is now also a view of c's data and the
132 // data allocated originally for a is freed
133 \endcode
134 The above example also illustrates how reference counting is used
135 to keep track of the underlying data. Once there are no views
136 of the data, it is automatically freed.
137
138 There are only two ways to actually copy the underlying data. A
139 new, complete, and contiguous copy of a tensor and its data may be
140 generated with the \c copy() function. Or, to copy data from one tensor
141 into the data viewed by another tensor, you must use a Slice.
142
143 \par Indexing
144
145 One dimensional tensors (i.e., vectors) may be indexed using
146 either square brackets (e.g., \c v[i] ) or round brackets (e.g.,
147 \c v(i) ). All higher-dimensional tensors must use only round
148 brackets (e.g., \c t(i,j,k) ). This is due to C++'s restriction
149 that the indexing operator (\c [] ) can only have one argument.
150 The indexing operation should generate efficient code.
151
152 For the sake of efficiency, no bounds checking is performed by
153 default by most single element indexing operations. Checking can
154 be enabled at compile time by defining \c -DTENSOR_BOUNDS_CHECKING for
155 application files including \c tensor.h. The MADNESS configure script
156 has the option \c --enable-tensor-bound-checking to define the macro
157 in \c madness_config.h . The general indexing
158 operation that takes a \c std::vector<long> index and all slicing
159 operations always perform bounds checking. To make indexing with
160 checking a bit easier, a factory function has been provided for
161 vectors ... but note you need to explicitly use longs as the
162 index.
163 \code
164 Tensor<long> a(7,7,7);
165 a(3,4,5) += 1; // OK ... adds 1 to element (3,4,5)
166 a(3,4,9) += 1; // BAD ... undetected out-of-bounds access
167 a(vector_factory(3L,4L,9L)) += 1; // OK ... out-bounds access will
168 // be detected at runtime.
169 \endcode
170
171 \par Slicing
172
173 Slices generate sub-tensors --- i.e., views of patches of the
174 data. E.g., to refer to all but the first and last elements in
175 each dimension of a matrix use
176 \code
177 a(Slice(1,-2),Slice(1,-2))
178 \endcode
179 Or to view odd elements in each dimension
180 \code
181 a(Slice(0,-1,2),Slice(0,-1,2))
182 \endcode
183 A slice or patch of a
184 tensor behaves exactly like a tensor \em except for assignment.
185 When a slice is assigned to, the data is copied with the
186 requirement that the source and destinations agree in size and
187 shape (i.e., they conform). Thus, to copy the all of the data
188 from a to b,
189 \code
190 Tensor<double> a(3,4), b(3,4);
191 a = 1; // Set all elements of a to 1
192 b = 2; // Set all elements of b to 2
193 a(Slice(0,-1,1),Slice(0,-1,1)) = b; // Copy all data from b to a
194 a(_,_) = b(_,_); // Copy all data from b to a
195 a(___) = b(___); // Copy all data from b to a
196 a(Slice(1,2),Slice(1,2)) = b; // Error, do not conform
197 \endcode
198 Special slice values \c _ ,\c _reverse, and \c ___ have
199 been defined to refer to all elements in a dimension, all
200 elements in a dimension but reversed, and all elements in all
201 dimensions, respectively.
202
203 \par Iteration and algorithms
204
205 See tensor_macros.h for documentation on the easiest mechanisms for iteration over
206 elements of tensors and tips for optimization. See \c TensorIterator for
207 the most general form of iteration.
208*/
209
210
211#ifndef HAVE_STD_ABS_LONG
212#ifndef HAVE_STD_LABS
213namespace std {
214 static long abs(long a) {
215 return a>=0 ? a : -a;
216 }
217}
218#else
219namespace std {
220 static long abs(long a) {
221 return std::labs(a);
222 }
223}
224#endif
225#endif
226
227
228namespace madness {
229#define IS_ODD(n) ((n)&0x1)
230#define IS_UNALIGNED(p) (((unsigned long)(p))&0x7)
231
232
233 /// For real types return value, for complex return conjugate
234 template <typename Q, bool iscomplex>
236 static Q op(const Q& coeff) {
237 return coeff;
238 }
239 };
240
241 /// For real types return value, for complex return conjugate
242 template <typename Q>
244 static Q op(const Q& coeff) {
245 return conj(coeff);
246 }
247 };
248
249 /// For real types return value, for complex return conjugate
250 template <typename Q>
254
255 namespace detail {
256 template <typename T> T mynorm(T t) {
257 return t*t;
258 }
259 template <typename T=int> double mynorm(int t) {
260 return double(t)*double(t);
261 }
262
263 template <typename T> T mynorm(std::complex<T> t) {
264 return std::norm(t);
265 }
266 }
267
268 template <class T> class SliceTensor;
269
270
271
272 //#define TENSOR_USE_SHARED_ALIGNED_ARRAY
273#ifdef TENSOR_USE_SHARED_ALIGNED_ARRAY
274#define TENSOR_SHARED_PTR detail::SharedAlignedArray
275 // this code has been tested and seems to work correctly on all
276 // tests and moldft ... however initial testing indicated a hard
277 // to measure improvement in thread scaling (from 20 to 60 threads
278 // on cn-mem) and no change in the modest thread count (20)
279 // execution time with tbballoc. hence we are not presently using
280 // it but will test more in the future with different allocators
281 namespace detail {
282 // Minimal ref-counted array with data+counter in one alloc
283 template <typename T> class SharedAlignedArray {
284 T* volatile p;
285 AtomicInt* cnt;
286 void dec() {if (p && ((*cnt)-- == 1)) {free(p); p = 0;}}
287 void inc() {if (p) (*cnt)++;}
288 public:
289 SharedAlignedArray() : p(0), cnt(0) {}
290 T* allocate(std::size_t size, unsigned int alignment) {
291 std::size_t offset = (size*sizeof(T)-1)/sizeof(AtomicInt) + 1; // Where the counter will be
292 std::size_t nbyte = (offset+1)*sizeof(AtomicInt);
293 if (posix_memalign((void **) &p, alignment, nbyte)) throw 1;
294 cnt = (AtomicInt*)(p) + offset;
295 *cnt = 1;
296 return p;
297 }
298 SharedAlignedArray<T>& operator=(const SharedAlignedArray<T>& other) {
299 if (this != &other) {dec(); p = other.p; cnt = other.cnt; inc();}
300 return *this;
301 }
302 void reset() {dec(); p = 0;}
303 ~SharedAlignedArray() {dec();}
304 };
305 }
306#else
307#define TENSOR_SHARED_PTR std::shared_ptr
308#endif
309
310 /// A tensor is a multidimensional array
311
312 /// \ingroup tensor
313 template <class T> class Tensor : public BaseTensor {
314 template <class U> friend class SliceTensor;
315
316 protected:
319
320 void allocate(long nd, const long d[], bool dozero) {
322 if (nd < 0) {
323 _p = 0;
324 _shptr.reset();
325 _size = 0;
326 _ndim = -1;
327 return;
328 }
329
330 TENSOR_ASSERT(nd>0 && nd <= TENSOR_MAXDIM,"invalid ndim in new tensor", nd, 0);
331 // sanity check ... 2GB in doubles
332 for (int i=0; i<nd; ++i) {
333 TENSOR_ASSERT(d[i]>=0 && d[i]<268435456, "invalid dimension size in new tensor",d[i],0);
334 }
335 set_dims_and_size(nd, d);
336 if (_size) {
337 TENSOR_ASSERT(_size>=0 && _size<268435456, "invalid size in new tensor",_size,0);
338 try {
339#if HAVE_IBMBGP
340#define TENSOR_ALIGNMENT 16
341#elif HAVE_IBMBGQ
342#define TENSOR_ALIGNMENT 32
343#elif MADNESS_HAVE_AVX2
344/* 32B alignment is best for performance according to
345 * http://www.nas.nasa.gov/hecc/support/kb/haswell-processors_492.html */
346#define TENSOR_ALIGNMENT 32
347#elif MADNESS_HAVE_AVX512
348/* One can infer from the AVX2 case that 64B alignment helps with 512b SIMD. */
349#define TENSOR_ALIGNMENT 64
350#else
351// Typical cache line size
352#define TENSOR_ALIGNMENT 64
353#endif
354
355#ifdef TENSOR_USE_SHARED_ALIGNED_ARRAY
356 _p = _shptr.allocate(_size, TENSOR_ALIGNMENT);
357#elif defined WORLD_GATHER_MEM_STATS
358 _p = new T[_size];
359 _shptr = std::shared_ptr<T>(_p);
360#else
361 if (posix_memalign((void **) &_p, TENSOR_ALIGNMENT, sizeof(T)*_size)) throw 1;
362 _shptr.reset(_p, &free);
363#endif
364 }
365 catch (...) {
366 // Ideally use if constexpr here but want headers C++14 for cuda compatibility
367MADNESS_PRAGMA_GCC(diagnostic push)
368MADNESS_PRAGMA_GCC(diagnostic ignored "-Warray-bounds")
369 std::printf("new failed nd=%ld type=%ld size=%ld\n", nd, id(), _size);
370 std::printf(" %ld %ld %ld %ld %ld %ld\n",
371 d[0], d[1], d[2], d[3], d[4], d[5]);
372MADNESS_PRAGMA_GCC(diagnostic pop)
373 TENSOR_EXCEPTION("new failed",_size,this);
374 }
375 //std::printf("allocated %p [%ld] %ld\n", _p, size, p.use_count());
376 if (dozero) {
377 //T zero = 0; for (long i=0; i<_size; ++i) _p[i] = zero;
378 // or
379#ifdef HAVE_MEMSET
380 memset((void *) _p, 0, _size*sizeof(T));
381#else
383#endif
384 }
385 }
386 else {
387 _p = 0;
388 _shptr.reset();
389 }
390 }
391
392 // Free memory and restore default constructor state
393 void deallocate() {
394 _p = 0;
395 _shptr.reset();
396 _size = 0;
397 _ndim = -1;
398 }
399
400 public:
401 /// C++ typename of this tensor.
402 typedef T type;
403
404 /// C++ typename of the real type associated with a complex type.
406
407 /// C++ typename of the floating point type associated with scalar real type
409
410 /// Default constructor does not allocate any data and sets ndim=-1, size=0, _p=0, and id.
411 Tensor() : _p(0) {
413 }
414
415 /// Copy constructor is shallow (same as assignment)
416
417 /// \em Caveat \em emptor: The shallow copy constructor has many virtues but
418 /// enables you to violate constness with simple code such as
419 /// \code
420 /// const Tensor<double> a(5);
421 /// Tensor<double> b(a);
422 /// b[1] = 3; // a[1] is now also 3
423 /// \endcode
424 Tensor(const Tensor<T>& t) {
426 *this = t;
427 }
428
429 /// Assignment is shallow (same as copy constructor)
430
431 /// \em Caveat \em emptor: The shallow assignment has many virtues but
432 /// enables you to violate constness with simple code such as
433 /// \code
434 /// const Tensor<double> a(5);
435 /// Tensor<double> b;
436 /// b = a;
437 /// b[1] = 3; // a[1] is now also 3
438 /// \endcode
440 if (this != &t) {
441 _p = t._p;
442 _shptr = t._shptr;
443 _size = t._size;
444 _ndim = t._ndim;
445MADNESS_PRAGMA_GCC(diagnostic push)
446MADNESS_PRAGMA_GCC(diagnostic ignored "-Wmaybe-uninitialized")
447 for (int i=0; i<TENSOR_MAXDIM; ++i) {
448 _dim[i] = t._dim[i];
449 _stride[i] = t._stride[i];
450 }
451MADNESS_PRAGMA_GCC(diagnostic pop)
452 }
453 return *this;
454 }
455
456 /// convenience for testing if tensor is empty (i.e., has no data)
457 explicit operator bool() const noexcept {
458 return this->size() > 0;
459 }
460
461 /// convenience for testing if tensor is empty (i.e., has no data)
462 bool operator!() const noexcept {
463 return !static_cast<bool>(*this);
464 }
465
466
467 /// Type conversion makes a deep copy
468 template <class Q> operator Tensor<Q>() const { // type conv => deep copy
469 Tensor<Q> result = Tensor<Q>(this->_ndim,this->_dim,false);
470 BINARY_OPTIMIZED_ITERATOR(Q, result, const T, (*this), *_p0 = (Q)(*_p1));
471 return result;
472 }
473
474 /// Create and zero new 1-d tensor
475
476 /// @param[in] d0 Size of dimension 0
477 explicit Tensor(long d0) : _p(0) {
478 _dim[0] = d0;
479 allocate(1, _dim, true);
480 }
481
482 /// Create and zero new 2-d tensor
483
484 /// @param[in] d0 Size of dimension 0
485 /// @param[in] d1 Size of dimension 1
486 explicit Tensor(long d0, long d1) : _p(0) {
487 _dim[0] = d0; _dim[1] = d1;
488 allocate(2, _dim, true);
489 }
490
491 /// Create and zero new 3-d tensor
492
493 /// @param[in] d0 Size of dimension 0
494 /// @param[in] d1 Size of dimension 1
495 /// @param[in] d2 Size of dimension 2
496 explicit Tensor(long d0, long d1, long d2) : _p(0) {
497 _dim[0] = d0; _dim[1] = d1; _dim[2] = d2;
498 allocate(3, _dim, true);
499 }
500
501 /// Create and zero new 4-d tensor
502
503 /// @param[in] d0 Size of dimension 0
504 /// @param[in] d1 Size of dimension 1
505 /// @param[in] d2 Size of dimension 2
506 /// @param[in] d3 Size of dimension 3
507 explicit Tensor(long d0, long d1, long d2, long d3) : _p(0) {
508 _dim[0] = d0; _dim[1] = d1; _dim[2] = d2; _dim[3] = d3;
509 allocate(4, _dim, true);
510 }
511
512 /// Create and zero new 5-d tensor
513
514 /// @param[in] d0 Size of dimension 0
515 /// @param[in] d1 Size of dimension 1
516 /// @param[in] d2 Size of dimension 2
517 /// @param[in] d3 Size of dimension 3
518 /// @param[in] d4 Size of dimension 4
519 explicit Tensor(long d0, long d1, long d2, long d3, long d4) : _p(0) {
520 _dim[0] = d0; _dim[1] = d1; _dim[2] = d2; _dim[3] = d3; _dim[4] = d4;
521 allocate(5, _dim, true);
522 }
523
524 /// Create and zero new 6-d tensor
525
526 /// @param[in] d0 Size of dimension 0
527 /// @param[in] d1 Size of dimension 1
528 /// @param[in] d2 Size of dimension 2
529 /// @param[in] d3 Size of dimension 3
530 /// @param[in] d4 Size of dimension 4
531 /// @param[in] d5 Size of dimension 5
532 explicit Tensor(long d0, long d1, long d2, long d3, long d4, long d5) {
533 _dim[0] = d0; _dim[1] = d1; _dim[2] = d2; _dim[3] = d3; _dim[4] = d4; _dim[5] = d5;
534 allocate(6, _dim, true);
535 }
536
537 /// Create and optionally zero new n-d tensor. This is the most general constructor.
538
539 /// @param[in] d Vector containing size of each dimension, number of dimensions inferred from vector size.
540 /// @param[in] dozero If true (default) the tensor is initialized to zero
541 explicit Tensor(const std::vector<long>& d, bool dozero=true) : _p(0) {
542 allocate(d.size(), d.size() ? &(d[0]) : 0, dozero);
543 }
544
545 /// Politically incorrect general constructor.
546
547 /// @param[in] nd Number of dimensions
548 /// @param[in] d Size of each dimension
549 /// @param[in] dozero If true (default) the tensor is initialized to zero
550 explicit Tensor(long nd, const long d[], bool dozero=true) : _p(0) {
551 allocate(nd,d,dozero);
552 }
553
554 /// Inplace fill tensor with scalar
555
556 /// @param[in] x Value used to fill tensor via assigment
557 /// @return %Reference to this tensor
559 UNARY_OPTIMIZED_ITERATOR(T,(*this),*_p0 = x);
560 return *this;
561 }
562
563 /// Inplace fill with a scalar (legacy name)
564
565 /// @param[in] x Value used to fill tensor via assigment
566 /// @return %Reference to this tensor
568 *this = x;
569 return *this;
570 }
571
572 /// Inplace addition of two tensors
573
574 /// @param[in] t Conforming tensor to be added in-place to this tensor
575 /// @return %Reference to this tensor
576 template <typename Q>
578 BINARY_OPTIMIZED_ITERATOR(T, (*this), const T, t, *_p0 += *_p1);
579 return *this;
580 }
581
582 /// Inplace subtraction of two tensors
583
584 /// @param[in] t Conforming tensor to be subtracted in-place from this tensor
585 /// @return %Reference to this tensor
586 template <typename Q>
588 BINARY_OPTIMIZED_ITERATOR(T, (*this), const T, t, *_p0 -= *_p1);
589 return *this;
590 }
591
592 /// Addition of two tensors to produce a new tensor
593
594 /// @param[in] t Conforming tensor to be added out-of-place to this tensor
595 /// @return New tensor
596 template <typename Q>
598 typedef TENSOR_RESULT_TYPE(T,Q) resultT;
599 Tensor<resultT> result(_ndim,_dim,false);
600 TERNARY_OPTIMIZED_ITERATOR(resultT, result, const T, (*this), const Q, t, *_p0 = *_p1 + *_p2);
601 return result;
602 }
603
604 /// Subtraction of two tensors to produce a new tensor
605
606 /// @param[in] t Conforming tensor to be subtracted out-of-place from this tensor
607 /// @return New tensor
608 template <typename Q>
610 typedef TENSOR_RESULT_TYPE(T,Q) resultT;
611 Tensor<resultT> result(_ndim,_dim,false);
612 TERNARY_OPTIMIZED_ITERATOR(resultT, result, const T, (*this), const Q, t, *_p0 = *_p1 - *_p2);
613 return result;
614 }
615
616 /// Multiplication of tensor by a scalar of a supported type to produce a new tensor
617
618 /// @param[in] x Scalar value
619 /// @return New tensor
620 template <typename Q>
622 operator*(const Q& x) const {
623 typedef TENSOR_RESULT_TYPE(T,Q) resultT;
624 Tensor<resultT> result(_ndim,_dim,false);
625 BINARY_OPTIMIZED_ITERATOR(resultT, result, const T, (*this), *_p0 = *_p1 * x);
626 return result;
627 }
628
629 /// Divide tensor by a scalar of a supported type to produce a new tensor
630
631 /// @param[in] x Scalar value
632 /// @return New tensor
633 template <typename Q>
635 operator/(const Q& x) const {
636 typedef TENSOR_RESULT_TYPE(T,Q) resultT;
637 Tensor<resultT> result(_ndim,_dim);
638 BINARY_OPTIMIZED_ITERATOR(resultT, result, const T, (*this), *_p0 = *_p1 / x);
639 return result;
640 }
641
642 /// Add a scalar of the same type to all elements of a tensor producing a new tensor
643
644 /// @param[in] x Scalar value
645 /// @return New tensor
646 template <typename Q>
648 operator+(const Q& x) const {
649 typedef TENSOR_RESULT_TYPE(T,Q) resultT;
650 Tensor<resultT> result(_ndim,_dim);
651 BINARY_OPTIMIZED_ITERATOR(resultT, result, const T, (*this), *_p0 = *_p1 + x);
652 return result;
653 }
654
655 /// Subtract a scalar of the same type from all elements producing a new tensor
656
657 /// @param[in] x Scalar value
658 /// @return New tensor
659 template <typename Q>
661 operator-(const Q& x) const {
662 return (*this) + (-x);
663 }
664
665 /// Unary negation producing a new tensor
666
667 /// @return New tensor
669 Tensor<T> result = Tensor<T>(_ndim,_dim,false);
670 BINARY_OPTIMIZED_ITERATOR(T, result, const T, (*this), *(_p0) = - (*_p1));
671 return result;
672 }
673
674 /// Inplace multiplication by scalar of supported type
675
676 /// @param[in] x Scalar value
677 /// @return %Reference to this tensor
678 template <typename Q>
680 operator*=(const Q& x) {
681 UNARY_OPTIMIZED_ITERATOR(T, (*this), *_p0 *= x);
682 return *this;
683 }
684
685 /// Inplace multiplication by scalar of supported type (legacy name)
686
687 /// @param[in] x Scalar value
688 /// @return %Reference to this tensor
689 template <typename Q>
691 scale(Q x) {
692 return (*this)*=x;
693 }
694
695 /// Inplace increment by scalar of supported type
696
697 /// @param[in] x Scalar value
698 /// @return %Reference to this tensor
699 template <typename Q>
701 operator+=(const Q& x) {
702 UNARY_OPTIMIZED_ITERATOR(T, (*this), *_p0 += x);
703 return *this;
704 }
705
706 /// Inplace decrement by scalar of supported type
707
708 /// @param[in] x Scalar value
709 /// @return %Reference to this tensor
710 template <typename Q>
712 operator-=(const Q& x) {
713 UNARY_OPTIMIZED_ITERATOR(T, (*this), *_p0 -= x);
714 return *this;
715 }
716
717
718 /// Inplace complex conjugate
719
720 /// @return %Reference to this tensor
722 UNARY_OPTIMIZED_ITERATOR(T, (*this), *_p0 = conditional_conj(*_p0));
723 return *this;
724 }
725
726 /// Inplace fill with random values ( \c [0,1] for floats, \c [0,MAXSIZE] for integers)
727
728 /// @return %Reference to this tensor
730 if (iscontiguous()) {
732 }
733 else {
735 }
736 return *this;
737 }
738
739 /// Inplace fill with the index of each element
740
741 /// Each element is assigned it's logical index according to this loop structure
742 /// \code
743 /// Tensor<float> t(5,6,7,...)
744 /// long index=0;
745 /// for (long i=0; i<_dim[0]; ++i)
746 /// for (long j=0; j<_dim[1]; ++j)
747 /// for (long k=0; k<_dim[2]; ++k)
748 /// ...
749 /// tensor(i,j,k,...) = index++
750 /// \endcode
751 ///
752 /// @return %Reference to this tensor
754 long count = 0;
755 UNARY_UNOPTIMIZED_ITERATOR(T,(*this), *_p0 = count++); // Fusedim would be OK
756 return *this;
757 }
758
759 /// Inplace set elements of \c *this less than \c x in absolute magnitude to zero.
760
761 /// @param[in] x Scalar value
762 /// @return %Reference to this tensor
763 Tensor<T>& screen(double x) {
764 T zero = 0;
765 UNARY_OPTIMIZED_ITERATOR(T,(*this), if (std::abs(*_p0)<x) *_p0=zero);
766 return *this;
767 }
768
769
770 /// Return true if bounds checking was enabled at compile time
771
772 /// @return True if bounds checking was enabled at compile time
773 static bool bounds_checking() {
774#ifdef TENSOR_BOUNDS_CHECKING
775 return true;
776#else
777 return false;
778#endif
779 }
780
781 /// 1-d indexing operation using \c [] \em without bounds checking.
782
783 /// @param[in] i index for dimension 0
784 /// @return %Reference to element
785 T& operator[](long i) {
786#ifdef TENSOR_BOUNDS_CHECKING
787 TENSOR_ASSERT(i>=0 && i<_dim[0],"1d bounds check failed dim=0",i,this);
788#endif
789 return _p[i*_stride[0]];
790 }
791
792 /// 1-d indexing operation using \c [] \em without bounds checking.
793
794 /// @param[in] i index for dimension 0
795 /// @return %Reference to element
796 const T& operator[](long i) const {
797#ifdef TENSOR_BOUNDS_CHECKING
798 TENSOR_ASSERT(i>=0 && i<_dim[0],"1d bounds check failed dim=0",i,this);
799#endif
800 return _p[i*_stride[0]];
801 }
802
803 /// 1-d indexing operation \em without bounds checking.
804
805 /// @param[in] i index for dimension 0
806 /// @return %Reference to element
807 T& operator()(long i) {
808#ifdef TENSOR_BOUNDS_CHECKING
809 TENSOR_ASSERT(i>=0 && i<_dim[0],"1d bounds check failed dim=0",i,this);
810#endif
811 return _p[i*_stride[0]];
812 }
813
814 /// 1-d indexing operation \em without bounds checking.
815
816 /// @param[in] i index for dimension 0
817 /// @return %Reference to element
818 const T& operator()(long i) const {
819#ifdef TENSOR_BOUNDS_CHECKING
820 TENSOR_ASSERT(i>=0 && i<_dim[0],"1d bounds check failed dim=0",i,this);
821#endif
822 return _p[i*_stride[0]];
823 }
824
825 /// 2-d indexing operation \em without bounds checking.
826
827 /// @param[in] i index for dimension 0
828 /// @param[in] j index for dimension 1
829 /// @return %Reference to element
830 T& operator()(long i, long j) {
831#ifdef TENSOR_BOUNDS_CHECKING
832 TENSOR_ASSERT(i>=0 && i<_dim[0],"2d bounds check failed dim=0",i,this);
833 TENSOR_ASSERT(j>=0 && j<_dim[1],"2d bounds check failed dim=1",j,this);
834#endif
835 return _p[i*_stride[0]+j*_stride[1]];
836 }
837
838 /// 2-d indexing operation \em without bounds checking.
839
840 /// @param[in] i index for dimension 0
841 /// @param[in] j index for dimension 1
842 /// @return %Reference to element
843 const T& operator()(long i, long j) const {
844#ifdef TENSOR_BOUNDS_CHECKING
845 TENSOR_ASSERT(i>=0 && i<_dim[0],"2d bounds check failed dim=0",i,this);
846 TENSOR_ASSERT(j>=0 && j<_dim[1],"2d bounds check failed dim=1",j,this);
847#endif
848 return _p[i*_stride[0]+j*_stride[1]];
849 }
850
851 /// 3-d indexing operation \em without bounds checking.
852
853 /// @param[in] i index for dimension 0
854 /// @param[in] j index for dimension 1
855 /// @param[in] k index for dimension 2
856 /// @return %Reference to element
857 T& operator()(long i, long j, long k) {
858#ifdef TENSOR_BOUNDS_CHECKING
859 TENSOR_ASSERT(i>=0 && i<_dim[0],"3d bounds check failed dim=0",i,this);
860 TENSOR_ASSERT(j>=0 && j<_dim[1],"3d bounds check failed dim=1",j,this);
861 TENSOR_ASSERT(k>=0 && k<_dim[2],"3d bounds check failed dim=2",k,this);
862#endif
863 return _p[i*_stride[0]+j*_stride[1]+k*_stride[2]];
864 }
865
866 /// 3-d indexing operation \em without bounds checking.
867
868 /// @param[in] i index for dimension 0
869 /// @param[in] j index for dimension 1
870 /// @param[in] k index for dimension 2
871 /// @return %Reference to element
872 const T& operator()(long i, long j, long k) const {
873#ifdef TENSOR_BOUNDS_CHECKING
874 TENSOR_ASSERT(i>=0 && i<_dim[0],"3d bounds check failed dim=0",i,this);
875 TENSOR_ASSERT(j>=0 && j<_dim[1],"3d bounds check failed dim=1",j,this);
876 TENSOR_ASSERT(k>=0 && k<_dim[2],"3d bounds check failed dim=2",k,this);
877#endif
878 return _p[i*_stride[0]+j*_stride[1]+k*_stride[2]];
879 }
880
881 /// 4-d indexing operation \em without bounds checking.
882
883 /// @param[in] i index for dimension 0
884 /// @param[in] j index for dimension 1
885 /// @param[in] k index for dimension 2
886 /// @param[in] l index for dimension 3
887 /// @return %Reference to element
888 T& operator()(long i, long j, long k, long l) {
889#ifdef TENSOR_BOUNDS_CHECKING
890 TENSOR_ASSERT(i>=0 && i<_dim[0],"4d bounds check failed dim=0",i,this);
891 TENSOR_ASSERT(j>=0 && j<_dim[1],"4d bounds check failed dim=1",j,this);
892 TENSOR_ASSERT(k>=0 && k<_dim[2],"4d bounds check failed dim=2",k,this);
893 TENSOR_ASSERT(l>=0 && l<_dim[3],"4d bounds check failed dim=3",l,this);
894#endif
895 return _p[i*_stride[0]+j*_stride[1]+k*_stride[2]+
896 l*_stride[3]];
897 }
898
899 /// 4-d indexing operation \em without bounds checking.
900
901 /// @param[in] i index for dimension 0
902 /// @param[in] j index for dimension 1
903 /// @param[in] k index for dimension 2
904 /// @param[in] l index for dimension 3
905 /// @return %Reference to element
906 const T& operator()(long i, long j, long k, long l) const {
907#ifdef TENSOR_BOUNDS_CHECKING
908 TENSOR_ASSERT(i>=0 && i<_dim[0],"4d bounds check failed dim=0",i,this);
909 TENSOR_ASSERT(j>=0 && j<_dim[1],"4d bounds check failed dim=1",j,this);
910 TENSOR_ASSERT(k>=0 && k<_dim[2],"4d bounds check failed dim=2",k,this);
911 TENSOR_ASSERT(l>=0 && l<_dim[3],"4d bounds check failed dim=3",l,this);
912#endif
913 return _p[i*_stride[0]+j*_stride[1]+k*_stride[2]+
914 l*_stride[3]];
915 }
916
917 /// 5-d indexing operation \em without bounds checking.
918
919 /// @param[in] i index for dimension 0
920 /// @param[in] j index for dimension 1
921 /// @param[in] k index for dimension 2
922 /// @param[in] l index for dimension 3
923 /// @param[in] m index for dimension 4
924 /// @return %Reference to element
925 T& operator()(long i, long j, long k, long l, long m) {
926#ifdef TENSOR_BOUNDS_CHECKING
927 TENSOR_ASSERT(i>=0 && i<_dim[0],"5d bounds check failed dim=0",i,this);
928 TENSOR_ASSERT(j>=0 && j<_dim[1],"5d bounds check failed dim=1",j,this);
929 TENSOR_ASSERT(k>=0 && k<_dim[2],"5d bounds check failed dim=2",k,this);
930 TENSOR_ASSERT(l>=0 && l<_dim[3],"5d bounds check failed dim=3",l,this);
931 TENSOR_ASSERT(m>=0 && m<_dim[4],"5d bounds check failed dim=4",m,this);
932#endif
933 return _p[i*_stride[0]+j*_stride[1]+k*_stride[2]+
934 l*_stride[3]+m*_stride[4]];
935 }
936
937 /// 5-d indexing operation \em without bounds checking.
938
939 /// @param[in] i index for dimension 0
940 /// @param[in] j index for dimension 1
941 /// @param[in] k index for dimension 2
942 /// @param[in] l index for dimension 3
943 /// @param[in] m index for dimension 4
944 /// @return %Reference to element
945 const T& operator()(long i, long j, long k, long l, long m) const {
946#ifdef TENSOR_BOUNDS_CHECKING
947 TENSOR_ASSERT(i>=0 && i<_dim[0],"5d bounds check failed dim=0",i,this);
948 TENSOR_ASSERT(j>=0 && j<_dim[1],"5d bounds check failed dim=1",j,this);
949 TENSOR_ASSERT(k>=0 && k<_dim[2],"5d bounds check failed dim=2",k,this);
950 TENSOR_ASSERT(l>=0 && l<_dim[3],"5d bounds check failed dim=3",l,this);
951 TENSOR_ASSERT(m>=0 && m<_dim[4],"5d bounds check failed dim=4",m,this);
952#endif
953 return _p[i*_stride[0]+j*_stride[1]+k*_stride[2]+
954 l*_stride[3]+m*_stride[4]];
955 }
956
957 /// 6-d indexing operation \em without bounds checking.
958
959 /// @param[in] i index for dimension 0
960 /// @param[in] j index for dimension 1
961 /// @param[in] k index for dimension 2
962 /// @param[in] l index for dimension 3
963 /// @param[in] m index for dimension 4
964 /// @param[in] n index for dimension 5
965 /// @return %Reference to element
966 T& operator()(long i, long j, long k, long l, long m, long n) {
967#ifdef TENSOR_BOUNDS_CHECKING
968 TENSOR_ASSERT(i>=0 && i<_dim[0],"6d bounds check failed dim=0",i,this);
969 TENSOR_ASSERT(j>=0 && j<_dim[1],"6d bounds check failed dim=1",j,this);
970 TENSOR_ASSERT(k>=0 && k<_dim[2],"6d bounds check failed dim=2",k,this);
971 TENSOR_ASSERT(l>=0 && l<_dim[3],"6d bounds check failed dim=3",l,this);
972 TENSOR_ASSERT(m>=0 && m<_dim[4],"6d bounds check failed dim=4",m,this);
973 TENSOR_ASSERT(n>=0 && n<_dim[5],"6d bounds check failed dim=5",n,this);
974#endif
975 return _p[i*_stride[0]+j*_stride[1]+k*_stride[2]+
976 l*_stride[3]+m*_stride[4]+n*_stride[5]];
977 }
978
979 /// 6-d indexing operation \em without bounds checking.
980
981 /// @param[in] i index for dimension 0
982 /// @param[in] j index for dimension 1
983 /// @param[in] k index for dimension 2
984 /// @param[in] l index for dimension 3
985 /// @param[in] m index for dimension 4
986 /// @param[in] n index for dimension 5
987 /// @return %Reference to element
988 const T& operator()(long i, long j, long k, long l, long m, long n) const {
989#ifdef TENSOR_BOUNDS_CHECKING
990 TENSOR_ASSERT(i>=0 && i<_dim[0],"6d bounds check failed dim=0",i,this);
991 TENSOR_ASSERT(j>=0 && j<_dim[1],"6d bounds check failed dim=1",j,this);
992 TENSOR_ASSERT(k>=0 && k<_dim[2],"6d bounds check failed dim=2",k,this);
993 TENSOR_ASSERT(l>=0 && l<_dim[3],"6d bounds check failed dim=3",l,this);
994 TENSOR_ASSERT(m>=0 && m<_dim[4],"6d bounds check failed dim=4",m,this);
995 TENSOR_ASSERT(n>=0 && n<_dim[5],"6d bounds check failed dim=5",n,this);
996#endif
997 return _p[i*_stride[0]+j*_stride[1]+k*_stride[2]+
998 l*_stride[3]+m*_stride[4]+n*_stride[5]];
999 }
1000
1001 /// Politically incorrect general indexing operation \em without bounds checking.
1002
1003 /// @param[in] ind Array containing index for each dimension
1004 /// @return %Reference to element
1005 T& operator()(const long ind[]) {
1006 long offset = 0;
1007 for (int d=0; d<_ndim; ++d) {
1008 long i = ind[d];
1009#ifdef TENSOR_BOUNDS_CHECKING
1010 TENSOR_ASSERT(i>=0 && i<_dim[0],"non-PC general indexing bounds check failed dim=",d,this);
1011#endif
1012 offset += i*_stride[d];
1013 }
1014 return _p[offset];
1015 }
1016
1017 /// Politically incorrect general indexing operation \em without bounds checking.
1018
1019 /// @param[in] ind Array containing index for each dimension
1020 /// @return %Reference to element
1021 const T& operator()(const long ind[]) const {
1022 long offset = 0;
1023 for (int d=0; d<_ndim; ++d) {
1024 long i = ind[d];
1025#ifdef TENSOR_BOUNDS_CHECKING
1026 TENSOR_ASSERT(i>=0 && i<_dim[0],"non-PC general indexing bounds check failed dim=",d,this);
1027#endif
1028 offset += i*_stride[d];
1029 }
1030 return _p[offset];
1031 }
1032
1033 /// General indexing operation \em with bounds checking.
1034
1035 /// @param[in] ind Vector containing index for each dimension
1036 /// @return %Reference to element
1037 T& operator()(const std::vector<long> ind) {
1038 TENSOR_ASSERT(ind.size()>=(unsigned int) _ndim,"invalid number of dimensions",ind.size(),this);
1039 long index=0;
1040 for (long d=0; d<_ndim; ++d) {
1041 TENSOR_ASSERT(ind[d]>=0 && ind[d]<_dim[d],"out-of-bounds access",ind[d],this);
1042 index += ind[d]*_stride[d];
1043 }
1044 return _p[index];
1045 }
1046
1047 /// General indexing operation \em with bounds checking.
1048
1049 /// @param[in] ind Vector containing index for each dimension
1050 /// @return %Reference to element
1051 const T& operator()(const std::vector<long> ind) const {
1052 TENSOR_ASSERT(ind.size()>=(unsigned int) _ndim,"invalid number of dimensions",ind.size(),this);
1053 long index=0;
1054 for (long d=0; d<_ndim; ++d) {
1055 TENSOR_ASSERT(ind[d]>=0 && ind[d]<_dim[d],"out-of-bounds access",ind[d],this);
1056 index += ind[d]*_stride[d];
1057 }
1058 return _p[index];
1059 }
1060
1061 /// General slicing operation
1062
1063 /// @param[in] s Vector containing slice for each dimension
1064 /// @return SliceTensor viewing patch of original tensor
1065 SliceTensor<T> operator()(const std::vector<Slice>& s) {
1066 TENSOR_ASSERT(s.size()>=(unsigned)(this->ndim()), "invalid number of dimensions",
1067 this->ndim(),this);
1068 return SliceTensor<T>(*this,&(s[0]));
1069 }
1070
1071 /// General slicing operation (const)
1072
1073 /// @param[in] s Vector containing slice for each dimension
1074 /// @return Constant Tensor viewing patch of original tensor
1075 const Tensor<T> operator()(const std::vector<Slice>& s) const {
1076 TENSOR_ASSERT(s.size()>=(unsigned)(this->ndim()), "invalid number of dimensions",
1077 this->ndim(),this);
1078 return SliceTensor<T>(*this,&(s[0]));
1079 }
1080
1081 /// General slicing operation
1082
1083 /// @param[in] s array containing slice for each dimension
1084 /// @return SliceTensor viewing patch of original tensor
1085 SliceTensor<T> operator()(const std::array<Slice,TENSOR_MAXDIM>& s) {
1086 return SliceTensor<T>(*this,s);
1087 }
1088
1089 /// General slicing operation (const)
1090
1091 /// @param[in] s array containing slice for each dimension
1092 /// @return Constant Tensor viewing patch of original tensor
1093 const Tensor<T> operator()(const std::array<Slice,TENSOR_MAXDIM>& s) const {
1094 return SliceTensor<T>(*this,s);
1095 }
1096
1097 /// Return a 1d SliceTensor that views the specified range of the 1d Tensor
1098
1099 /// @return SliceTensor viewing patch of original tensor
1101 TENSOR_ASSERT(this->ndim()==1,"invalid number of dimensions",
1102 this->ndim(),this);
1103 Slice s[1] = {s0};
1104 return SliceTensor<T>(*this,s);
1105 }
1106
1107 /// Return a 1d SliceTensor that views the specified range of the 1d Tensor
1108
1109 /// @return Constant Tensor viewing patch of original tensor: \f$ R(*,*,\ldots) \rightarrow I(*,*,\ldots) \f$
1110 const Tensor<T> operator()(const Slice& s0) const {
1111 TENSOR_ASSERT(this->ndim()==1,"invalid number of dimensions",
1112 this->ndim(),this);
1113 Slice s[1] = {s0};
1114 return SliceTensor<T>(*this,s);
1115 }
1116
1117 /// Return a 1d SliceTensor that views the specified range of the 2d Tensor
1118
1119 /// @return SliceTensor viewing patch of original tensor: \f$ R(*) \rightarrow I(i,*) \f$
1120 SliceTensor<T> operator()(long i, const Slice& s1) {
1121 TENSOR_ASSERT(this->ndim()==2,"invalid number of dimensions",
1122 this->ndim(),this);
1123 Slice s[2] = {Slice(i,i,0),s1};
1124 return SliceTensor<T>(*this,s);
1125 }
1126
1127 /// Return a 1d SliceTensor that views the specified range of the 2d Tensor
1128
1129 /// @return Constant Tensor viewing patch of original tensor
1130 const Tensor<T> operator()(long i, const Slice& s1) const {
1131 TENSOR_ASSERT(this->ndim()==2,"invalid number of dimensions",
1132 this->ndim(),this);
1133 Slice s[2] = {Slice(i,i,0),s1};
1134 return SliceTensor<T>(*this,s);
1135 }
1136
1137 /// Return a 1d SliceTensor that views the specified range of the 2d Tensor
1138
1139 /// @return SliceTensor viewing patch of original tensor
1141 TENSOR_ASSERT(this->ndim()==2,"invalid number of dimensions",
1142 this->ndim(),this);
1143 Slice s[2] = {s0,Slice(j,j,0)};
1144 return SliceTensor<T>(*this,s);
1145 }
1146
1147 /// Return a 1d constant Tensor that views the specified range of the 2d Tensor
1148
1149 /// @return Constant Tensor viewing patch of original tensor
1150 const Tensor<T> operator()(const Slice& s0, long j) const {
1151 TENSOR_ASSERT(this->ndim()==2,"invalid number of dimensions",
1152 this->ndim(),this);
1153 Slice s[2] = {s0,Slice(j,j,0)};
1154 return SliceTensor<T>(*this,s);
1155 }
1156
1157 /// Return a 2d SliceTensor that views the specified range of the 2d Tensor
1158
1159 /// @return SliceTensor viewing patch of original tensor
1161 TENSOR_ASSERT(this->ndim()==2,"invalid number of dimensions",
1162 this->ndim(),this);
1163 Slice s[2] = {s0,s1};
1164 return SliceTensor<T>(*this,s);
1165 }
1166
1167 /// Return a 2d constant Tensor that views the specified range of the 2d Tensor
1168
1169 /// @return Constant Tensor viewing patch of original tensor
1170 const Tensor<T> operator()(const Slice& s0, const Slice& s1) const {
1171 TENSOR_ASSERT(this->ndim()==2,"invalid number of dimensions",
1172 this->ndim(),this);
1173 Slice s[2] = {s0,s1};
1174 return SliceTensor<T>(*this,s);
1175 }
1176
1177 /// Return a 3d SliceTensor that views the specified range of the 3d Tensor
1178
1179 /// @return SliceTensor viewing patch of original tensor
1180 SliceTensor<T> operator()(const Slice& s0, const Slice& s1, const Slice& s2) {
1181 TENSOR_ASSERT(this->ndim()==3,"invalid number of dimensions",
1182 this->ndim(),this);
1183 Slice s[3] = {s0,s1,s2};
1184 return SliceTensor<T>(*this,s);
1185 }
1186
1187 /// Return a 3d constant Tensor that views the specified range of the 3d Tensor
1188
1189 /// @return Constant Tensor viewing patch of original tensor
1190 const Tensor<T> operator()(const Slice& s0, const Slice& s1, const Slice& s2) const {
1191 TENSOR_ASSERT(this->ndim()==3,"invalid number of dimensions",
1192 this->ndim(),this);
1193 Slice s[3] = {s0,s1,s2};
1194 return SliceTensor<T>(*this,s);
1195 }
1196
1197 /// Return a 2d SliceTensor that views the specified range of the 3d Tensor
1198
1199 /// @return SliceTensor viewing patch of original tensor
1200 SliceTensor<T> operator()(long i, const Slice& s1, const Slice& s2) {
1201 TENSOR_ASSERT(this->ndim()==3,"invalid number of dimensions",
1202 this->ndim(),this);
1203 Slice s[3] = {Slice(i,i,0),s1,s2};
1204 return SliceTensor<T>(*this,s);
1205 }
1206
1207 /// Return a 2d constant Tensor that views the specified range of the 3d Tensor
1208
1209 /// @return Constant Tensor viewing patch of original tensor
1210 const Tensor<T> operator()(long i, const Slice& s1, const Slice& s2) const {
1211 TENSOR_ASSERT(this->ndim()==3,"invalid number of dimensions",
1212 this->ndim(),this);
1213 Slice s[3] = {Slice(i,i,0),s1,s2};
1214 return SliceTensor<T>(*this,s);
1215 }
1216
1217 /// Return a 2d SliceTensor that views the specified range of the 3d Tensor
1218
1219 /// @return SliceTensor viewing patch of original tensor
1220 SliceTensor<T> operator()(const Slice& s0, long j, const Slice& s2) {
1221 TENSOR_ASSERT(this->ndim()==3,"invalid number of dimensions",
1222 this->ndim(),this);
1223 Slice s[3] = {s0,Slice(j,j,0),s2};
1224 return SliceTensor<T>(*this,s);
1225 }
1226
1227 /// Return a 2d constant Tensor that views the specified range of the 3d Tensor
1228
1229 /// @return Constant Tensor viewing patch of original tensor
1230 const Tensor<T> operator()(const Slice& s0, long j, const Slice& s2) const {
1231 TENSOR_ASSERT(this->ndim()==3,"invalid number of dimensions",
1232 this->ndim(),this);
1233 Slice s[3] = {s0,Slice(j,j,0),s2};
1234 return SliceTensor<T>(*this,s);
1235 }
1236
1237 /// Return a 2d SliceTensor that views the specified range of the 3d Tensor
1238
1239 /// @return SliceTensor viewing patch of original tensor
1240 SliceTensor<T> operator()(const Slice& s0, const Slice& s1, long k) {
1241 TENSOR_ASSERT(this->ndim()==3,"invalid number of dimensions",
1242 this->ndim(),this);
1243 Slice s[3] = {s0,s1,Slice(k,k,0)};
1244 return SliceTensor<T>(*this,s);
1245 }
1246
1247 /// Return a 2d constant Tensor that views the specified range of the 3d Tensor
1248
1249 /// @return Constant Tensor viewing patch of original tensor
1250 const Tensor<T> operator()(const Slice& s0, const Slice& s1, long k) const {
1251 TENSOR_ASSERT(this->ndim()==3,"invalid number of dimensions",
1252 this->ndim(),this);
1253 Slice s[3] = {s0,s1,Slice(k,k,0)};
1254 return SliceTensor<T>(*this,s);
1255 }
1256
1257 /// Return a 1d SliceTensor that views the specified range of the 3d Tensor
1258
1259 /// @return SliceTensor viewing patch of original tensor
1260 SliceTensor<T> operator()(long i, long j, const Slice& s2) {
1261 TENSOR_ASSERT(this->ndim()==3,"invalid number of dimensions",
1262 this->ndim(),this);
1263 Slice s[3] = {Slice(i,i,0),Slice(j,j,0),s2};
1264 return SliceTensor<T>(*this,s);
1265 }
1266
1267 /// Return a 1d constant Tensor that views the specified range of the 3d Tensor
1268
1269 /// @return Constant Tensor viewing patch of original tensor
1270 const Tensor<T> operator()(long i, long j, const Slice& s2) const {
1271 TENSOR_ASSERT(this->ndim()==3,"invalid number of dimensions",
1272 this->ndim(),this);
1273 Slice s[3] = {Slice(i,i,0),Slice(j,j,0),s2};
1274 return SliceTensor<T>(*this,s);
1275 }
1276
1277 /// Return a 1d SliceTensor that views the specified range of the 3d Tensor
1278
1279 /// @return SliceTensor viewing patch of original tensor
1280 SliceTensor<T> operator()(long i, const Slice& s1, long k) {
1281 TENSOR_ASSERT(this->ndim()==3,"invalid number of dimensions",
1282 this->ndim(),this);
1283 Slice s[3] = {Slice(i,i,0),s1,Slice(k,k,0)};
1284 return SliceTensor<T>(*this,s);
1285 }
1286
1287 /// Return a 1d constant Tensor that views the specified range of the 3d Tensor
1288
1289 /// @return Constant Tensor viewing patch of original tensor
1290 const Tensor<T> operator()(long i, const Slice& s1, long k) const {
1291 TENSOR_ASSERT(this->ndim()==3,"invalid number of dimensions",
1292 this->ndim(),this);
1293 Slice s[3] = {Slice(i,i,0),s1,Slice(k,k,0)};
1294 return SliceTensor<T>(*this,s);
1295 }
1296
1297 /// Return a 1d SliceTensor that views the specified range of the 3d Tensor
1298
1299 /// @return SliceTensor viewing patch of original tensor
1300 SliceTensor<T> operator()(const Slice& s0, long j, long k) {
1301 TENSOR_ASSERT(this->ndim()==3,"invalid number of dimensions",
1302 this->ndim(),this);
1303 Slice s[3] = {s0,Slice(j,j,0),Slice(k,k,0)};
1304 return SliceTensor<T>(*this,s);
1305 }
1306
1307 /// Return a 1d constant Tensor that views the specified range of the 3d Tensor
1308
1309 /// @return Constant Tensor viewing patch of original tensor
1310 const Tensor<T> operator()(const Slice& s0, long j, long k) const {
1311 TENSOR_ASSERT(this->ndim()==3,"invalid number of dimensions",
1312 this->ndim(),this);
1313 Slice s[3] = {s0,Slice(j,j,0),Slice(k,k,0)};
1314 return SliceTensor<T>(*this,s);
1315 }
1316
1317 /// Return a 1-4d SliceTensor that views the specified range of the 4d Tensor
1318
1319 /// @return SliceTensor viewing patch of original tensor
1320 SliceTensor<T> operator()(const Slice& s0, const Slice& s1, const Slice& s2,
1321 const Slice& s3) {
1322 TENSOR_ASSERT(this->ndim()==4,"invalid number of dimensions",
1323 this->ndim(),this);
1324 Slice s[4] = {s0,s1,s2,s3};
1325 return SliceTensor<T>(*this,s);
1326 }
1327
1328 /// Return a 1-4d constant Tensor that views the specified range of the 4d Tensor
1329
1330 /// @return Constant Tensor viewing patch of original tensor
1331 const Tensor<T> operator()(const Slice& s0, const Slice& s1, const Slice& s2,
1332 const Slice& s3) const {
1333 TENSOR_ASSERT(this->ndim()==4,"invalid number of dimensions",
1334 this->ndim(),this);
1335 Slice s[4] = {s0,s1,s2,s3};
1336 return SliceTensor<T>(*this,s);
1337 }
1338
1339 /// Return a 1-5d SliceTensor that views the specified range of the 5d Tensor
1340
1341 /// @return SliceTensor viewing patch of original tensor
1342 SliceTensor<T> operator()(const Slice& s0, const Slice& s1, const Slice& s2,
1343 const Slice& s3, const Slice& s4) {
1344 TENSOR_ASSERT(this->ndim()==5,"invalid number of dimensions",
1345 this->ndim(),this);
1346 Slice s[5] = {s0,s1,s2,s3,s4};
1347 return SliceTensor<T>(*this,s);
1348 }
1349
1350 /// Return a 1-5d constant Tensor that views the specified range of the 5d Tensor
1351
1352 /// @return Constant Tensor viewing patch of original tensor
1353 const Tensor<T> operator()(const Slice& s0, const Slice& s1, const Slice& s2,
1354 const Slice& s3, const Slice& s4) const {
1355 TENSOR_ASSERT(this->ndim()==5,"invalid number of dimensions",
1356 this->ndim(),this);
1357 Slice s[5] = {s0,s1,s2,s3,s4};
1358 return SliceTensor<T>(*this,s);
1359 }
1360
1361 /// Return a 1-6d SliceTensor that views the specified range of the 6d Tensor
1362
1363 /// @return SliceTensor viewing patch of original tensor
1364 SliceTensor<T> operator()(const Slice& s0, const Slice& s1, const Slice& s2,
1365 const Slice& s3, const Slice& s4, const Slice& s5) {
1366 TENSOR_ASSERT(this->ndim()==6,"invalid number of dimensions",
1367 this->ndim(),this);
1368 Slice s[6] = {s0,s1,s2,s3,s4,s5};
1369 return SliceTensor<T>(*this,s);
1370 }
1371
1372
1373 /// Return a 1-6d constant Tensor that views the specified range of the 6d Tensor
1374
1375 /// @return Constant Tensor viewing patch of original tensor
1376 const Tensor<T> operator()(const Slice& s0, const Slice& s1, const Slice& s2,
1377 const Slice& s3, const Slice& s4, const Slice& s5) const {
1378 TENSOR_ASSERT(this->ndim()==6,"invalid number of dimensions",
1379 this->ndim(),this);
1380 Slice s[6] = {s0,s1,s2,s3,s4,s5};
1381 return SliceTensor<T>(*this,s);
1382 }
1383
1384 /// Returns new view/tensor reshaping size/number of dimensions to conforming tensor
1385
1386 /// @param[in] ndimnew Number of dimensions in the result
1387 /// @param[in] d Array containing size of each new dimension
1388 /// @return New tensor (viewing same underlying data as the original but with different shape)
1389 Tensor<T> reshape(int ndimnew, const long* d) {
1390 Tensor<T> result(*this);
1391 result.reshape_inplace(ndimnew,d);
1392 return result;
1393 }
1394
1395 /// Returns new view/tensor reshaping size/number of dimensions to conforming tensor
1396
1397 /// @param[in] ndimnew Number of dimensions in the result
1398 /// @param[in] d Array containing size of each new dimension
1399 /// @return New tensor (viewing same underlying data as the original but with different shape)
1400 const Tensor<T> reshape(int ndimnew, const long* d) const {
1401 Tensor<T> result(*const_cast<Tensor<T>*>(this));
1402 result.reshape_inplace(ndimnew,d);
1403 return result;
1404 }
1405
1406 /// Returns new view/tensor reshaping size/number of dimensions to conforming tensor
1407
1408 /// @param[in] d Array containing size of each new dimension
1409 /// @return New tensor (viewing same underlying data as the original but with different shape)
1410 Tensor<T> reshape(const std::vector<long>& d) {
1411 return reshape(d.size(), d.size() ? &d[0] : 0);
1412 }
1413
1414 /// Returns new view/tensor reshaping size/number of dimensions to conforming tensor
1415
1416 /// @param[in] d Array containing size of each new dimension
1417 /// @return New tensor (viewing same underlying data as the original but with different shape)
1418 const Tensor<T> reshape(const std::vector<long>& d) const {
1419 return reshape(d.size(), d.size() ? &d[0] : 0);
1420 }
1421
1422 /// Returns new view/tensor rehapings to conforming 1-d tensor with given dimension
1423
1424 /// @param[in] dim0 Size of new dimension 0
1425 /// @return New tensor (viewing same underlying data as the original but with different shape)
1426 Tensor<T> reshape(long dim0) {
1427 long d[1] = {dim0};
1428 return reshape(1,d);
1429 }
1430 /// Returns new view/tensor rehapings to conforming 1-d tensor with given dimension
1431
1432 /// @param[in] dim0 Size of new dimension 0
1433 /// @return New tensor (viewing same underlying data as the original but with different shape)
1434 const Tensor<T> reshape(long dim0) const {
1435 long d[1] = {dim0};
1436 return reshape(1,d);
1437 }
1438
1439 /// Returns new view/tensor rehaping to conforming 2-d tensor with given dimensions
1440
1441 /// @param[in] dim0 Size of new dimension 0
1442 /// @param[in] dim1 Size of new dimension 1
1443 /// @return New tensor (viewing same underlying data as the original but with different shape)
1444 Tensor<T> reshape(long dim0, long dim1) {
1445 long d[2] = {dim0,dim1};
1446 return reshape(2,d);
1447 }
1448
1449 /// Returns new view/tensor rehaping to conforming 2-d tensor with given dimensions
1450
1451 /// @param[in] dim0 Size of new dimension 0
1452 /// @param[in] dim1 Size of new dimension 1
1453 /// @return New tensor (viewing same underlying data as the original but with different shape)
1454 const Tensor<T> reshape(long dim0, long dim1) const {
1455 long d[2] = {dim0,dim1};
1456 return reshape(2,d);
1457 }
1458
1459 /// Returns new view/tensor rehaping to conforming 3-d tensor with given dimensions
1460
1461 /// @param[in] dim0 Size of new dimension 0
1462 /// @param[in] dim1 Size of new dimension 1
1463 /// @param[in] dim2 Size of new dimension 2
1464 /// @return New tensor (viewing same underlying data as the original but with different shape)
1465 Tensor<T> reshape(long dim0, long dim1, long dim2) {
1466 long d[3] = {dim0,dim1,dim2};
1467 return reshape(3,d);
1468 }
1469
1470 /// Returns new view/tensor rehaping to conforming 3-d tensor with given dimensions
1471
1472 /// @param[in] dim0 Size of new dimension 0
1473 /// @param[in] dim1 Size of new dimension 1
1474 /// @param[in] dim2 Size of new dimension 2
1475 /// @return New tensor (viewing same underlying data as the original but with different shape)
1476 const Tensor<T> reshape(long dim0, long dim1, long dim2) const {
1477 long d[3] = {dim0,dim1,dim2};
1478 return reshape(3,d);
1479 }
1480
1481 /// Returns new view/tensor rehaping to conforming 4-d tensor with given dimensions
1482
1483 /// @param[in] dim0 Size of new dimension 0
1484 /// @param[in] dim1 Size of new dimension 1
1485 /// @param[in] dim2 Size of new dimension 2
1486 /// @param[in] dim3 Size of new dimension 3
1487 /// @return New tensor (viewing same underlying data as the original but with different shape)
1488 Tensor<T> reshape(long dim0, long dim1, long dim2, long dim3) {
1489 long d[4] = {dim0,dim1,dim2,dim3};
1490 return reshape(4,d);
1491 }
1492
1493 /// Returns new view/tensor rehaping to conforming 4-d tensor with given dimensions
1494
1495 /// @param[in] dim0 Size of new dimension 0
1496 /// @param[in] dim1 Size of new dimension 1
1497 /// @param[in] dim2 Size of new dimension 2
1498 /// @param[in] dim3 Size of new dimension 3
1499 /// @return New tensor (viewing same underlying data as the original but with different shape)
1500 const Tensor<T> reshape(long dim0, long dim1, long dim2, long dim3) const {
1501 long d[4] = {dim0,dim1,dim2,dim3};
1502 return reshape(4,d);
1503 }
1504
1505 /// Returns new view/tensor rehaping to conforming 5-d tensor with given dimensions
1506
1507 /// @param[in] dim0 Size of new dimension 0
1508 /// @param[in] dim1 Size of new dimension 1
1509 /// @param[in] dim2 Size of new dimension 2
1510 /// @param[in] dim3 Size of new dimension 3
1511 /// @param[in] dim4 Size of new dimension 4
1512 /// @return New tensor (viewing same underlying data as the original but with different shape)
1513 Tensor<T> reshape(long dim0, long dim1, long dim2, long dim3, long dim4) {
1514 long d[5] = {dim0,dim1,dim2,dim3,dim4};
1515 return reshape(5,d);
1516 }
1517
1518 /// Returns new view/tensor rehaping to conforming 5-d tensor with given dimensions
1519
1520 /// @param[in] dim0 Size of new dimension 0
1521 /// @param[in] dim1 Size of new dimension 1
1522 /// @param[in] dim2 Size of new dimension 2
1523 /// @param[in] dim3 Size of new dimension 3
1524 /// @param[in] dim4 Size of new dimension 4
1525 /// @return New tensor (viewing same underlying data as the original but with different shape)
1526 const Tensor<T> reshape(long dim0, long dim1, long dim2, long dim3, long dim4) const {
1527 long d[5] = {dim0,dim1,dim2,dim3,dim4};
1528 return reshape(5,d);
1529 }
1530
1531 /// Returns new view/tensor rehaping to conforming 6-d tensor with given dimensions
1532
1533 /// @param[in] dim0 Size of new dimension 0
1534 /// @param[in] dim1 Size of new dimension 1
1535 /// @param[in] dim2 Size of new dimension 2
1536 /// @param[in] dim3 Size of new dimension 3
1537 /// @param[in] dim4 Size of new dimension 4
1538 /// @param[in] dim5 Size of new dimension 5
1539 /// @return New tensor (viewing same underlying data as the original but with different shape)
1540 Tensor<T> reshape(long dim0, long dim1, long dim2, long dim3, long dim4, long dim5) {
1541 long d[6] = {dim0,dim1,dim2,dim3,dim4,dim5};
1542 return reshape(6,d);
1543 }
1544
1545 /// Returns new view/tensor rehaping to conforming 6-d tensor with given dimensions
1546
1547 /// @param[in] dim0 Size of new dimension 0
1548 /// @param[in] dim1 Size of new dimension 1
1549 /// @param[in] dim2 Size of new dimension 2
1550 /// @param[in] dim3 Size of new dimension 3
1551 /// @param[in] dim4 Size of new dimension 4
1552 /// @param[in] dim5 Size of new dimension 5
1553 /// @return New tensor (viewing same underlying data as the original but with different shape)
1554 const Tensor<T> reshape(long dim0, long dim1, long dim2, long dim3, long dim4, long dim5) const {
1555 long d[6] = {dim0,dim1,dim2,dim3,dim4,dim5};
1556 return reshape(6,d);
1557 }
1558
1559 /// Returns new view/tensor rehshaping to flat (1-d) tensor
1561 long d[1] = {_size};
1562 return reshape(1,d);
1563 }
1564
1565 /// Returns new view/tensor rehshaping to flat (1-d) tensor
1566 const Tensor<T> flat() const {
1567 long d[1] = {_size};
1568 return reshape(1,d);
1569 }
1570
1571 /// Returns new view/tensor splitting dimension \c i as \c dimi0*dimi1 to produce conforming d+1 dimension tensor
1572
1573 /// @return New tensor (viewing same underlying data as the original but with additional dimensions)
1574 Tensor<T> splitdim(long i, long dimi0, long dimi1) {
1575 Tensor<T> result(*this);
1576 result.splitdim_inplace(i, dimi0, dimi1);
1577 return result;
1578 }
1579
1580 /// Returns new view/tensor splitting dimension \c i as \c dimi0*dimi1 to produce conforming d+1 dimension tensor
1581
1582 /// @return New tensor (viewing same underlying data as the original but with additional dimensions)
1583 const Tensor<T> splitdim(long i, long dimi0, long dimi1) const {
1584 Tensor<T> result(*const_cast<Tensor<T>*>(this));
1585 result.splitdim_inplace(i, dimi0, dimi1);
1586 return result;
1587 }
1588
1589 /// Returns new view/tensor fusing contiguous dimensions \c i and \c i+1
1590
1591 /// @return New tensor (viewing same underlying data as the original but with fewer dimensions)
1593 Tensor<T> result(*this);
1594 result.fusedim_inplace(i);
1595 return result;
1596 }
1597
1598 /// Returns new view/tensor fusing contiguous dimensions \c i and \c i+1
1599
1600 /// @return New tensor (viewing same underlying data as the original but with fewer dimensions)
1601 const Tensor<T> fusedim(long i) const {
1602 Tensor<T> result(*const_cast<Tensor<T>*>(this));
1603 result.fusedim_inplace(i);
1604 return result;
1605 }
1606
1607 /// Returns new view/tensor swaping dimensions \c i and \c j
1608
1609 /// @return New tensor (viewing same underlying data as the original but with reordered dimensions)
1610 Tensor<T> swapdim(long idim, long jdim) {
1611 Tensor<T> result(*this);
1612 result.swapdim_inplace(idim, jdim);
1613 return result;
1614 }
1615
1616 /// Returns new view/tensor swaping dimensions \c i and \c j
1617
1618 /// @return New tensor (viewing same underlying data as the original but with reordered dimensions)
1619 const Tensor<T> swapdim(long idim, long jdim) const {
1620 Tensor<T> result(*const_cast<Tensor<T>*>(this));
1621 result.swapdim_inplace(idim, jdim);
1622 return result;
1623 }
1624
1625 /// Returns new view/tensor permuting the dimensions
1626
1627 /// @param[in] map Old dimension i becomes new dimension \c map[i]
1628 /// @return New tensor (viewing same underlying data as the original but with reordered dimensions)
1629 Tensor<T> mapdim(const std::vector<long>& map) {
1630 Tensor<T> result(*this);
1631 result.mapdim_inplace(map);
1632 return result;
1633 }
1634
1635 /// Returns new view/tensor permuting the dimensions
1636
1637 /// @return New tensor (viewing same underlying data as the original but with reordered dimensions)
1638 const Tensor<T> mapdim(const std::vector<long>& map) const {
1639 Tensor<T> result(*const_cast<Tensor<T>*>(this));
1640 result.mapdim_inplace(map);
1641 return result;
1642 }
1643
1644
1645 /// Returns new view/tensor cycling the sub-dimensions `(start,...,end)` with `shift` steps
1646 Tensor<T> cycledim(long nshift, long start, long end) {
1647 Tensor<T> result(*this);
1648 result.cycledim_inplace(nshift, start, end);
1649 return result;
1650 }
1651
1652
1653 /// Returns new view/tensor cycling the sub-dimensions `(start,...,end)` with `shift` steps
1654 const Tensor<T> cycledim(long nshift, long start, long end) const {
1655 Tensor<T> result(*const_cast<Tensor<T>*>(this));
1656 result.cycledim_inplace(nshift, start, end);
1657 return result;
1658 }
1659
1660
1661 /// Test if \c *this and \c t conform.
1662 template <class Q> bool conforms(const Tensor<Q>& t) const {
1663 return BaseTensor::conforms(&t);
1664 }
1665
1666 /// Returns the sum of all elements of the tensor
1667 T sum() const {
1668 T result = 0;
1669 UNARY_OPTIMIZED_ITERATOR(const T,(*this),result += *_p0);
1670 return result;
1671 }
1672
1673 /// Returns the sum of the squares of the elements
1674 T sumsq() const {
1675 T result = 0;
1676 UNARY_OPTIMIZED_ITERATOR(const T,(*this),result += (*_p0) * (*_p0));
1677 return result;
1678 }
1679
1680 /// Return the product of all elements of the tensor
1681 T product() const {
1682 T result = 1;
1683 UNARY_OPTIMIZED_ITERATOR(const T,(*this),result *= *_p0);
1684 return result;
1685 }
1686
1687 /// Return the minimum value (and if ind is non-null, its index) in the Tensor
1688 T min(long* ind=0) const {
1689 T result = *(this->_p);
1690 if (ind) {
1691 for (long i=0; i<_ndim; ++i) ind[i]=0;
1692 long nd = _ndim-1;
1693 UNARY_UNOPTIMIZED_ITERATOR(const T,(*this),
1694 if (result > *_p0) {
1695 result = *_p0;
1696 for (long i=0; i<nd; ++i) ind[i]=iter.ind[i];
1697 ind[nd] = _j;
1698 }
1699 );
1700 }
1701 else {
1702 UNARY_OPTIMIZED_ITERATOR(const T,(*this),result=std::min<T>(result,*_p0));
1703 }
1704 return result;
1705 }
1706
1707 /// Return the maximum value (and if ind is non-null, its index) in the Tensor
1708 T max(long* ind=0) const {
1709 T result = *(this->_p);
1710 if (ind) {
1711 for (long i=0; i<_ndim; ++i) ind[i]=0;
1712 long nd = _ndim-1;
1713 UNARY_UNOPTIMIZED_ITERATOR(const T,(*this),
1714 if (result < *_p0) {
1715 result = *_p0;
1716 for (long i=0; i<nd; ++i) ind[i]=iter.ind[i];
1717 ind[nd] = _j;
1718 }
1719 );
1720 }
1721 else {
1722 UNARY_OPTIMIZED_ITERATOR(const T,(*this),result=std::max<T>(result,*_p0));
1723 }
1724 return result;
1725 }
1726
1727 // For complex types, this next group returns the appropriate real type
1728 // For real types, the same type as T is returned (type_data.h)
1729
1730 /// Returns the Frobenius norm of the tensor
1732 float_scalar_type result = 0;
1733 UNARY_OPTIMIZED_ITERATOR(const T,(*this),result += ::madness::detail::mynorm(*_p0));
1734 return (float_scalar_type) std::sqrt(result);
1735 }
1736
1737 /// Return the absolute minimum value (and if ind is non-null, its index) in the Tensor
1738 scalar_type absmin(long *ind = 0) const {
1739 scalar_type result = std::abs(*(this->_p));
1740 if (ind) {
1741 for (long i=0; i<_ndim; ++i) ind[i]=0;
1742 long nd = _ndim-1;
1743 UNARY_UNOPTIMIZED_ITERATOR(const T,(*this),
1744 scalar_type absval = std::abs(*_p0);
1745 if (result > absval) {
1746 result = absval;
1747 for (long i=0; i<nd; ++i) ind[i]=iter.ind[i];
1748 ind[nd] = _j;
1749 }
1750 );
1751 }
1752 else {
1753 UNARY_OPTIMIZED_ITERATOR(const T,(*this),result=std::min<scalar_type>(result,std::abs(*_p0)));
1754 }
1755 return result;
1756 }
1757
1758 /// Return the absolute maximum value (and if ind is non-null, its index) in the Tensor
1759 scalar_type absmax(long *ind = 0) const {
1760 scalar_type result = std::abs(*(this->_p));
1761 if (ind) {
1762 for (long i=0; i<_ndim; ++i) ind[i]=0;
1763 long nd = _ndim-1;
1765 scalar_type absval = std::abs(*_p0);
1766 if (result < absval) {
1767 result = absval;
1768 for (long i=0; i<nd; ++i) ind[i]=iter.ind[i];
1769 ind[nd] = _j;
1770 }
1771 );
1772 }
1773 else {
1774 UNARY_OPTIMIZED_ITERATOR(const T,(*this),result=std::max<scalar_type>(result,std::abs(*_p0)));
1775 }
1776 return result;
1777 }
1778
1779
1780 /// Return the trace of two tensors (no complex conjugate invoked)
1781 template <class Q>
1782 TENSOR_RESULT_TYPE(T,Q) trace(const Tensor<Q>& t) const {
1783 TENSOR_RESULT_TYPE(T,Q) result = 0;
1784 BINARY_OPTIMIZED_ITERATOR(const T,(*this),const Q,t,result += (*_p0)*(*_p1));
1785 return result;
1786 }
1787
1788 /// Return the trace of two tensors with complex conjugate of the leftmost (i.e., this)
1789 template <class Q>
1790 TENSOR_RESULT_TYPE(T,Q) trace_conj(const Tensor<Q>& t) const {
1791 TENSOR_RESULT_TYPE(T,Q) result = 0;
1792 BINARY_OPTIMIZED_ITERATOR(const T,(*this),const Q,t,result += conditional_conj(*_p0)*(*_p1));
1793 return result;
1794 }
1795
1796 /// Inplace apply a unary function to each element of the tensor
1797 template <typename opT>
1799 UNARY_OPTIMIZED_ITERATOR(T,(*this),*_p0=op(*_p0));
1800 return *this;
1801 }
1802
1803 /// Inplace multiply by corresponding elements of argument Tensor
1805 BINARY_OPTIMIZED_ITERATOR(T,(*this),const T,t,*_p0 *= *_p1);
1806 return *this;
1807 }
1808
1809 /// Inplace generalized saxpy ... this = this*alpha + other*beta
1810 Tensor<T>& gaxpy(T alpha, const Tensor<T>& other, T beta) {
1811 if (alpha == T(1)) {
1812 if (beta == T(1)) {
1813 BINARY_OPTIMIZED_ITERATOR(T, (*this), const T, other, (*_p0) += (*_p1));
1814 }
1815 else if (beta == T(0)) {
1816 // noop
1817 }
1818 else {
1819 BINARY_OPTIMIZED_ITERATOR(T, (*this), const T, other, (*_p0) += beta * (*_p1));
1820 }
1821 }
1822 else if (alpha == T(0)) {
1823 if (beta == T(1)) {
1824 BINARY_OPTIMIZED_ITERATOR(T, (*this), const T, other, (*_p0) = (*_p1));
1825 }
1826 else if (beta == T(0)) {
1827 *this = T(0);
1828 }
1829 else {
1830 BINARY_OPTIMIZED_ITERATOR(T, (*this), const T, other, (*_p0) = beta * (*_p1));
1831 }
1832 } else {
1833 if (beta == T(1)) {
1834 BINARY_OPTIMIZED_ITERATOR(T, (*this), const T, other, (*_p0) = alpha * (*_p0) + (*_p1));
1835 } else if (beta == T(0)) {
1836 BINARY_OPTIMIZED_ITERATOR(T, (*this), const T, other, (*_p0) = alpha * (*_p0));
1837 } else {
1838 BINARY_OPTIMIZED_ITERATOR(T, (*this), const T, other, (*_p0) = alpha * (*_p0) + beta * (*_p1));
1839 }
1840 }
1841 return *this;
1842 }
1843
1844 /// Returns a pointer to the internal data
1845 T* ptr() {
1846 return _p;
1847 }
1848
1849 /// Returns a pointer to the internal data
1850 const T* ptr() const {
1851 return _p;
1852 }
1853
1854 /// Returns a pointer to the base class
1856 return static_cast<BaseTensor*>(this);
1857 }
1858
1859 /// Returns a pointer to the base class
1860 const BaseTensor* base() const {
1861 return static_cast<const BaseTensor*>(this);
1862 }
1863
1864 /// Return iterator over single tensor
1866 bool optimize=true,
1867 bool fusedim=true,
1868 long jdim=default_jdim) const {
1869 return TensorIterator<T>(this,(const Tensor<T>*) 0, (const Tensor<T>*) 0,
1870 iterlevel, optimize, fusedim, jdim);
1871 }
1872
1873 /// Return iterator over two tensors
1874 template <class Q>
1876 long iterlevel=0,
1877 bool optimize=true,
1878 bool fusedim=true,
1879 long jdim=default_jdim) const {
1880 return TensorIterator<T,Q>(this,&q,(const Tensor<T>*) 0,
1881 iterlevel, optimize, fusedim, jdim);
1882 }
1883
1884 /// Return iterator over three tensors
1885 template <class Q, class R>
1887 const Tensor<R>& r,
1888 long iterlevel=0,
1889 bool optimize=true,
1890 bool fusedim=true,
1891 long jdim=default_jdim) const {
1892 return TensorIterator<T,Q,R>(this,&q,&r,
1893 iterlevel, optimize, fusedim, jdim);
1894 }
1895
1896 /// End point for forward iteration
1897 const TensorIterator<T>& end() const {
1898 static TensorIterator<T> theend(0,0,0,0,0,0);
1899 return theend;
1900 }
1901
1902 virtual ~Tensor() {}
1903
1904 /// Frees all memory and resests to state of default constructor
1905 void clear() {deallocate();}
1906
1907 bool has_data() const {return size()!=0;};
1908
1909 };
1910
1911 template <class T>
1912 std::ostream& operator << (std::ostream& out, const Tensor<T>& t);
1913
1914
1915 namespace archive {
1916 /// Serialize a tensor
1917 template <class Archive, typename T>
1918 struct ArchiveStoreImpl< Archive, Tensor<T> > {
1919 static void store(const Archive& s, const Tensor<T>& t) {
1920 if (t.iscontiguous()) {
1921 s & t.size() & t.id();
1922 if (t.size()) s & t.ndim() & wrap(t.dims(),TENSOR_MAXDIM) & wrap(t.ptr(),t.size());
1923 }
1924 else {
1925 s & copy(t);
1926 }
1927 };
1928 };
1929
1930
1931 /// Deserialize a tensor ... existing tensor is replaced
1932 template <class Archive, typename T>
1933 struct ArchiveLoadImpl< Archive, Tensor<T> > {
1934 static void load(const Archive& s, Tensor<T>& t) {
1935 long sz = 0l, id = 0l;
1936 s & sz & id;
1937 if (id != t.id()) throw "type mismatch deserializing a tensor";
1938 if (sz) {
1939 long _ndim = 0l, _dim[TENSOR_MAXDIM];
1940 s & _ndim & wrap(_dim,TENSOR_MAXDIM);
1941 t = Tensor<T>(_ndim, _dim, false);
1942 if (sz != t.size()) throw "size mismatch deserializing a tensor";
1943 s & wrap(t.ptr(), t.size());
1944 }
1945 else {
1946 t = Tensor<T>();
1947 }
1948 };
1949 };
1950
1951 }
1952
1953 /// The class defines tensor op scalar ... here define scalar op tensor.
1954
1955 /// \ingroup tensor
1956 template <typename T, typename Q>
1957 typename IsSupported < TensorTypeData<Q>, Tensor<T> >::type
1958 operator+(Q x, const Tensor<T>& t) {
1959 return t+x;
1960 }
1961
1962 /// The class defines tensor op scalar ... here define scalar op tensor.
1963
1964 /// \ingroup tensor
1965 template <typename T, typename Q>
1966 typename IsSupported < TensorTypeData<Q>, Tensor<T> >::type
1967 operator*(const Q& x, const Tensor<T>& t) {
1968 return t*x;
1969 }
1970
1971 /// The class defines tensor op scalar ... here define scalar op tensor.
1972
1973 /// \ingroup tensor
1974 template <typename T, typename Q>
1975 typename IsSupported < TensorTypeData<Q>, Tensor<T> >::type
1976 operator-(Q x, const Tensor<T>& t) {
1977 return (-t)+=x;
1978 }
1979
1980 /// Returns a new contiguous tensor that is a deep copy of the input
1981
1982 /// \ingroup tensor
1983 /// @result Returns a new contiguous tensor that is a deep copy of the input
1984 template <class T> Tensor<T> copy(const Tensor<T>& t) {
1985 if (t.size()) {
1986 Tensor<T> result = Tensor<T>(t.ndim(),t.dims(),false);
1987 BINARY_OPTIMIZED_ITERATOR(T, result, const T, t, *_p0 = *_p1);
1988 return result;
1989 }
1990 else {
1991 return Tensor<T>();
1992 }
1993 }
1994
1995 /// Returns a new contiguous tensor of type Q that is a deep copy of the input
1996
1997 /// \ingroup tensor
1998 /// @result Returns a new contiguous tensor that is a deep copy of the input
1999 template <class Q, class T>
2001 if (t.size()) {
2002 Tensor<Q> result = Tensor<Q>(t.ndim(),t.dims(),false);
2003 BINARY_OPTIMIZED_ITERATOR(Q, result, const T, t, *_p0 = *_p1);
2004 return result;
2005 }
2006 else {
2007 return Tensor<Q>();
2008 }
2009 }
2010
2011
2012 /// Transforms one dimension of the tensor t by the matrix c, returns new contiguous tensor
2013
2014 /// \ingroup tensor
2015 /// \code
2016 /// transform_dir(t,c,1) = r(i,j,k,...) = sum(j') t(i,j',k,...) * c(j',j)
2017 /// \endcode
2018 /// @param[in] t Tensor to transform (size of dimension to be transformed must match size of first dimension of \c c )
2019 /// @param[in] c Matrix used for the transformation
2020 /// @param[in] axis Dimension (or axis) to be transformed
2021 /// @result Returns a new, contiguous tensor
2022 template <class T, class Q>
2024 if (axis == 0) {
2025 return inner(c,t,0,axis);
2026 }
2027 else if (axis == t.ndim()-1) {
2028 return inner(t,c,axis,0);
2029 }
2030 else {
2031 return copy(inner(t,c,axis,0).cycledim(1,axis, -1)); // Copy to make contiguous
2032 }
2033 }
2034
2035 /// Returns a new deep copy of the transpose of the input tensor
2036
2037 /// \ingroup tensor
2038 template <class T>
2040 TENSOR_ASSERT(t.ndim() == 2, "transpose requires a matrix", t.ndim(), &t);
2041 return copy(t.swapdim(0,1));
2042 }
2043
2044 /// Returns a new deep copy of the complex conjugate transpose of the input tensor
2045
2046 /// \ingroup tensor
2047 template <class T>
2049 TENSOR_ASSERT(t.ndim() == 2, "conj_transpose requires a matrix", t.ndim(), &t);
2050 return conj(t.swapdim(0,1));
2051 }
2052
2053 /// Indexing a non-constant tensor with slices returns a SliceTensor
2054
2055 /// \ingroup tensor
2056 /// A slice tensor differs from a tensor only in that assignment
2057 /// causes the data to be copied rather than entire new copy
2058 /// generated. You will usually not instantiate one except as a
2059 /// temporary produced by indexing a tensor with slice and then
2060 /// assigning it back to a tensor, or performing some other
2061 /// operation and discarding.
2062 template <class T> class SliceTensor : public Tensor<T> {
2063 private:
2065
2066 public:
2067
2068 // delegating constructor
2069 SliceTensor(const Tensor<T>& t, const std::array<Slice,TENSOR_MAXDIM> s)
2070 : SliceTensor(t,s.data()) {}
2071
2072
2073 SliceTensor(const Tensor<T>& t, const Slice s[])
2074 : Tensor<T>(const_cast<Tensor<T>&>(t)) //!!!!!!!!!!!
2075 {
2076 // C++ standard says class derived from parameterized base class cannot
2077 // directly access the base class elements ... must explicitly reference.
2078
2079 long nd = 0, size=1;
2080 for (long i=0; i<t._ndim; ++i) {
2081 long start=s[i].start, end=s[i].end, step=s[i].step;
2082 //std::printf("%ld input start=%ld end=%ld step=%ld\n",
2083 //i, start, end, step);
2084 if (start < 0) start += this->_dim[i];
2085 if (end < 0) end += this->_dim[i];
2086 long len = end-start+1;
2087 if (step) len /= step; // Rounds len towards zero
2088
2089 // if input length is not exact multiple of step, round end towards start
2090 // for the same behaviour of for (i=start; i<=end; i+=step);
2091 end = start + (len-1)*step;
2092
2093 //std::printf("%ld munged start=%ld end=%ld step=%ld len=%ld _dim=%ld\n",
2094 // i, start, end, step, len, this->_dim[i]);
2095
2096 TENSOR_ASSERT(start>=0 && start<this->_dim[i],"slice start invalid",start,this);
2097 TENSOR_ASSERT(end>=0 && end<this->_dim[i],"slice end invalid",end,this);
2098 TENSOR_ASSERT(len>0,"slice length must be non-zero",len,this);
2099
2100 this->_p += start * t._stride[i];
2101
2102 if (step) {
2103 size *= len;
2104 this->_dim[nd] = len;
2105 this->_stride[nd] = step * t._stride[i];
2106 ++nd;
2107 }
2108 }
2109 //For Python interface need to be able to return a scalar inside a tensor with nd=0
2110 //TENSOR_ASSERT(nd>0,"slicing produced a scalar, but cannot return one",nd,this);
2111 for (long i=nd; i<TENSOR_MAXDIM; ++i) { // So can iterate over missing dimensions
2112 this->_dim[i] = 1;
2113 this->_stride[i] = 0;
2114 }
2115
2116 this->_ndim = nd;
2117 this->_size = size;
2118 }
2119
2121 BINARY_OPTIMIZED_ITERATOR(T, (*this), const T, t, *_p0 = (T)(*_p1));
2122 return *this;
2123 }
2124
2125 template <class Q>
2127 BINARY_OPTIMIZED_ITERATOR(T, (*this), const Q, t, *_p0 = (T)(*_p1));
2128 return *this;
2129 }
2130
2132 BINARY_OPTIMIZED_ITERATOR(T, (*this), const T, t, *_p0 = (T)(*_p1));
2133 return *this;
2134 }
2135
2136 template <class Q>
2138 BINARY_OPTIMIZED_ITERATOR(T, (*this), const Q, t, *_p0 = (T)(*_p1));
2139 return *this;
2140 }
2141
2143 UNARY_OPTIMIZED_ITERATOR(T, (*this), *_p0 = t);
2144 return *this;
2145 }
2146
2147 virtual ~SliceTensor() {}; // Tensor<T> destructor does enough
2148 };
2149
2150
2151 // Specializations for complex types
2152 template<> float_complex Tensor<float_complex>::min(long* ind) const ;
2153 template<> double_complex Tensor<double_complex>::min(long* ind) const ;
2154 template<> float_complex Tensor<float_complex>::max(long* ind) const ;
2155 template<> double_complex Tensor<double_complex>::max(long* ind) const ;
2156
2157 // Stream stuff
2158
2159 /// Print (for human consumption) a tensor to the stream
2160
2161 /// \ingroup tensor
2162 template <class T>
2163 std::ostream& operator << (std::ostream& s, const Tensor<T>& t) {
2164 if (t.size() == 0) {
2165 s << "[empty tensor]\n";
2166 return s;
2167 }
2168
2169 long maxdim = 0;
2170 long index_width = 0;
2171 for (int i = 0; i<(t.ndim()-1); ++i) {
2172 if (maxdim < t.dim(i)) maxdim = t.dim(i);
2173 }
2174 if (maxdim < 10)
2175 index_width = 1;
2176 else if (maxdim < 100)
2177 index_width = 2;
2178 else if (maxdim < 1000)
2179 index_width = 3;
2180 else if (maxdim < 10000)
2181 index_width = 4;
2182 else
2183 index_width = 6;
2184
2185 std::ios::fmtflags oldflags = s.setf(std::ios::scientific);
2186 long oldprec = s.precision();
2187 long oldwidth = s.width();
2188
2189 // C++ formatted IO is worse than Fortran !!
2190 for (TensorIterator<T> iter=t.unary_iterator(1,false,false); iter!=t.end(); ++iter) {
2191 const T* p = iter._p0;
2192 long inc = iter._s0;
2193 long dimj = iter.dimj;
2194 s.unsetf(std::ios::scientific);
2195 s << '[';
2196 for (long i=0; i<iter.ndim; ++i) {
2197 s.width(index_width);
2198 s << iter.ind[i];
2199 //if (i != iter.ndim)
2200 s << ",";
2201 }
2202 s << "*]";
2203//flo s.setf(std::ios::scientific);
2204 s.setf(std::ios::fixed);
2205 for (long j=0; j<dimj; ++j, p+=inc) {
2206//flo s.precision(4);
2207 s << " ";
2208 s.precision(8);
2209 s.width(12);
2210 s << *p;
2211 }
2212 s.unsetf(std::ios::scientific);
2213 s << std::endl;
2214 }
2215 s.setf(oldflags,std::ios::floatfield);
2216 s.precision(oldprec);
2217 s.width(oldwidth);
2218
2219 return s;
2220 }
2221
2222
2223 /// Outer product ... result(i,j,...,p,q,...) = left(i,k,...)*right(p,q,...)
2224
2225 /// \ingroup tensor
2226 template <class T>
2227 Tensor<T> outer(const Tensor<T>& left, const Tensor<T>& right) {
2228 long nd = left.ndim() + right.ndim();
2229 TENSOR_ASSERT(nd <= TENSOR_MAXDIM, "too many dimensions in result",
2230 nd, 0);
2231 long d[TENSOR_MAXDIM];
2232 for (long i = 0; i < left.ndim(); ++i) d[i] = left.dim(i);
2233 for (long i = 0; i < right.ndim(); ++i) d[i + left.ndim()] = right.dim(i);
2234 Tensor<T> result(nd, d, false);
2235 outer_result(left,right,result);
2236 return result;
2237 }
2238
2239 /// Outer product ... result(i,j,...,p,q,...) = left(i,k,...)*right(p,q,...)
2240
2241 /// accumulate into result, no allocation is performed
2242 template<class T>
2243 void outer_result(const Tensor<T>& left, const Tensor<T>& right, Tensor<T>& result) {
2244 TENSOR_ASSERT(left.ndim() + right.ndim() == result.ndim(),"inconsistent dimension in outer_result",
2245 result.ndim(),0);
2246 T *ptr = result.ptr();
2247 TensorIterator<T> iter=right.unary_iterator(1,false,true);
2248 for (TensorIterator<T> p=left.unary_iterator(); p!=left.end(); ++p) {
2249 T val1 = *p;
2250 // Cannot reorder dimensions, but can fuse contiguous dimensions
2251 for (iter.reset(); iter._p0; ++iter) {
2252 long dimj = iter.dimj;
2253 T* _p0 = iter._p0;
2254 long Tstride = iter._s0;
2255 for (long _j=0; _j<dimj; ++_j, _p0+=Tstride) {
2256 *ptr++ = val1 * (*_p0);
2257 }
2258 }
2259 }
2260 }
2261
2262
2263 /// Inner product ... result(i,j,...,p,q,...) = sum(z) left(i,j,...,z)*right(z,p,q,...)
2264
2265 /// \ingroup tensor
2266 /// By default it contracts the last dimension of the left tensor and
2267 /// the first dimension of the right tensor. These defaults can be
2268 /// changed by specifying \c k0 and \c k1 , the index to contract in
2269 /// the left and right side tensors, respectively. The defaults
2270 /// correspond to (\c k0=-1 and \c k1=0 ).
2271 template <class T, class Q>
2272 Tensor<TENSOR_RESULT_TYPE(T,Q)> inner(const Tensor<T>& left, const Tensor<Q>& right,
2273 long k0=-1, long k1=0) {
2274 if (k0 < 0) k0 += left.ndim();
2275 if (k1 < 0) k1 += right.ndim();
2276 long nd = left.ndim() + right.ndim() - 2;
2277 TENSOR_ASSERT(nd!=0, "result is a scalar but cannot return one ... use dot",
2278 nd, &left);
2279
2280
2281 TENSOR_ASSERT(left.dim(k0) == right.dim(k1),"common index must be same length",
2282 right.dim(k1), &left);
2283
2284 TENSOR_ASSERT(nd > 0 && nd <= TENSOR_MAXDIM,
2285 "invalid number of dimensions in the result", nd,0);
2286
2287 long d[TENSOR_MAXDIM];
2288
2289 long base=0;
2290 for (long i=0; i<k0; ++i) d[i] = left.dim(i);
2291 for (long i=k0+1; i<left.ndim(); ++i) d[i-1] = left.dim(i);
2292 base = left.ndim()-1;
2293 for (long i=0; i<k1; ++i) d[i+base] = right.dim(i);
2294 base--;
2295 for (long i=k1+1; i<right.ndim(); ++i) d[i+base] = right.dim(i);
2296
2297 Tensor<TENSOR_RESULT_TYPE(T,Q)> result(nd,d);
2298
2299 inner_result(left,right,k0,k1,result);
2300
2301 return result;
2302 }
2303
2304 /// Accumulate inner product into user provided, contiguous, correctly sized result tensor
2305
2306 /// \ingroup tensor
2307 /// This routine may be used to optimize away the tensor constructor
2308 /// of the result tensor in inner loops when the result tensor may be
2309 /// reused or accumulated into. If the user calls this routine
2310 /// directly very little checking is done since it is intended as an
2311 /// optimization for small tensors. As far as the result goes, the
2312 /// caller is completely responsible for providing a contiguous tensor
2313 /// that has the correct dimensions and is appropriately initialized.
2314 /// The inner product is accumulated into result.
2315 template <class T, class Q>
2316 void inner_result(const Tensor<T>& left, const Tensor<Q>& right,
2317 long k0, long k1, Tensor< TENSOR_RESULT_TYPE(T,Q) >& result) {
2318
2319 typedef TENSOR_RESULT_TYPE(T,Q) resultT;
2320 // Need to include explicit optimizations for common special cases
2321 // E.g., contiguous, matrix-matrix, and 3d-tensor*matrix
2322
2323 resultT* ptr = result.ptr();
2324
2325 if (k0 < 0) k0 += left.ndim();
2326 if (k1 < 0) k1 += right.ndim();
2327
2328 if (left.iscontiguous() && right.iscontiguous()) {
2329 if (k0==0 && k1==0) {
2330 // c[i,j] = a[k,i]*b[k,j] ... collapsing extra indices to i & j
2331 long dimk = left.dim(k0);
2332 long dimj = right.stride(0);
2333 long dimi = left.stride(0);
2334 mTxm(dimi,dimj,dimk,ptr,left.ptr(),right.ptr());
2335 return;
2336 }
2337 else if (k0==(left.ndim()-1) && k1==(right.ndim()-1)) {
2338 // c[i,j] = a[i,k]*b[j,k] ... collapsing extra indices to i & j
2339 long dimk = left.dim(k0);
2340 long dimi = left.size()/dimk;
2341 long dimj = right.size()/dimk;
2342 mxmT(dimi,dimj,dimk,ptr,left.ptr(),right.ptr());
2343 return;
2344 }
2345 else if (k0==0 && k1==(right.ndim()-1)) {
2346 // c[i,j] = a[k,i]*b[j,k] ... collapsing extra indices to i & j
2347 long dimk = left.dim(k0);
2348 long dimi = left.stride(0);
2349 long dimj = right.size()/dimk;
2350 mTxmT(dimi,dimj,dimk,ptr,left.ptr(),right.ptr());
2351 return;
2352 }
2353 else if (k0==(left.ndim()-1) && k1==0) {
2354 // c[i,j] = a[i,k]*b[k,j] ... collapsing extra indices to i & j
2355 long dimk = left.dim(k0);
2356 long dimi = left.size()/dimk;
2357 long dimj = right.stride(0);
2358 mxm(dimi,dimj,dimk,ptr,left.ptr(),right.ptr());
2359 return;
2360 }
2361 }
2362
2363 long dimj = left.dim(k0);
2364 TensorIterator<Q> iter1=right.unary_iterator(1,false,false,k1);
2365
2366 for (TensorIterator<T> iter0=left.unary_iterator(1,false,false,k0);
2367 iter0._p0; ++iter0) {
2368 T* MADNESS_RESTRICT xp0 = iter0._p0;
2369 long s0 = iter0._s0;
2370 for (iter1.reset(); iter1._p0; ++iter1) {
2371 T* MADNESS_RESTRICT p0 = xp0;
2372 Q* MADNESS_RESTRICT p1 = iter1._p0;
2373 long s1 = iter1._s0;
2374 resultT sum = 0;
2375 for (long j=0; j<dimj; ++j,p0+=s0,p1+=s1) {
2376 sum += (*p0) * (*p1);
2377 }
2378 *ptr++ += sum;
2379 }
2380 }
2381 }
2382
2383 /// Transform all dimensions of the tensor t by the matrix c
2384
2385 /// \ingroup tensor
2386 /// Often used to transform all dimensions from one basis to another
2387 /// \code
2388 /// result(i,j,k...) <-- sum(i',j', k',...) t(i',j',k',...) c(i',i) c(j',j) c(k',k) ...
2389 /// \endcode
2390 /// The input dimensions of \c t must all be the same and agree with
2391 /// the first dimension of \c c . The dimensions of \c c may differ in
2392 /// size. If the dimensions of \c c are the same, and the operation
2393 /// is being performed repeatedly, then you might consider calling \c
2394 /// fast_transform instead which enables additional optimizations and
2395 /// can eliminate all constructor overhead and improve cache locality.
2396 ///
2397 template <class T, class Q>
2399 typedef TENSOR_RESULT_TYPE(T,Q) resultT;
2400 TENSOR_ASSERT(c.ndim() == 2,"second argument must be a matrix",c.ndim(),&c);
2401 if (c.dim(0)==c.dim(1) && t.iscontiguous() && c.iscontiguous()) {
2402 Tensor<resultT> result(t.ndim(),t.dims(),false);
2403 Tensor<resultT> work(t.ndim(),t.dims(),false);
2404 return fast_transform(t, c, result, work);
2405 }
2406 else {
2407 Tensor<resultT> result = t;
2408 for (long i=0; i<t.ndim(); ++i) {
2409 result = inner(result,c,0,0);
2410 }
2411 return result;
2412 }
2413 }
2414
2415 /// Transform all dimensions of the tensor t by distinct matrices c
2416
2417 /// \ingroup tensor
2418 /// Similar to transform but each dimension is transformed with a
2419 /// distinct matrix.
2420 /// \code
2421 /// result(i,j,k...) <-- sum(i',j', k',...) t(i',j',k',...) c[0](i',i) c[1](j',j) c[2](k',k) ...
2422 /// \endcode
2423 /// The first dimension of the matrices c must match the corresponding
2424 /// dimension of t.
2425 template <class T, class Q>
2427 typedef TENSOR_RESULT_TYPE(T,Q) resultT;
2428 Tensor<resultT> result = t;
2429 for (long i=0; i<t.ndim(); ++i) {
2430 result = inner(result,c[i],0,0);
2431 }
2432 return result;
2433 }
2434
2435 /// Restricted but heavily optimized form of transform()
2436
2437 /// \ingroup tensor
2438 /// Both dimensions of \c c must be the same and match all dimensions
2439 /// of the input tensor \c t. All tensors must be contiguous.
2440 ///
2441 /// Performs the same operation as \c transform but it requires
2442 /// that the caller pass in workspace and a preallocated result,
2443 /// hoping that that both can be reused. If the result and
2444 /// workspace are reused between calls, then no tensor
2445 /// constructors need be called and cache locality should be
2446 /// improved. By passing in the workspace, this routine is kept
2447 /// thread safe.
2448 ///
2449 /// The input, result and workspace tensors must be distinct.
2450 ///
2451 /// All input tensors must be contiguous and fastest execution
2452 /// will result if all dimensions are approriately aligned and
2453 /// multiples of the underlying vector length. The workspace and
2454 /// the result must be of the same size as the input \c t . The
2455 /// result tensor need not be initialized before calling
2456 /// fast_transform.
2457 ///
2458 /// \code
2459 /// result(i,j,k,...) <-- sum(i',j', k',...) t(i',j',k',...) c(i',i) c(j',j) c(k',k) ...
2460 /// \endcode
2461 ///
2462 /// The input dimensions of \c t must all be the same .
2463 template <class T, class Q>
2465 Tensor< TENSOR_RESULT_TYPE(T,Q) >& workspace) {
2466 typedef TENSOR_RESULT_TYPE(T,Q) resultT;
2467 const Q *pc=c.ptr();
2468 resultT *t0=workspace.ptr(), *t1=result.ptr();
2469 if (t.ndim()&1) {
2470 t0 = result.ptr();
2471 t1 = workspace.ptr();
2472 }
2473
2474 long dimj = c.dim(1);
2475 long dimi = 1;
2476 for (int n=1; n<t.ndim(); ++n) dimi *= dimj;
2477
2478 mTxmq(dimi, dimj, dimj, t0, t.ptr(), pc);
2479 for (int n=1; n<t.ndim(); ++n) {
2480 mTxmq(dimi, dimj, dimj, t1, t0, pc);
2481 std::swap(t0,t1);
2482 }
2483
2484 return result;
2485 }
2486
2487 /// Optimized fast_transform for complex tensor * real matrix.
2488 /// Transforms the real and imaginary parts across all dimensions in real
2489 /// space, unpacking once on entry and repacking once into result on exit.
2490 ///
2491 /// Allocates nothing: the two caller-supplied complex tensors hold 2*sz
2492 /// reals each, which is exactly the four real buffers of length sz that the
2493 /// split needs. The initial assignment is chosen so that the ndim swaps
2494 /// below leave the live buffer in the workspace, letting the final repack
2495 /// into result run without aliasing its own source.
2496 template <class R>
2497 Tensor<std::complex<R>>& fast_transform(const Tensor<std::complex<R>>& t,
2498 const Tensor<R>& c,
2499 Tensor<std::complex<R>>& result,
2500 Tensor<std::complex<R>>& workspace) {
2501 MADNESS_CHECK(t.iscontiguous() && result.iscontiguous() && workspace.iscontiguous());
2502 MADNESS_CHECK(result.ptr() != workspace.ptr());
2503 MADNESS_CHECK(t.ptr() != result.ptr() && t.ptr() != workspace.ptr());
2504
2505 const R* pc = c.ptr();
2506 const long ndim = t.ndim();
2507 const long sz = t.size();
2508 MADNESS_CHECK(result.size() >= sz && workspace.size() >= sz);
2509
2510 long dimj = c.dim(1);
2511 long dimi = 1;
2512 for (int n = 1; n < ndim; ++n) dimi *= dimj;
2513
2514 R* res_raw = reinterpret_cast<R*>(result.ptr());
2515 R* wrk_raw = reinterpret_cast<R*>(workspace.ptr());
2516 R* bufA = (ndim & 1) ? res_raw : wrk_raw;
2517 R* bufB = (ndim & 1) ? wrk_raw : res_raw;
2518
2519 R* in_re = bufA;
2520 R* in_im = bufA + sz;
2521 R* out_re = bufB;
2522 R* out_im = bufB + sz;
2523
2524 // 1. Unpack complex input into Real and Imag arrays ONCE at the start
2525 const R* t_raw = reinterpret_cast<const R*>(t.ptr());
2526 for (long i = 0; i < sz; ++i) {
2527 in_re[i] = t_raw[2 * i];
2528 in_im[i] = t_raw[2 * i + 1];
2529 }
2530
2531 for (int n = 0; n < ndim; ++n) {
2532 mTxmq(dimi, dimj, dimj, out_re, in_re, pc);
2533 mTxmq(dimi, dimj, dimj, out_im, in_im, pc);
2534 std::swap(in_re, out_re);
2535 std::swap(in_im, out_im);
2536 }
2537
2538 // 2. Repack into result ONCE at the end (in_* is in the workspace here)
2539 for (long i = 0; i < sz; ++i) {
2540 res_raw[2 * i] = in_re[i];
2541 res_raw[2 * i + 1] = in_im[i];
2542 }
2543
2544 return result;
2545 }
2546
2547 /// Separated transform with a distinct matrix per dimension, reusing caller buffers.
2548 ///
2549 /// Computes, with no internal allocation,
2550 /// result(i,j,...) <-- sum(i',j',...) t(i',j',...) c[0](i',i) c[1](j',j) ...
2551 /// like general_transform, but the caller supplies result and workspace so they
2552 /// can be reused across many calls. Both must be contiguous and at least as large
2553 /// as the biggest intermediate the contraction produces. That is t.size() when no
2554 /// axis expands, but an expanding matrix (c[d].dim(1) > c[d].dim(0), e.g.
2555 /// coeffs2values with npt > k) can grow it larger, so size to the running maximum,
2556 /// not t.size(). c[d] may be rectangular; c[d].dim(0) must equal dim d of t.
2557 /// t, result and workspace must be distinct: the contraction ping-pongs between
2558 /// result and workspace and mTxmq cannot alias its source and destination.
2559 /// No communication; safe on any worker thread as long as result and workspace
2560 /// are not shared between concurrent calls.
2561 ///
2562 /// Instantiate only where TENSOR_RESULT_TYPE(T,Q) == T (the matrix type Q does not
2563 /// promote the result). This covers every (T,double) the eval path needs; it
2564 /// excludes real-tensor x complex-matrix pairs like (double,double_complex), which
2565 /// lower to a mixed-type cblas gemm that MKL is missing.
2566 template <class T, class Q>
2569 Tensor<TENSOR_RESULT_TYPE(T,Q)>& result,
2570 Tensor<TENSOR_RESULT_TYPE(T,Q)>& workspace) {
2571 typedef TENSOR_RESULT_TYPE(T,Q) R;
2572 // Excluded pairs would compile by implicit instantiation and then hit the
2573 // missing mixed-type gemm; fail loudly here instead (see the doc comment).
2574 static_assert(std::is_same<TENSOR_RESULT_TYPE(T,Q), T>::value,
2575 "general_fast_transform requires the matrix type not to "
2576 "promote the result past the tensor type");
2577 MADNESS_CHECK(t.iscontiguous() && result.iscontiguous() && workspace.iscontiguous());
2578 // Catch the realistic accident of reusing one scratch tensor for two
2579 // arguments (exact base-pointer aliasing); arbitrary partial overlap is
2580 // the caller's responsibility.
2581 MADNESS_CHECK(result.ptr() != workspace.ptr());
2582 MADNESS_CHECK(t.ptr() != result.ptr() && t.ptr() != workspace.ptr());
2583
2584 const long D = t.ndim();
2585
2586 // Largest intermediate any buffer must hold = max over steps of the output
2587 // size. The running count starts at t.size() and is rescaled by dimj/dimk
2588 // each step; for expanding matrices (m_d > k) it can exceed t.size().
2589 {
2590 long running = t.size();
2591 long max_running = running;
2592 for (long d = 0; d < D; ++d) {
2593 MADNESS_CHECK(c[d].ndim() == 2 && c[d].dim(0) > 0);
2594 MADNESS_CHECK(running % c[d].dim(0) == 0);
2595 running = (running / c[d].dim(0)) * c[d].dim(1);
2596 if (running > max_running) max_running = running;
2597 }
2598 MADNESS_CHECK(result.size() >= max_running &&
2599 workspace.size() >= max_running);
2600 }
2601
2602 R* buf0 = workspace.ptr();
2603 R* buf1 = result.ptr();
2604 if (D & 1) std::swap(buf0, buf1); // odd # of steps: final write lands in result
2605
2606 R* out = buf0;
2607 R* in_r = nullptr; // R* source for steps d >= 1
2608 long n = t.size();
2609
2610 for (long d = 0; d < D; ++d) {
2611 const long dimk = c[d].dim(0);
2612 const long dimj = c[d].dim(1);
2613 const long dimi = n / dimk;
2614 if (d == 0) {
2615 mTxmq(dimi, dimj, dimk, out, t.ptr(), c[d].ptr());
2616 } else {
2617 mTxmq(dimi, dimj, dimk, out, in_r, c[d].ptr());
2618 }
2619 n = dimi * dimj;
2620 in_r = out;
2621 out = (out == buf0) ? buf1 : buf0;
2622 }
2623 return result;
2624 }
2625
2626 /// Optimized general_fast_transform for complex tensor * real matrices.
2627 template <class R>
2629 general_fast_transform(const Tensor<std::complex<R>>& t,
2630 const Tensor<R>* c,
2631 Tensor<std::complex<R>>& result,
2632 Tensor<std::complex<R>>& workspace) {
2633 MADNESS_CHECK(t.iscontiguous() && result.iscontiguous() && workspace.iscontiguous());
2634 MADNESS_CHECK(result.ptr() != workspace.ptr());
2635 MADNESS_CHECK(t.ptr() != result.ptr() && t.ptr() != workspace.ptr());
2636
2637 const long D = t.ndim();
2638
2639 long running = t.size();
2640 long max_running = running;
2641 for (long d = 0; d < D; ++d) {
2642 MADNESS_CHECK(c[d].ndim() == 2 && c[d].dim(0) > 0);
2643 MADNESS_CHECK(running % c[d].dim(0) == 0);
2644 running = (running / c[d].dim(0)) * c[d].dim(1);
2645 if (running > max_running) max_running = running;
2646 }
2647 MADNESS_CHECK(result.size() >= max_running &&
2648 workspace.size() >= max_running);
2649
2650 // Allocates nothing: result and workspace hold 2*max_running reals
2651 // each, exactly the four real buffers the split needs. Chosen so the
2652 // D swaps below leave the live buffer in the workspace, so the final
2653 // repack into result does not alias its own source.
2654 R* res_raw = reinterpret_cast<R*>(result.ptr());
2655 R* wrk_raw = reinterpret_cast<R*>(workspace.ptr());
2656 R* bufA = (D & 1) ? res_raw : wrk_raw;
2657 R* bufB = (D & 1) ? wrk_raw : res_raw;
2658
2659 R* bufA_re = bufA;
2660 R* bufA_im = bufA + max_running;
2661 R* bufB_re = bufB;
2662 R* bufB_im = bufB + max_running;
2663
2664 // 1. Unpack complex input into Real and Imag arrays ONCE
2665 const long sz0 = t.size();
2666 const R* t_raw = reinterpret_cast<const R*>(t.ptr());
2667 for (long i = 0; i < sz0; ++i) {
2668 bufA_re[i] = t_raw[2 * i];
2669 bufA_im[i] = t_raw[2 * i + 1];
2670 }
2671
2672 R* in_re = bufA_re;
2673 R* in_im = bufA_im;
2674 R* out_re = bufB_re;
2675 R* out_im = bufB_im;
2676 long n = sz0;
2677
2678 for (long d = 0; d < D; ++d) {
2679 const long dimk = c[d].dim(0);
2680 const long dimj = c[d].dim(1);
2681 const long dimi = n / dimk;
2682
2683 mTxmq(dimi, dimj, dimk, out_re, in_re, c[d].ptr());
2684 mTxmq(dimi, dimj, dimk, out_im, in_im, c[d].ptr());
2685
2686 n = dimi * dimj;
2687 std::swap(in_re, out_re);
2688 std::swap(in_im, out_im);
2689 }
2690
2691 // 2. Repack into result ONCE (in_* is in the workspace here)
2692 const long final_sz = n;
2693 for (long i = 0; i < final_sz; ++i) {
2694 res_raw[2 * i] = in_re[i];
2695 res_raw[2 * i + 1] = in_im[i];
2696 }
2697
2698 return result;
2699 }
2700
2701 namespace detail {
2702 /// Per-thread grow-on-demand buffer pair for general_fast_transform.
2703 template <typename R>
2704 struct EvalScratch { Tensor<R> a, b; };
2705
2706 /// The function-local static pool backing eval_scratch<R>(). One pool
2707 /// per result type R, shared by every FunctionImpl<T,NDIM> of that type;
2708 /// its lifetime is the process, but eval_scratch_clear<R>() reclaims the
2709 /// buffers on demand.
2710 template <typename R>
2715
2716 /// Grow-on-demand per-thread buffer pair for general_fast_transform.
2717 ///
2718 /// Backed by a reclaimable thread_specific pool rather than a
2719 /// thread_local: the pair can grow to k^NDIM each for 6-D eval, and a
2720 /// thread_local would pin that per worker thread for the life of the
2721 /// thread (≈ the process) with no way to free it — bad under the
2722 /// TBB/PaRSEC backends, whose arenas touch more threads than
2723 /// MAD_NUM_THREADS. eval_scratch_clear<R>() frees them. Each thread
2724 /// first-touches its own pair (NUMA-local); buffers grow monotonically
2725 /// to the largest need seen on that thread. Never shared across threads.
2726 template <typename R>
2727 std::pair<Tensor<R>&, Tensor<R>&> eval_scratch(long need) {
2728 EvalScratch<R>& s = eval_scratch_pool<R>().local();
2729 if (s.a.size() < need) {
2730 s.a = Tensor<R>(need);
2731 s.b = Tensor<R>(need);
2732 }
2733 return {s.a, s.b};
2734 }
2735
2736 /// Free every thread's general_fast_transform scratch buffers. Call
2737 /// only at a quiescent point — no eval may be in flight and no
2738 /// reference returned by eval_scratch<R>() may still be in use (see
2739 /// thread_specific::clear()).
2740 template <typename R>
2742 eval_scratch_pool<R>().clear();
2743 }
2744 } // namespace detail
2745
2746 /// Return a new tensor holding the absolute value of each element of t
2747
2748 /// \ingroup tensor
2749 template <class T>
2751 typedef typename Tensor<T>::scalar_type scalar_type;
2752 Tensor<scalar_type> result(t.ndim(),t.dims(),false);
2753 BINARY_OPTIMIZED_ITERATOR(scalar_type,result,const T,t,*_p0 = std::abs(*_p1));
2754 return result;
2755 }
2756
2757 /// Return a new tensor holding the argument of each element of t (complex types only)
2758
2759 /// \ingroup tensor
2760 template <class T>
2762 typedef typename Tensor<T>::scalar_type scalar_type;
2763 Tensor<scalar_type> result(t.ndim(),t.dims(),false);
2764 BINARY_OPTIMIZED_ITERATOR(scalar_type,result,T,t,*_p0 = std::arg(*_p1));
2765 return result;
2766 }
2767
2768 /// Return a new tensor holding the real part of each element of t (complex types only)
2769
2770 /// \ingroup tensor
2771 template <class T>
2773 typedef typename Tensor<T>::scalar_type scalar_type;
2774 Tensor<scalar_type> result(t.ndim(),t.dims(),false);
2775 BINARY_OPTIMIZED_ITERATOR(scalar_type,result,const T,t,*_p0 = std::real(*_p1));
2776 return result;
2777 }
2778
2779 /// Return a new tensor holding the imaginary part of each element of t (complex types only)
2780
2781 /// \ingroup tensor
2782 template <class T>
2784 typedef typename Tensor<T>::scalar_type scalar_type;
2785 Tensor<scalar_type> result(t.ndim(),t.dims(),false);
2786 BINARY_OPTIMIZED_ITERATOR(scalar_type,result,const T,t,*_p0 = std::imag(*_p1));
2787 return result;
2788 }
2789
2790 /// Returns a new deep copy of the complex conjugate of the input tensor (complex types only)
2791
2792 /// \ingroup tensor
2793 template <class T>
2795 Tensor<T> result(t.ndim(),t.dims(),false);
2796 BINARY_OPTIMIZED_ITERATOR(T,result,const T,t,*_p0 = conditional_conj(*_p1));
2797 return result;
2798 }
2799
2800 /// Returns the identity matrix of the specified size
2801
2802 /// \ingroup tensor
2803 template <class T>
2805 Tensor<T> result(n,n);
2806 for (long i=0; i<n; ++i) result(i,i) = T(1);
2807 return result;
2808 }
2809
2810}
2811
2812#undef TENSOR_SHARED_PTR
2813
2814#endif // MADNESS_TENSOR_TENSOR_H__INCLUDED
double q(double t)
Definition DKops.h:18
Provides routines for internal use optimized for aligned data.
Interface templates for the archives (serialization).
Declares BaseTensor.
std::complex< double > double_complex
Definition cfft.h:14
A tensor is a multidimensional array.
Definition tensor.h:313
bool conforms(const BaseTensor *t) const
Returns true if this and *t are the same shape and size.
Definition basetensor.h:159
long dim(int i) const
Returns the size of dimension i.
Definition basetensor.h:147
bool iscontiguous() const
Returns true if the tensor refers to contiguous memory locations.
Definition basetensor.h:168
void mapdim_inplace(const std::vector< long > &map)
General permutation of dimensions.
Definition basetensor.cc:156
const long * dims() const
Returns the array of tensor dimensions.
Definition basetensor.h:153
long _stride[TENSOR_MAXDIM]
Increment between elements in each dimension.
Definition basetensor.h:97
long stride(int i) const
Returns the stride associated with dimension i.
Definition basetensor.h:150
long _size
Number of elements in the tensor.
Definition basetensor.h:93
long id() const
Returns the typeid of the tensor (c.f., TensorTypeData<T> ).
Definition basetensor.h:141
void set_dims_and_size(long nd, const long d[])
Definition basetensor.h:99
long _id
Id from TensorTypeData<T> in type_data.h.
Definition basetensor.h:95
void splitdim_inplace(long i, long dimi0, long dimi1)
Splits dimension i.
Definition basetensor.cc:88
void swapdim_inplace(long i, long j)
Swaps the dimensions.
Definition basetensor.cc:124
BaseTensor()
Definition basetensor.h:116
void fusedim_inplace(long i)
Fuses dimensions i and i+1.
Definition basetensor.cc:107
long _dim[TENSOR_MAXDIM]
Size of each dimension.
Definition basetensor.h:96
long ndim() const
Returns the number of dimensions in the tensor.
Definition basetensor.h:144
long size() const
Returns the number of elements in the tensor.
Definition basetensor.h:138
void cycledim_inplace(long shift, long start, long end)
Cyclic shift of dimensions.
Definition basetensor.cc:134
long _ndim
Number of dimensions (-1=invalid; 0=no supported; >0=tensor).
Definition basetensor.h:94
void reshape_inplace(const std::vector< long > &d)
Reshapes the tensor inplace.
Definition basetensor.cc:76
virtual ~SliceTensor()
Definition tensor.h:2147
SliceTensor(const Tensor< T > &t, const Slice s[])
Definition tensor.h:2073
SliceTensor< T > & operator=(const SliceTensor< Q > &t)
Definition tensor.h:2126
SliceTensor< T > & operator=(const Tensor< Q > &t)
Definition tensor.h:2137
SliceTensor< T > & operator=(const SliceTensor< T > &t)
Definition tensor.h:2120
SliceTensor(const Tensor< T > &t, const std::array< Slice, TENSOR_MAXDIM > s)
Definition tensor.h:2069
SliceTensor< T > & operator=(const Tensor< T > &t)
Definition tensor.h:2131
SliceTensor< T > & operator=(const T &t)
Definition tensor.h:2142
A slice defines a sub-range or patch of a dimension.
Definition slice.h:103
Definition tensoriter.h:61
long dimj
Definition tensoriter.h:70
long _s0
Definition tensoriter.h:71
void reset()
Reset the iterator back to the start ...
Definition tensoriter.h:354
T * _p0
Definition tensoriter.h:66
Traits class to specify support of numeric types.
Definition type_data.h:56
A tensor is a multidimensional array.
Definition tensor.h:313
scalar_type absmax(long *ind=0) const
Return the absolute maximum value (and if ind is non-null, its index) in the Tensor.
Definition tensor.h:1759
void deallocate()
Definition tensor.h:393
double *MADNESS_RESTRICT _p
Definition tensor.h:317
Tensor< T > & operator=(T x)
Inplace fill tensor with scalar.
Definition tensor.h:558
const Tensor< T > swapdim(long idim, long jdim) const
Returns new view/tensor swaping dimensions i and j.
Definition tensor.h:1619
Tensor(const std::vector< long > &d, bool dozero=true)
Create and optionally zero new n-d tensor. This is the most general constructor.
Definition tensor.h:541
SliceTensor< T > operator()(const Slice &s0, const Slice &s1, const Slice &s2, const Slice &s3, const Slice &s4)
Return a 1-5d SliceTensor that views the specified range of the 5d Tensor.
Definition tensor.h:1342
const Tensor< T > operator()(const Slice &s0, const Slice &s1, const Slice &s2, const Slice &s3) const
Return a 1-4d constant Tensor that views the specified range of the 4d Tensor.
Definition tensor.h:1331
float_scalar_type normf() const
Returns the Frobenius norm of the tensor.
Definition tensor.h:1731
Tensor< T > & gaxpy(T alpha, const Tensor< T > &other, T beta)
Inplace generalized saxpy ... this = this*alpha + other*beta.
Definition tensor.h:1810
TensorIterator< T, Q > binary_iterator(const Tensor< Q > &q, long iterlevel=0, bool optimize=true, bool fusedim=true, long jdim=default_jdim) const
Return iterator over two tensors.
Definition tensor.h:1875
SliceTensor< T > operator()(long i, const Slice &s1, long k)
Return a 1d SliceTensor that views the specified range of the 3d Tensor.
Definition tensor.h:1280
Tensor(long d0, long d1)
Create and zero new 2-d tensor.
Definition tensor.h:486
const T * ptr() const
Returns a pointer to the internal data.
Definition tensor.h:1850
bool operator!() const noexcept
convenience for testing if tensor is empty (i.e., has no data)
Definition tensor.h:462
scalar_type absmin(long *ind=0) const
Return the absolute minimum value (and if ind is non-null, its index) in the Tensor.
Definition tensor.h:1738
Tensor< T > & unaryop(opT &op)
Inplace apply a unary function to each element of the tensor.
Definition tensor.h:1798
IsSupported< TensorTypeData< Q >, Tensor< TENSOR_RESULT_TYPE(T, Q)> >::type operator+(const Q &x) const
Add a scalar of the same type to all elements of a tensor producing a new tensor.
Definition tensor.h:648
Tensor< T > & fill(T x)
Inplace fill with a scalar (legacy name).
Definition tensor.h:567
const Tensor< T > operator()(long i, const Slice &s1, const Slice &s2) const
Return a 2d constant Tensor that views the specified range of the 3d Tensor.
Definition tensor.h:1210
Tensor< T > & operator+=(const Tensor< Q > &t)
Inplace addition of two tensors.
Definition tensor.h:577
Tensor< T > reshape(long dim0, long dim1, long dim2, long dim3, long dim4)
Returns new view/tensor rehaping to conforming 5-d tensor with given dimensions.
Definition tensor.h:1513
Tensor< T > swapdim(long idim, long jdim)
Returns new view/tensor swaping dimensions i and j.
Definition tensor.h:1610
const Tensor< T > flat() const
Returns new view/tensor rehshaping to flat (1-d) tensor.
Definition tensor.h:1566
T sum() const
Returns the sum of all elements of the tensor.
Definition tensor.h:1667
Tensor< T > reshape(int ndimnew, const long *d)
Returns new view/tensor reshaping size/number of dimensions to conforming tensor.
Definition tensor.h:1389
const T & operator[](long i) const
1-d indexing operation using [] without bounds checking.
Definition tensor.h:796
TensorIterator< T > unary_iterator(long iterlevel=0, bool optimize=true, bool fusedim=true, long jdim=default_jdim) const
Return iterator over single tensor.
Definition tensor.h:1865
Tensor< T > reshape(long dim0, long dim1)
Returns new view/tensor rehaping to conforming 2-d tensor with given dimensions.
Definition tensor.h:1444
TensorTypeData< double >::scalar_type scalar_type
Definition tensor.h:405
Tensor(long d0, long d1, long d2, long d3, long d4, long d5)
Create and zero new 6-d tensor.
Definition tensor.h:532
double type
Definition tensor.h:402
Tensor< TENSOR_RESULT_TYPE(T, Q) > operator+(const Tensor< Q > &t) const
Addition of two tensors to produce a new tensor.
Definition tensor.h:597
T & operator()(long i)
1-d indexing operation without bounds checking.
Definition tensor.h:807
SliceTensor< T > operator()(const Slice &s0, const Slice &s1, const Slice &s2, const Slice &s3)
Return a 1-4d SliceTensor that views the specified range of the 4d Tensor.
Definition tensor.h:1320
T & operator()(long i, long j, long k, long l, long m)
5-d indexing operation without bounds checking.
Definition tensor.h:925
T * ptr()
Returns a pointer to the internal data.
Definition tensor.h:1845
bool conforms(const Tensor< Q > &t) const
Test if *this and t conform.
Definition tensor.h:1662
const Tensor< T > mapdim(const std::vector< long > &map) const
Returns new view/tensor permuting the dimensions.
Definition tensor.h:1638
T & operator()(long i, long j)
2-d indexing operation without bounds checking.
Definition tensor.h:830
const Tensor< T > reshape(const std::vector< long > &d) const
Returns new view/tensor reshaping size/number of dimensions to conforming tensor.
Definition tensor.h:1418
Tensor< T > cycledim(long nshift, long start, long end)
Returns new view/tensor cycling the sub-dimensions (start,...,end) with shift steps.
Definition tensor.h:1646
const Tensor< T > operator()(const std::vector< Slice > &s) const
General slicing operation (const).
Definition tensor.h:1075
Tensor< T > & operator-=(const Tensor< Q > &t)
Inplace subtraction of two tensors.
Definition tensor.h:587
const Tensor< T > reshape(long dim0, long dim1, long dim2) const
Returns new view/tensor rehaping to conforming 3-d tensor with given dimensions.
Definition tensor.h:1476
const T & operator()(long i, long j, long k) const
3-d indexing operation without bounds checking.
Definition tensor.h:872
SliceTensor< T > operator()(long i, const Slice &s1)
Return a 1d SliceTensor that views the specified range of the 2d Tensor.
Definition tensor.h:1120
const Tensor< T > operator()(const Slice &s0, const Slice &s1, const Slice &s2, const Slice &s3, const Slice &s4, const Slice &s5) const
Return a 1-6d constant Tensor that views the specified range of the 6d Tensor.
Definition tensor.h:1376
Tensor< T > mapdim(const std::vector< long > &map)
Returns new view/tensor permuting the dimensions.
Definition tensor.h:1629
IsSupported< TensorTypeData< Q >, Tensor< TENSOR_RESULT_TYPE(T, Q)> >::type operator*(const Q &x) const
Multiplication of tensor by a scalar of a supported type to produce a new tensor.
Definition tensor.h:622
const Tensor< T > operator()(const std::array< Slice, TENSOR_MAXDIM > &s) const
General slicing operation (const).
Definition tensor.h:1093
SliceTensor< T > operator()(const Slice &s0, const Slice &s1, long k)
Return a 2d SliceTensor that views the specified range of the 3d Tensor.
Definition tensor.h:1240
const Tensor< T > reshape(int ndimnew, const long *d) const
Returns new view/tensor reshaping size/number of dimensions to conforming tensor.
Definition tensor.h:1400
const Tensor< T > fusedim(long i) const
Returns new view/tensor fusing contiguous dimensions i and i+1.
Definition tensor.h:1601
IsSupported< TensorTypeData< Q >, Tensor< T > & >::type scale(Q x)
Inplace multiplication by scalar of supported type (legacy name).
Definition tensor.h:691
IsSupported< TensorTypeData< Q >, Tensor< T > & >::type operator-=(const Q &x)
Inplace decrement by scalar of supported type.
Definition tensor.h:712
IsSupported< TensorTypeData< Q >, Tensor< TENSOR_RESULT_TYPE(T, Q)> >::type operator/(const Q &x) const
Divide tensor by a scalar of a supported type to produce a new tensor.
Definition tensor.h:635
SliceTensor< T > operator()(const Slice &s0, const Slice &s1)
Return a 2d SliceTensor that views the specified range of the 2d Tensor.
Definition tensor.h:1160
TensorTypeData< double >::float_scalar_type float_scalar_type
Definition tensor.h:408
Tensor(const Tensor< T > &t)
Copy constructor is shallow (same as assignment).
Definition tensor.h:424
T & operator()(long i, long j, long k)
3-d indexing operation without bounds checking.
Definition tensor.h:857
const Tensor< T > operator()(const Slice &s0, const Slice &s1, const Slice &s2, const Slice &s3, const Slice &s4) const
Return a 1-5d constant Tensor that views the specified range of the 5d Tensor.
Definition tensor.h:1353
const Tensor< T > reshape(long dim0, long dim1, long dim2, long dim3) const
Returns new view/tensor rehaping to conforming 4-d tensor with given dimensions.
Definition tensor.h:1500
Tensor< T > operator-() const
Unary negation producing a new tensor.
Definition tensor.h:668
const T & operator()(long i, long j) const
2-d indexing operation without bounds checking.
Definition tensor.h:843
const Tensor< T > operator()(const Slice &s0, long j, long k) const
Return a 1d constant Tensor that views the specified range of the 3d Tensor.
Definition tensor.h:1310
T & operator()(long i, long j, long k, long l, long m, long n)
6-d indexing operation without bounds checking.
Definition tensor.h:966
SliceTensor< T > operator()(const Slice &s0, const Slice &s1, const Slice &s2, const Slice &s3, const Slice &s4, const Slice &s5)
Return a 1-6d SliceTensor that views the specified range of the 6d Tensor.
Definition tensor.h:1364
SliceTensor< T > operator()(const Slice &s0)
Return a 1d SliceTensor that views the specified range of the 1d Tensor.
Definition tensor.h:1100
SliceTensor< T > operator()(const Slice &s0, long j, long k)
Return a 1d SliceTensor that views the specified range of the 3d Tensor.
Definition tensor.h:1300
const T & operator()(const long ind[]) const
Politically incorrect general indexing operation without bounds checking.
Definition tensor.h:1021
Tensor< T > & emul(const Tensor< T > &t)
Inplace multiply by corresponding elements of argument Tensor.
Definition tensor.h:1804
Tensor< T > & operator=(const Tensor< T > &t)
Assignment is shallow (same as copy constructor).
Definition tensor.h:439
SliceTensor< T > operator()(long i, const Slice &s1, const Slice &s2)
Return a 2d SliceTensor that views the specified range of the 3d Tensor.
Definition tensor.h:1200
T & operator()(long i, long j, long k, long l)
4-d indexing operation without bounds checking.
Definition tensor.h:888
TENSOR_RESULT_TYPE(T, Q) trace(const Tensor< Q > &t) const
Return the trace of two tensors (no complex conjugate invoked).
Definition tensor.h:1782
SliceTensor< T > operator()(const std::array< Slice, TENSOR_MAXDIM > &s)
General slicing operation.
Definition tensor.h:1085
T max(long *ind=0) const
Return the maximum value (and if ind is non-null, its index) in the Tensor.
Definition tensor.h:1708
Tensor(long d0)
Create and zero new 1-d tensor.
Definition tensor.h:477
const T & operator()(long i, long j, long k, long l) const
4-d indexing operation without bounds checking.
Definition tensor.h:906
T product() const
Return the product of all elements of the tensor.
Definition tensor.h:1681
const T & operator()(long i, long j, long k, long l, long m) const
5-d indexing operation without bounds checking.
Definition tensor.h:945
T min(long *ind=0) const
Return the minimum value (and if ind is non-null, its index) in the Tensor.
Definition tensor.h:1688
Tensor< TENSOR_RESULT_TYPE(T, Q) > operator-(const Tensor< Q > &t) const
Subtraction of two tensors to produce a new tensor.
Definition tensor.h:609
const T & operator()(long i, long j, long k, long l, long m, long n) const
6-d indexing operation without bounds checking.
Definition tensor.h:988
T & operator()(const std::vector< long > ind)
General indexing operation with bounds checking.
Definition tensor.h:1037
Tensor< T > splitdim(long i, long dimi0, long dimi1)
Returns new view/tensor splitting dimension i as dimi0*dimi1 to produce conforming d+1 dimension tens...
Definition tensor.h:1574
virtual ~Tensor()
Definition tensor.h:1902
const Tensor< T > operator()(const Slice &s0) const
Return a 1d SliceTensor that views the specified range of the 1d Tensor.
Definition tensor.h:1110
void allocate(long nd, const long d[], bool dozero)
Definition tensor.h:320
const BaseTensor * base() const
Returns a pointer to the base class.
Definition tensor.h:1860
Tensor< T > reshape(long dim0, long dim1, long dim2, long dim3, long dim4, long dim5)
Returns new view/tensor rehaping to conforming 6-d tensor with given dimensions.
Definition tensor.h:1540
T sumsq() const
Returns the sum of the squares of the elements.
Definition tensor.h:1674
IsSupported< TensorTypeData< Q >, Tensor< T > & >::type operator*=(const Q &x)
Inplace multiplication by scalar of supported type.
Definition tensor.h:680
const Tensor< T > operator()(const Slice &s0, long j) const
Return a 1d constant Tensor that views the specified range of the 2d Tensor.
Definition tensor.h:1150
T & operator[](long i)
1-d indexing operation using [] without bounds checking.
Definition tensor.h:785
Tensor< T > & screen(double x)
Inplace set elements of *this less than x in absolute magnitude to zero.
Definition tensor.h:763
const Tensor< T > cycledim(long nshift, long start, long end) const
Returns new view/tensor cycling the sub-dimensions (start,...,end) with shift steps.
Definition tensor.h:1654
friend class SliceTensor
Definition tensor.h:314
const Tensor< T > splitdim(long i, long dimi0, long dimi1) const
Returns new view/tensor splitting dimension i as dimi0*dimi1 to produce conforming d+1 dimension tens...
Definition tensor.h:1583
Tensor(long d0, long d1, long d2, long d3)
Create and zero new 4-d tensor.
Definition tensor.h:507
Tensor(long d0, long d1, long d2)
Create and zero new 3-d tensor.
Definition tensor.h:496
const Tensor< T > reshape(long dim0, long dim1, long dim2, long dim3, long dim4, long dim5) const
Returns new view/tensor rehaping to conforming 6-d tensor with given dimensions.
Definition tensor.h:1554
const Tensor< T > reshape(long dim0) const
Returns new view/tensor rehapings to conforming 1-d tensor with given dimension.
Definition tensor.h:1434
bool has_data() const
Definition tensor.h:1907
Tensor< T > reshape(const std::vector< long > &d)
Returns new view/tensor reshaping size/number of dimensions to conforming tensor.
Definition tensor.h:1410
BaseTensor * base()
Returns a pointer to the base class.
Definition tensor.h:1855
const TensorIterator< double > & end() const
Definition tensor.h:1897
Tensor< T > reshape(long dim0, long dim1, long dim2)
Returns new view/tensor rehaping to conforming 3-d tensor with given dimensions.
Definition tensor.h:1465
Tensor< T > reshape(long dim0, long dim1, long dim2, long dim3)
Returns new view/tensor rehaping to conforming 4-d tensor with given dimensions.
Definition tensor.h:1488
SliceTensor< T > operator()(const Slice &s0, const Slice &s1, const Slice &s2)
Return a 3d SliceTensor that views the specified range of the 3d Tensor.
Definition tensor.h:1180
Tensor< T > reshape(long dim0)
Returns new view/tensor rehapings to conforming 1-d tensor with given dimension.
Definition tensor.h:1426
SliceTensor< T > operator()(const Slice &s0, long j)
Return a 1d SliceTensor that views the specified range of the 2d Tensor.
Definition tensor.h:1140
Tensor< T > fusedim(long i)
Returns new view/tensor fusing contiguous dimensions i and i+1.
Definition tensor.h:1592
const Tensor< T > operator()(long i, long j, const Slice &s2) const
Return a 1d constant Tensor that views the specified range of the 3d Tensor.
Definition tensor.h:1270
const Tensor< T > operator()(const Slice &s0, const Slice &s1, const Slice &s2) const
Return a 3d constant Tensor that views the specified range of the 3d Tensor.
Definition tensor.h:1190
TENSOR_RESULT_TYPE(T, Q) trace_conj(const Tensor< Q > &t) const
Return the trace of two tensors with complex conjugate of the leftmost (i.e., this).
Definition tensor.h:1790
const Tensor< T > operator()(const Slice &s0, const Slice &s1, long k) const
Return a 2d constant Tensor that views the specified range of the 3d Tensor.
Definition tensor.h:1250
const T & operator()(const std::vector< long > ind) const
General indexing operation with bounds checking.
Definition tensor.h:1051
T & operator()(const long ind[])
Politically incorrect general indexing operation without bounds checking.
Definition tensor.h:1005
Tensor< T > flat()
Returns new view/tensor rehshaping to flat (1-d) tensor.
Definition tensor.h:1560
const Tensor< T > reshape(long dim0, long dim1) const
Returns new view/tensor rehaping to conforming 2-d tensor with given dimensions.
Definition tensor.h:1454
Tensor(long d0, long d1, long d2, long d3, long d4)
Create and zero new 5-d tensor.
Definition tensor.h:519
Tensor()
Default constructor does not allocate any data and sets ndim=-1, size=0, _p=0, and id.
Definition tensor.h:411
const Tensor< T > operator()(long i, const Slice &s1, long k) const
Return a 1d constant Tensor that views the specified range of the 3d Tensor.
Definition tensor.h:1290
TensorIterator< T, Q, R > ternary_iterator(const Tensor< Q > &q, const Tensor< R > &r, long iterlevel=0, bool optimize=true, bool fusedim=true, long jdim=default_jdim) const
Return iterator over three tensors.
Definition tensor.h:1886
const Tensor< T > operator()(long i, const Slice &s1) const
Return a 1d SliceTensor that views the specified range of the 2d Tensor.
Definition tensor.h:1130
static bool bounds_checking()
Return true if bounds checking was enabled at compile time.
Definition tensor.h:773
const T & operator()(long i) const
1-d indexing operation without bounds checking.
Definition tensor.h:818
void clear()
Frees all memory and resests to state of default constructor.
Definition tensor.h:1905
TENSOR_SHARED_PTR< double > _shptr
Definition tensor.h:318
Tensor< T > & fillrandom()
Inplace fill with random values ( [0,1] for floats, [0,MAXSIZE] for integers).
Definition tensor.h:729
Tensor(long nd, const long d[], bool dozero=true)
Politically incorrect general constructor.
Definition tensor.h:550
const Tensor< T > operator()(const Slice &s0, long j, const Slice &s2) const
Return a 2d constant Tensor that views the specified range of the 3d Tensor.
Definition tensor.h:1230
IsSupported< TensorTypeData< Q >, Tensor< TENSOR_RESULT_TYPE(T, Q)> >::type operator-(const Q &x) const
Subtract a scalar of the same type from all elements producing a new tensor.
Definition tensor.h:661
const Tensor< T > operator()(const Slice &s0, const Slice &s1) const
Return a 2d constant Tensor that views the specified range of the 2d Tensor.
Definition tensor.h:1170
Tensor< T > & fillindex()
Inplace fill with the index of each element.
Definition tensor.h:753
SliceTensor< T > operator()(long i, long j, const Slice &s2)
Return a 1d SliceTensor that views the specified range of the 3d Tensor.
Definition tensor.h:1260
const Tensor< T > reshape(long dim0, long dim1, long dim2, long dim3, long dim4) const
Returns new view/tensor rehaping to conforming 5-d tensor with given dimensions.
Definition tensor.h:1526
IsSupported< TensorTypeData< Q >, Tensor< T > & >::type operator+=(const Q &x)
Inplace increment by scalar of supported type.
Definition tensor.h:701
Tensor< T > & conj()
Inplace complex conjugate.
Definition tensor.h:721
SliceTensor< T > operator()(const Slice &s0, long j, const Slice &s2)
Return a 2d SliceTensor that views the specified range of the 3d Tensor.
Definition tensor.h:1220
SliceTensor< T > operator()(const std::vector< Slice > &s)
General slicing operation.
Definition tensor.h:1065
Definition thread_specific.h:82
static const double R
Definition csqrt.cc:46
char * p(char *buf, const char *name, int k, int initial_level, double thresh, int order)
Definition derivatives.cc:72
archive_array< T > wrap(const T *, unsigned int)
Factory function to wrap a dynamically allocated pointer as a typed archive_array.
Definition archive.h:914
Tensor< T > identity_matrix(long n)
Returns the identity matrix of the specified size.
Definition tensor.h:2804
Tensor< T > conj_transpose(const Tensor< T > &t)
Returns a new deep copy of the complex conjugate transpose of the input tensor.
Definition tensor.h:2048
Tensor< typename Tensor< T >::scalar_type > arg(const Tensor< T > &t)
Return a new tensor holding the argument of each element of t (complex types only).
Definition tensor.h:2761
Tensor< TENSOR_RESULT_TYPE(T, Q) > & fast_transform(const Tensor< T > &t, const Tensor< Q > &c, Tensor< TENSOR_RESULT_TYPE(T, Q) > &result, Tensor< TENSOR_RESULT_TYPE(T, Q) > &workspace)
Restricted but heavily optimized form of transform().
Definition tensor.h:2464
void inner_result(const Tensor< T > &left, const Tensor< Q > &right, long k0, long k1, Tensor< TENSOR_RESULT_TYPE(T, Q) > &result)
Accumulate inner product into user provided, contiguous, correctly sized result tensor.
Definition tensor.h:2316
Tensor< T > transpose(const Tensor< T > &t)
Returns a new deep copy of the transpose of the input tensor.
Definition tensor.h:2039
const double beta
Definition gygi_soltion.cc:62
Tensor< double > op(const Tensor< double > &x)
Definition kain.cc:508
#define MADNESS_RESTRICT
Definition mTxmq.h:37
Macros and tools pertaining to the configuration of MADNESS.
#define MADNESS_PRAGMA_GCC(x)
Definition madness_config.h:205
#define MADNESS_CHECK(condition)
Check a condition — even in a release build the condition is always evaluated so it can have side eff...
Definition madness_exception.h:182
Internal use only.
Definition potentialmanager.cc:41
void eval_scratch_clear()
Definition tensor.h:2741
std::pair< Tensor< R > &, Tensor< R > & > eval_scratch(long need)
Definition tensor.h:2727
thread_specific< EvalScratch< R > > & eval_scratch_pool()
Definition tensor.h:2711
T mynorm(T t)
Definition tensor.h:256
Namespace for all elements and tools of MADNESS.
Definition DFConvergence.h:9
std::ostream & operator<<(std::ostream &os, const particle< PDIM > &p)
Definition lowrankfunction.h:452
void RandomVector(int n, T *t)
Definition ran.h:153
double abs(double x)
Definition complexfun.h:48
void mTxmT(long dimi, long dimj, long dimk, T *MADNESS_RESTRICT c, const T *a, const T *b)
Matrix += Matrix transpose * matrix transpose ... MKL interface version.
Definition mxm.h:204
void outer_result(const Tensor< T > &left, const Tensor< T > &right, Tensor< T > &result)
Outer product ... result(i,j,...,p,q,...) = left(i,k,...)*right(p,q,...).
Definition tensor.h:2243
Q conditional_conj(const Q &coeff)
For real types return value, for complex return conjugate.
Definition tensor.h:251
GenTensor< TENSOR_RESULT_TYPE(R, Q)> general_transform(const GenTensor< R > &t, const Tensor< Q > c[])
Definition gentensor.h:274
int FunctionDefaults< NDIM >::k
Definition mraimpl.h:3878
Function< Q, NDIM > convert(const Function< T, NDIM > &f, bool fence=true)
Type conversion implies a deep copy. No communication except for optional fence.
Definition mra.h:2286
void mxm(long dimi, long dimj, long dimk, T *MADNESS_RESTRICT c, const T *a, const T *b)
Matrix += Matrix * matrix ... BLAS/MKL interface version.
Definition mxm.h:165
std::vector< Function< TENSOR_RESULT_TYPE(T, R), NDIM > > transform(World &world, const std::vector< Function< T, NDIM > > &v, const Tensor< R > &c, bool fence=true)
Transforms a vector of functions according to new[i] = sum[j] old[j]*c[j,i].
Definition vmra.h:807
Function< T, NDIM > conj(const Function< T, NDIM > &f, bool fence=true)
Return the complex conjugate of the input function with the same distribution and optional fence.
Definition mra.h:2300
void mTxm(long dimi, long dimj, long dimk, T *MADNESS_RESTRICT c, const T *a, const T *b)
Matrix += Matrix transpose * matrix ... MKL interface version.
Definition mxm.h:178
Tensor< TENSOR_RESULT_TYPE(T, Q)> & general_fast_transform(const Tensor< T > &t, const Tensor< Q > *c, Tensor< TENSOR_RESULT_TYPE(T, Q)> &result, Tensor< TENSOR_RESULT_TYPE(T, Q)> &workspace)
Definition tensor.h:2568
std::vector< CCPairFunction< T, NDIM > > operator*(const double fac, const std::vector< CCPairFunction< T, NDIM > > &arg)
Definition ccpairfunction.h:1111
std::vector< CCPairFunction< T, NDIM > > operator+(const CCPairFunction< T, NDIM > c1, const CCPairFunction< T, NDIM > &c2)
Definition ccpairfunction.h:1066
Function< T, NDIM > sum(World &world, const std::vector< Function< T, NDIM > > &f, bool fence=true)
Returns new function — q = sum_i f[i].
Definition vmra.h:1774
ConcurrentHashMap< hashT, std::shared_ptr< GaussianConvolution1D< double > > > GaussianConvolution1DCache< double >::map
Definition convolution1d.h:1073
std::enable_if< std::is_base_of< ProjectorBase, projT >::value, OuterProjector< projT, projQ > >::type outer(const projT &p0, const projQ &p1)
Definition projector.h:476
std::vector< CCPairFunction< T, NDIM > > operator-(const std::vector< CCPairFunction< T, NDIM > > c1, const std::vector< CCPairFunction< T, NDIM > > &c2)
Definition ccpairfunction.h:1082
static double pop(std::vector< double > &v)
Definition SCF.cc:118
static void aligned_zero(long n, T *a)
Definition aligned.h:55
const Future< void > Future< void >::value
Definition future.cc:44
T RandomValue()
Random value that wraps the default Fibonacci generator.
double imag(double x)
Definition complexfun.h:56
GenTensor< TENSOR_RESULT_TYPE(R, Q)> transform_dir(const GenTensor< R > &t, const Tensor< Q > &c, const int axis)
Definition lowranktensor.h:1108
std::string type(const PairType &n)
Definition PNOParameters.h:18
static const long default_jdim
Definition tensoriter.h:57
Function< T, CCPairFunction< T, NDIM >::LDIM > inner(const CCPairFunction< T, NDIM > &c, const Function< T, CCPairFunction< T, NDIM >::LDIM > &f, const std::tuple< int, int, int > v1, const std::tuple< int, int, int > v2)
Definition ccpairfunction.h:1007
double real(double x)
Definition complexfun.h:52
const FunctionCommonData< T, NDIM > * FunctionCommonData< T, NDIM >::data[MAXK]
Definition mraimpl.h:3875
void mxmT(long dimi, long dimj, long dimk, T *MADNESS_RESTRICT c, const T *a, const T *b)
Matrix += Matrix * matrix transpose ... MKL interface version.
Definition mxm.h:191
Function< T, NDIM > copy(const Function< T, NDIM > &f, const std::shared_ptr< WorldDCPmapInterface< Key< NDIM > > > &pmap, bool fence=true)
Create a new copy of the function with different distribution and optional fence.
Definition mra.h:2239
void mTxmq(long dimi, long dimj, long dimk, double *MADNESS_RESTRICT c, const double *a, const double *b, long ldb)
Explicit template specializations for homogeneous types (implemented in mTxmq.cc).
Definition mTxmq.cc:551
Definition mraimpl.h:53
static long abs(long a)
Definition tensor.h:214
static const double d
Definition nonlinschro.cc:121
static const double a
Definition nonlinschro.cc:118
Implement dummy posix_memalign if it is missing on the system.
int posix_memalign(void **memptr, std::size_t alignment, std::size_t size)
Definition posixmem.h:44
std::complex< float > float_complex
Definition ran.h:40
double Q(double a)
Definition relops.cc:20
static const double c
Definition relops.cc:10
static const double m
Definition relops.cc:9
Definition test_ar.cc:204
Definition type_data.h:146
static void load(const Archive &s, Tensor< T > &t)
Definition tensor.h:1934
Default load of an object via serialize(ar, t).
Definition archive.h:667
static void store(const Archive &s, const Tensor< T > &t)
Definition tensor.h:1919
Default store of an object via serialize(ar, t).
Definition archive.h:612
static Q op(const Q &coeff)
Definition tensor.h:244
For real types return value, for complex return conjugate.
Definition tensor.h:235
static Q op(const Q &coeff)
Definition tensor.h:236
Per-thread grow-on-demand buffer pair for general_fast_transform.
Definition tensor.h:2704
Tensor< R > b
Definition tensor.h:2704
Tensor< R > a
Definition tensor.h:2704
static const double s0
Definition tdse4.cc:83
#define TENSOR_SHARED_PTR
Definition tensor.h:307
#define TENSOR_ALIGNMENT
#define UNARY_UNOPTIMIZED_ITERATOR(X, x, exp)
Definition tensor_macros.h:678
#define BINARY_OPTIMIZED_ITERATOR(X, x, Y, y, exp)
Definition tensor_macros.h:701
#define UNARY_OPTIMIZED_ITERATOR(X, x, exp)
Definition tensor_macros.h:658
#define TERNARY_OPTIMIZED_ITERATOR(X, x, Y, y, Z, z, exp)
Definition tensor_macros.h:719
#define TENSOR_MAXDIM
Definition tensor_macros.h:194
Declares and implements TensorException.
#define TENSOR_ASSERT(condition, msg, value, t)
Definition tensorexcept.h:130
#define TENSOR_EXCEPTION(msg, value, t)
Definition tensorexcept.h:126
Declares TensorIterator.
static const double alpha
Definition testcosine.cc:10
const double offset
Definition testfuns.cc:143
std::size_t axis
Definition testpdiff.cc:59
double k0
Definition testperiodic.cc:66
double k1
Definition testperiodic.cc:67
Reclaimable thread-specific storage (a thread_local you can free).
#define TENSOR_RESULT_TYPE(L, R)
This macro simplifies access to TensorResultType.
Definition type_data.h:205