v0.8.12
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> class Tensor2
17  {
18  T data[Tensor_Dim0][Tensor_Dim1];
19 
20  public:
21  /* Initializations for varying numbers of elements. */
22  template <class... U> Tensor2(U... d) : data{d...}
23  {
24  static_assert(sizeof...(d) == sizeof(data) / sizeof(T),
25  "Incorrect number of Arguments. Constructor should "
26  "initialize the entire Tensor");
27  }
28 
29  Tensor2() {}
30 
31  /* Get ptr */
32 
33  T *ptr(const int N1, const int N2) const {
34 #ifdef FTENSOR_DEBUG
35  if (N1 >= Tensor_Dim0 || N1 < 0 || N2 >= Tensor_Dim1 || N2 < 0) {
36  std::stringstream s;
37  s << "Bad index in Tensor2<T*," << Tensor_Dim0 << "," << Tensor_Dim1
38  << ">.ptr(" << N1 << "," << N2 << ")" << std::endl;
39  throw std::out_of_range(s.str());
40  }
41 #endif
42  return &data[N1][N2];
43  }
44 
45  /* There are two operator(int,int)'s, one for non-consts that lets you
46  change the value, and one for consts that doesn't. */
47 
48  T &operator()(const int N1, const int N2)
49  {
50 #ifdef FTENSOR_DEBUG
51  if(N1 >= Tensor_Dim0 || N1 < 0 || N2 >= Tensor_Dim1 || N2 < 0)
52  {
53  std::stringstream s;
54  s << "Bad index in Tensor2<T," << Tensor_Dim0 << "," << Tensor_Dim1
55  << ">.operator(" << N1 << "," << N2 << ")" << std::endl;
56  throw std::out_of_range(s.str());
57  }
58 #endif
59  return data[N1][N2];
60  }
61 
62  T operator()(const int N1, const int N2) const
63  {
64 #ifdef FTENSOR_DEBUG
65  if(N1 >= Tensor_Dim0 || N1 < 0 || N2 >= Tensor_Dim1 || N2 < 0)
66  {
67  std::stringstream s;
68  s << "Bad index in Tensor2<T," << Tensor_Dim0 << "," << Tensor_Dim1
69  << ">.operator(" << N1 << "," << N2 << ") const" << std::endl;
70  throw std::out_of_range(s.str());
71  }
72 #endif
73  return data[N1][N2];
74  }
75 
76  /* These operator()'s are the first part in constructing template
77  expressions. They can be used to slice off lower dimensional
78  parts. They are not entirely safe, since you can accidentaly use a
79  higher dimension than what is really allowed (like Dim=5). */
80 
81  template <char i, char j, int Dim0, int Dim1>
82  typename std::enable_if<(Tensor_Dim0 >= Dim0 && Tensor_Dim1 >= Dim1),
84  T, Dim0, Dim1, i, j>>::type
85  operator()(const Index<i, Dim0>, const Index<j, Dim1>)
86  {
88  i, j>(*this);
89  }
90 
91  template <char i, char j, int Dim0, int Dim1>
92  typename std::enable_if<
93  (Tensor_Dim0 >= Dim0 && Tensor_Dim1 >= Dim1),
95  i, j>>::type
96  operator()(const Index<i, Dim0>, const Index<j, Dim1>) const
97  {
99  Dim1, i, j>(*this);
100  }
101 
102  /* This is for expressions where a number is used for one slot, and
103  an index for another, yielding a Tensor1_Expr. The non-const
104  versions don't actually create a Tensor2_number_rhs_[01] object.
105  They create a Tensor1_Expr directly, which provides the
106  appropriate indexing operators. The const versions do create a
107  Tensor2_number_[01]. */
108 
109  template <char i, int Dim, int N>
110  typename std::enable_if<
111  (Tensor_Dim0 >= Dim && Tensor_Dim1 > N),
112  Tensor1_Expr<
114  Dim, i>>::type
115  operator()(const Index<i, Dim>, const Number<N>)
116  {
117  using TensorExpr
120  }
121 
122  template <char i, int Dim, int N>
123  typename std::enable_if<
124  (Tensor_Dim0 > N && Tensor_Dim1 >= Dim),
125  Tensor1_Expr<
127  Dim, i>>::type
128  operator()(const Number<N>, const Index<i, Dim>)
129  {
130  using TensorExpr
133  }
134 
135  template <char i, int Dim, int N>
136  typename std::enable_if<
137  (Tensor_Dim0 >= Dim && Tensor_Dim1 > N),
140  T, Dim, i>>::type
141  operator()(const Index<i, Dim>, const Number<N>) const
142  {
143  using TensorExpr
145  return Tensor1_Expr<TensorExpr, T, Dim, i>(TensorExpr(*this));
146  }
147 
148  template <char i, int Dim, int N>
149  typename std::enable_if<
150  (Tensor_Dim0 > N && Tensor_Dim1 >= Dim),
153  T, Dim, i>>::type
154  operator()(const Number<N>, const Index<i, Dim>) const
155  {
156  using TensorExpr
158  return Tensor1_Expr<TensorExpr, T, Dim, i>(TensorExpr(*this));
159  }
160 
161  /* This is for expressions where an actual number (not a Number<>)
162  is used for one slot, and an index for another, yielding a
163  Tensor1_Expr. */
164 
165  /* Unfortunately since this integers can only be checked at run time
166  i can only partially protect this expressions. We should suggest
167  when ever possible to use Number<>. */
168 
169  template <char i, int Dim>
170  typename std::enable_if<
171  (Tensor_Dim0 >= Dim),
172  Tensor1_Expr<
174  Dim, i>>::type
175  operator()(const Index<i, Dim>, const int N) const
176  {
177  using TensorExpr
179  return Tensor1_Expr<TensorExpr, T, Dim, i>(TensorExpr(*this, N));
180  }
181 
182  template <char i, int Dim>
183  typename std::enable_if<
184  (Tensor_Dim1 >= Dim),
185  Tensor1_Expr<
187  Dim, i>>::type
188  operator()(const int N, const Index<i, Dim>) const
189  {
190  using TensorExpr
192  return Tensor1_Expr<TensorExpr, T, Dim, i>(TensorExpr(*this, N));
193  }
194 
195  /* These two operator()'s return the Tensor2 with internal
196  contractions, yielding a T. I have to specify one for both
197  const and non-const because otherwise the compiler will use the
198  operator() which gives a Tensor2_Expr<>. */
199 
200  template <char i, int Dim>
201  typename std::enable_if<(Tensor_Dim0 >= Dim && Tensor_Dim1 >= Dim), 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), T>::type
209  operator()(const Index<i, Dim>, const Index<i, Dim>) const
210  {
211  return internal_contract(Number<Dim>());
212  }
213 
214  private:
215  template <int N> T internal_contract(Number<N>) const
216  {
217  return data[N - 1][N - 1] + internal_contract(Number<N - 1>());
218  }
219 
220  T internal_contract(Number<1>) const { return data[0][0]; }
221  };
222 }
223 
224 /// JSON compatible output
225 
226 namespace FTensor
227 {
228  template <class T, int Tensor_Dim0, int Tensor_Dim1>
229  std::ostream &
230  Tensor2_ostream_row(std::ostream &os,
232  const int &i)
233  {
234  os << '[';
235  for(int j = 0; j + 1 < Tensor_Dim1; ++j)
236  {
237  os << t(i, j) << ',';
238  }
239  if(Tensor_Dim1 > 0)
240  {
241  os << t(i, Tensor_Dim1 - 1);
242  }
243  os << ']';
244  return os;
245  }
246 }
247 
248 template <class T, int Tensor_Dim0, int Tensor_Dim1>
249 std::ostream &
250 operator<<(std::ostream &os,
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>
270  std::istream &
271  Tensor2_istream_row(std::istream &is,
273  const int &i)
274  {
275  char c;
276  is >> c;
277  for(int j = 0; j + 1 < Tensor_Dim1; ++j)
278  {
279  is >> t(i, j) >> c;
280  }
281  if(Tensor_Dim1 > 0)
282  {
283  is >> t(i, Tensor_Dim1 - 1);
284  }
285  is >> c;
286  return is;
287  }
288 }
289 
290 template <class T, int Tensor_Dim0, int Tensor_Dim1>
291 std::istream &
293 {
294  char c;
295  is >> c;
296  for(int i = 0; i + 1 < Tensor_Dim0; ++i)
297  {
299  is >> c;
300  }
301  if(Tensor_Dim0 > 0)
302  {
303  FTensor::Tensor2_istream_row(is, t, Tensor_Dim0 - 1);
304  }
305  is >> c;
306  return is;
307 }
std::istream & operator>>(std::istream &is, FTensor::Tensor2< T, Tensor_Dim0, Tensor_Dim1 > &t)
std::istream & Tensor2_istream_row(std::istream &is, FTensor::Tensor2< T, Tensor_Dim0, Tensor_Dim1 > &t, const int &i)
const Tensor1_Expr< const dTensor0< T, Dim, i >, typename promote< T, double >::V, Dim, i > d(const Tensor0< T *> &a, const Index< i, Dim > index, const Tensor1< int, Dim > &d_ijk, const Tensor1< double, Dim > &d_xyz)
Definition: dTensor0.hpp:27
Fully Antisymmetric Levi-Civita Tensor.
T operator()(const int N1, const int N2) const
T * ptr(const int N1, const int N2) const
std::ostream & Tensor2_ostream_row(std::ostream &os, const FTensor::Tensor2< T, Tensor_Dim0, Tensor_Dim1 > &t, const int &i)
T data[Tensor_Dim0][Tensor_Dim1]
T & operator()(const int N1, const int N2)
std::ostream & operator<<(std::ostream &os, const FTensor::Tensor2< T, Tensor_Dim0, Tensor_Dim1 > &t)
T internal_contract(Number< N >) const
T internal_contract(Number< 1 >) const
const int N
Definition: speed_test.cpp:3