v0.7.2
Tensor2_value.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 /* A general version, not for pointers. */
4 
5 #include <ostream>
6 
7 #ifdef FTENSOR_DEBUG
8 #include <sstream>
9 #include <stdexcept>
10 #endif
11 
12 #pragma once
13 
14 namespace FTensor
15 {
16  template <class T, int Tensor_Dim0, int Tensor_Dim1,
17  Layout layout>
18  class Tensor2
19  {
20  T data[(layout==column_major) ? Tensor_Dim0 : Tensor_Dim1]
21  [(layout==column_major) ? Tensor_Dim1 : Tensor_Dim0];
22  public:
23  /* Initializations for varying numbers of elements, with each one
24  defined for a particular Tensor_Dim. To initialize a different
25  dimension, just add the appropriate constructor and call to
26  the Tensor2_constructor constructor. */
27  Tensor2(T d00, T d01)
28  {
30  (data,d00,d01);
31  }
32  Tensor2(T d00, T d01,T d10, T d11)
33  {
35  (data,d00,d01,d10,d11);
36  }
37  Tensor2(T d00, T d01, T d02, T d10, T d11, T d12, T d20, T d21, T d22)
38  {
40  (data,d00,d01,d02,d10,d11,d12,d20,d21,d22);
41  }
42  Tensor2(T d00, T d01, T d10, T d11, T d20, T d21)
43  {
45  (data,d00,d01,d10,d11,d20,d21);
46  }
47  Tensor2(T d00, T d01, T d02, T d03, T d10, T d11, T d12, T d13,
48  T d20, T d21, T d22, T d23, T d30, T d31, T d32, T d33)
49  {
51  (data,d00,d01,d02,d03,d10,d11,d12,d13,d20,d21,d22,d23,d30,d31,d32,d33);
52  }
53  Tensor2() {}
54 
55  /* There are two operator(int,int)'s, one for non-consts that lets you
56  change the value, and one for consts that doesn't. */
57 
58  T & operator()(const int N1, const int N2)
59  {
60 #ifdef FTENSOR_DEBUG
61  if(N1>=Tensor_Dim0 || N1<0 || N2>=Tensor_Dim1 || N2<0)
62  {
63  std::stringstream s;
64  s << "Bad index in Tensor2<T,"
65  << Tensor_Dim0 << "," << Tensor_Dim1
66  << ">.operator(" << N1 << "," << N2 << ")"
67  << std::endl;
68  throw std::runtime_error(s.str());
69  }
70 #endif
71  return ((layout==column_major) ? data[N1][N2] : data[N2][N1]);
72  }
73 
74  T operator()(const int N1, const int N2) const
75  {
76 #ifdef FTENSOR_DEBUG
77  if(N1>=Tensor_Dim0 || N1<0 || N2>=Tensor_Dim1 || N2<0)
78  {
79  std::stringstream s;
80  s << "Bad index in Tensor2<T,"
81  << Tensor_Dim0 << "," << Tensor_Dim1
82  << ">.operator(" << N1 << "," << N2 << ") const"
83  << std::endl;
84  throw std::runtime_error(s.str());
85  }
86 #endif
87  return ((layout==column_major) ? data[N1][N2] : data[N2][N1]);
88  }
89 
90  /* These operator()'s are the first part in constructing template
91  expressions. They can be used to slice off lower dimensional
92  parts. They are not entirely safe, since you can accidently use a
93  higher dimension than what is really allowed (like Dim=5). */
94 
95  template<char i, char j, int Dim0, int Dim1>
96  typename std::enable_if<(Tensor_Dim0 >= Dim0 && Tensor_Dim1 >= Dim1),
98  operator()(const Index<i,Dim0> , const Index<j,Dim1> )
99  {
101  (*this);
102  }
103 
104  template<char i, char j, int Dim0, int Dim1>
105  typename std::enable_if<(Tensor_Dim0 >= Dim0 && Tensor_Dim1 >= Dim1),
106  Tensor2_Expr<const Tensor2<T,Tensor_Dim0,Tensor_Dim1,layout>,T,Dim0,Dim1,i,j> >::type
107  operator()(const Index<i,Dim0> , const Index<j,Dim1> ) const
108  {
110  T,Dim0,Dim1,i,j>(*this);
111  }
112 
113  /* This is for expressions where a number is used for one slot, and
114  an index for another, yielding a Tensor1_Expr. The non-const
115  versions don't actually create a Tensor2_number_rhs_[01] object.
116  They create a Tensor1_Expr directly, which provides the
117  appropriate indexing operators. The const versions do create a
118  Tensor2_number_[01]. */
119 
120  template<char i, int Dim, int N>
121  typename std::enable_if<(Tensor_Dim0 >= Dim && Tensor_Dim1 > N),
123  T,N>,T,Dim,i> >::type
124  operator()(const Index<i,Dim> , const Number<N> )
125  {
127  T,N> TensorExpr;
128  return Tensor1_Expr<TensorExpr,T,Dim,i>(*this);
129  }
130 
131  template<char i, int Dim, int N>
132  typename std::enable_if<(Tensor_Dim0 > N && Tensor_Dim1 >= Dim),
134  T,N>,T,Dim,i> >::type
135  operator()(const Number<N> , const Index<i,Dim> )
136  {
138  TensorExpr;
139  return Tensor1_Expr<TensorExpr,T,Dim,i>(*this);
140  }
141 
142  template<char i, int Dim, int N>
143  typename std::enable_if<(Tensor_Dim0 >= Dim && Tensor_Dim1 > N),
145  T,N>,T,Dim,i> >::type
146  operator()(const Index<i,Dim> , const Number<N> ) const
147  {
149  TensorExpr;
150  return Tensor1_Expr<TensorExpr,T,Dim,i>(TensorExpr(*this));
151  }
152 
153  template<char i, int Dim, int N>
154  typename std::enable_if<(Tensor_Dim0 > N && Tensor_Dim1 >= Dim),
156  T,N>,T,Dim,i> >::type
157  operator()(const Number<N> , const Index<i,Dim> ) const
158  {
160  TensorExpr;
161  return Tensor1_Expr<TensorExpr,T,Dim,i>(TensorExpr(*this));
162  }
163 
164  /* This is for expressions where an actual number (not a Number<>)
165  is used for one slot, and an index for another, yielding a
166  Tensor1_Expr. */
167 
168  /* Unfortunately since this integers can only be checked at run time
169  i can only partially protect this expressions. We should suggest
170  when ever possible to use Number<>. */
171 
172  template<char i, int Dim>
173  typename std::enable_if<(Tensor_Dim0 >= Dim),
175  <T,Tensor_Dim0,Tensor_Dim1>,T>,T,Dim,i> >::type
176  operator()(const Index<i,Dim>, const int N) const
177  {
179  TensorExpr;
180  return Tensor1_Expr<TensorExpr,T,Dim,i>(TensorExpr(*this,N));
181  }
182 
183  template<char i, int Dim>
184  typename std::enable_if<(Tensor_Dim1 >= Dim),
186  <T,Tensor_Dim0,Tensor_Dim1>,T>,T,Dim,i> >::type
187  operator()(const int N, const Index<i,Dim> ) const
188  {
190  TensorExpr;
191  return Tensor1_Expr<TensorExpr,T,Dim,i>(TensorExpr(*this,N));
192  }
193 
194  /* These two operator()'s return the Tensor2 with internal
195  contractions, yielding a T. I have to specify one for both
196  const and non-const because otherwise they compiler will use the
197  operator() which gives a Tensor2_Expr<>. */
198 
199  template<char i, int Dim>
200  typename std::enable_if<(Tensor_Dim0 >= Dim && Tensor_Dim1 >= Dim),
201  T>::type
202  operator()(const Index<i,Dim> , const Index<i,Dim> )
203  {
204  return internal_contract(Number<Dim>());
205  }
206 
207  template<char i, int Dim>
208  typename std::enable_if<(Tensor_Dim0 >= Dim && Tensor_Dim1 >= Dim),
209  T>::type operator()(const Index<i,Dim> , const Index<i,Dim> ) const
210  {
211  return internal_contract(Number<Dim>());
212  }
213  private:
214  template<int N>
216  {
217  return data[N-1][N-1] + internal_contract(Number<N-1>());
218  }
219 
221  {
222  return data[0][0];
223  }
224  };
225 }
226 
227 /// JSON compatible output
228 
229 namespace FTensor
230 {
231  template <class T, int Tensor_Dim0, int Tensor_Dim1, FTensor::Layout layout>
232  std::ostream &
234  (std::ostream &os,
236  const int &i)
237  {
238  os << '[';
239  for(int j=0; j+1<Tensor_Dim1; ++j)
240  { os << t(i,j) << ','; }
241  if(Tensor_Dim1>0)
242  { os << t(i,Tensor_Dim1-1); }
243  os << ']';
244  return os;
245  }
246 }
247 
248 template <class T, int Tensor_Dim0, int Tensor_Dim1, FTensor::Layout layout>
249 std::ostream & operator<<(std::ostream &os,
250  const FTensor::Tensor2<T,Tensor_Dim0,Tensor_Dim1,
251  layout> &t)
252 {
253  os << '[';
254  for(int i=0; i+1<Tensor_Dim0; ++i)
255  {
257  os << ',';
258  }
259  if(Tensor_Dim0>0)
260  {
261  FTensor::Tensor2_ostream_row(os,t,Tensor_Dim0-1);
262  }
263  os << ']';
264  return os;
265 }
266 
267 namespace FTensor
268 {
269  template <class T, int Tensor_Dim0, int Tensor_Dim1, FTensor::Layout layout>
270  std::istream &
272  (std::istream &is,
274  const int &i)
275  {
276  char c;
277  is >> c;
278  for(int j=0; j+1<Tensor_Dim1; ++j)
279  { is >> t(i,j) >> c; }
280  if(Tensor_Dim1>0)
281  { is >> t(i,Tensor_Dim1-1); }
282  is >> c;
283  return is;
284  }
285 }
286 
287 template <class T, int Tensor_Dim0, int Tensor_Dim1, FTensor::Layout layout>
288 std::istream & operator>>(std::istream &is,
289  FTensor::Tensor2<T,Tensor_Dim0,Tensor_Dim1,
290  layout> &t)
291 {
292  char c;
293  is >> c;
294  for(int i=0; i+1<Tensor_Dim0; ++i)
295  {
297  is >> c;
298  }
299  if(Tensor_Dim0>0)
300  {
301  FTensor::Tensor2_istream_row(is,t,Tensor_Dim0-1);
302  }
303  is >> c;
304  return is;
305 }
Tensor2(T d00, T d01, T d02, T d10, T d11, T d12, T d20, T d21, T d22)
Tensor2(T d00, T d01)
T internal_contract(Number< 1 >) const
std::istream & operator>>(std::istream &is, FTensor::Tensor2< T, Tensor_Dim0, Tensor_Dim1, layout > &t)
JSON compatible output.
std::istream & Tensor2_istream_row(std::istream &is, FTensor::Tensor2< T, Tensor_Dim0, Tensor_Dim1, layout > &t, const int &i)
Tensor2(T d00, T d01, T d10, T d11)
T internal_contract(Number< N >) const
Tensor2(T d00, T d01, T d02, T d03, T d10, T d11, T d12, T d13, T d20, T d21, T d22, T d23, T d30, T d31, T d32, T d33)
std::ostream & operator<<(std::ostream &os, const FTensor::Tensor2< T, Tensor_Dim0, Tensor_Dim1, layout > &t)
std::ostream & Tensor2_ostream_row(std::ostream &os, const FTensor::Tensor2< T, Tensor_Dim0, Tensor_Dim1, layout > &t, const int &i)
T & operator()(const int N1, const int N2)
const int N
Definition: speed_test.cpp:3
Tensor2(T d00, T d01, T d10, T d11, T d20, T d21)
T data[(layout==column_major) ? Tensor_Dim0 :Tensor_Dim1][(layout==column_major) ? Tensor_Dim1 :Tensor_Dim0]
T operator()(const int N1, const int N2) const