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   $Id$
33 */
34 
35 
36 #ifndef MADNESS_TENSOR_BASETENSOR_H__INCLUDED
37 #define MADNESS_TENSOR_BASETENSOR_H__INCLUDED
38 
39 /// \file basetensor.h
40 /// \brief Declares BaseTensor
41 
42 #include <complex>
43 
44 typedef std::complex<float> float_complex;
45 typedef std::complex<double> double_complex;
46 
47 // These probably have to be included in this order
48 #include <madness/tensor/tensor_macros.h>
49 #include <madness/tensor/type_data.h>
50 #include <madness/tensor/slice.h>
51 #include <madness/tensor/vector_factory.h>
52 
53 #include <madness/madness_config.h>
54 #include <madness/tensor/slice.h>
55 #include <madness/tensor/tensor_macros.h>
56 
57 #ifdef TENSOR_INSTANCE_COUNT
58 #include <madness/world/atomicint.h>
59 #endif
60 
61 namespace madness {
62     /*!
63       \ingroup tensor
64       \brief The base class for tensors defines generic capabilities.
65 
66       The base class manages the size, dimension and
67       stride information, and provides operations to manipulate
68       them.
69 
70       It also provides methods for type-safe operation on tensors using
71       just the base class pointers. This interface is primarily useful
72       only to the interface to Python, since Python is largely neutral
73       to (and ignorant of) the type.  These are still being
74       re-implemented after the big clean up.
75 
76       Since the base tensor class is virtual, you cannot have an
77       instance of it.  Thus, in addition to methods that return information
78       or perform checks, there are two types of base tensor
79       operations.
80         - Inplace operations change \c *this , and return \c void .
81         - Operations that must return a new tensor return a pointer to a tensor
82           allocated with \c new on the heap.  The caller is responsible for
83           eventually freeing the memory using \c delete .
84     */
85     class BaseTensor {
86     private:
87 #ifdef TENSOR_INSTANCE_COUNT
88         static madness::AtomicInt instance_count; ///< For debug, count total# instances
89 #endif
90 
91     protected:
92 
93         long _size;			///< Number of elements in the tensor
94         long _ndim;			///< Number of dimensions (-1=invalid; 0=no supported; >0=tensor)
95         long _id; 			///< Id from TensorTypeData<T> in type_data.h
96         long _dim[TENSOR_MAXDIM];	///< Size of each dimension
97         long _stride[TENSOR_MAXDIM];     ///< Increment between elements in each dimension
98 
set_dims_and_size(long nd,const long d[])99         void set_dims_and_size(long nd, const long d[]) {
100             _ndim = nd;
101             _size = 1;
102             if (_ndim < 0) _size=0;
103             for (long i=_ndim-1; i>=0; --i) {
104                 _dim[i] = d[i];
105                 _stride[i] = _size;
106                 _size *= d[i];
107             }
108             for (long i=std::max(_ndim,0L); i<TENSOR_MAXDIM; ++i) { // So can iterate over missing dimensions
109                 _dim[i] = 1;
110                 _stride[i] = 0;
111             }
112         }
113 
114     public:
115 
BaseTensor()116         BaseTensor() : _size(0), _ndim(-1) {
117 #ifdef TENSOR_INSTANCE_COUNT
118             instance_count++;
119 #endif
120         }
121 
~BaseTensor()122         virtual ~BaseTensor() {
123 #ifdef TENSOR_INSTANCE_COUNT
124             instance_count--;
125 #endif
126         }
127 
128         /// Returns the count of all current instances of tensors & slice tensors of all types.
get_instance_count()129         static inline int get_instance_count() {
130 #ifdef TENSOR_INSTANCE_COUNT
131             return instance_count;
132 #else
133             return 0;
134 #endif
135         }
136 
137         /// Returns the number of elements in the tensor
size()138         long size() const {return _size;}
139 
140         /// Returns the typeid of the tensor (c.f., \c TensorTypeData<T> )
id()141         long id() const {return _id;}
142 
143         /// Returns the number of dimensions in the tensor
ndim()144         long ndim() const {return _ndim;}
145 
146         /// Returns the size of dmension \c i
dim(int i)147         long dim(int i) const {return _dim[i];}
148 
149         /// Returns the stride associated with dimension \c i
stride(int i)150         long stride(int i) const {return _stride[i];}
151 
152         /// Returns the array of tensor dimensions
dims()153         const long* dims() const {return _dim;}
154 
155         /// Returns the array of tensor strides
strides()156         const long* strides() const {return _stride;}
157 
158         /// Returns true if this and *t are the same shape and size
conforms(const BaseTensor * t)159         bool conforms(const BaseTensor *t) const {
160             if (_ndim != t->_ndim) return false;
161             for (long i=0; i<_ndim; ++i) {
162                 if (_dim[i] != t->_dim[i]) return false;
163             }
164             return true;
165         }
166 
167         /// Returns true if the tensor refers to contiguous memory locations.
iscontiguous()168         bool iscontiguous() const {
169             if (_size <= 0) return true;
170             long sz = 1;
171             for (long i=_ndim-1; i>=0; --i) {
172                 if (_stride[i] != sz) return false;
173                 sz *= _dim[i];
174             }
175             return true;
176         }
177 
178     protected:
179 
180         /// Reshapes the tensor inplace
181         void reshape_inplace(const std::vector<long>& d);
182 
183         /// Reshapes the tensor inplace
184         void reshape_inplace(int ndimnew, const long* d);
185 
186         /// Reshapes the tensor inplace into 1D
187         void flat_inplace();
188 
189         /// Splits dimension \c i
190         void splitdim_inplace(long i, long dimi0, long dimi1);
191 
192         /// Fuses dimensions \c i and \c i+1
193         void fusedim_inplace(long i);
194 
195         /// Swaps the dimensions
196         void swapdim_inplace(long i, long j);
197 
198         /// Cyclic shift of dimensions
199         void cycledim_inplace(long shift, long start, long end);
200 
201         /// General permutation of dimensions
202         void mapdim_inplace(const std::vector<long>& map);
203     };
204 
205 }
206 
207 #endif // MADNESS_TENSOR_BASETENSOR_H__INCLUDED
208