v0.14.0
Loading...
Searching...
No Matches
Tensor2_antisymmetric_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
7namespace FTensor
8{
9 template <class T, int Tensor_Dim> class Tensor2_antisymmetric
10 {
11 T data[(Tensor_Dim * (Tensor_Dim - 1)) / 2];
12
13 public:
14 template <class... U> Tensor2_antisymmetric(U... d) : data{d...}
15 {
16 static_assert(sizeof...(d) == sizeof(data) / sizeof(T),
17 "Incorrect number of Arguments. Constructor should "
18 "initialize the entire Tensor");
19 }
20
22
23 /* There are two ways of accessing the values inside,
24 unsafe(int,int) and operator(int,int). unsafe(int,int) will give
25 you a wrong answer if you aren't careful. The problem is that we
26 only store the minimal set of components, but some have different
27 signs. We can't return the negative of a component, and assign
28 something to it, because that would assign something to a
29 temporary. To get the correct answer if you don't want to change
30 the value, just use operator(int,int). */
31
32 T &unsafe(const int N1, const int N2)
33 {
34#ifdef FTENSOR_DEBUG
35 if(N1 >= Tensor_Dim || N1 < 0 || N2 >= Tensor_Dim || N2 < 0 || N1 >= N2)
36 {
37 std::stringstream s;
38 s << "Bad index in Tensor2_antisymmetric<T," << Tensor_Dim
39 << ">.operator(" << N1 << "," << N2 << ")" << std::endl;
40 throw std::out_of_range(s.str());
41 }
42#endif
43 return data[(N2 - 1) + (N1 * (2 * (Tensor_Dim - 1) - N1 - 1)) / 2];
44 }
45
46 T operator()(const int N1, const int N2) const
47 {
48#ifdef FTENSOR_DEBUG
49 if(N1 >= Tensor_Dim || N1 < 0 || N2 >= Tensor_Dim || N2 < 0)
50 {
51 std::stringstream s;
52 s << "Bad index in Tensor2_antisymmetric<T," << Tensor_Dim
53 << ">.operator(" << N1 << "," << N2 << ") const" << std::endl;
54 throw std::out_of_range(s.str());
55 }
56#endif
57 return N1 == N2
58 ? 0
59 : (N1 < N2
60 ? data[(N2 - 1)
61 + (N1 * (2 * (Tensor_Dim - 1) - N1 - 1)) / 2]
62 : -data[(N1 - 1)
63 + (N2 * (2 * (Tensor_Dim - 1) - N2 - 1)) / 2]);
64 }
65
66 /* These operator()'s are the first part in constructing template
67 expressions. They can be used to slice off lower dimensional
68 parts. They are not entirely safe, since you can accidently use a
69 higher dimension than what is really allowed (like Dim=5). */
70
71 /* This returns a Tensor2_Expr, since the indices are not really
72 antisymmetric anymore since they cover different dimensions. */
73
74 template <char i, char j, int Dim0, int Dim1>
75 typename std::enable_if<(Tensor_Dim >= Dim0 && Tensor_Dim >= Dim1),
77 T, Dim0, Dim1, i, j>>::type
78 operator()(const Index<i, Dim0>, const Index<j, Dim1>)
79 {
81 i, j>(*this);
82 }
83
84 template <char i, char j, int Dim0, int Dim1>
85 typename std::enable_if<
86 (Tensor_Dim >= Dim0 && Tensor_Dim >= Dim1),
88 i, j>>::type
89 operator()(const Index<i, Dim0>, const Index<j, Dim1>) const
90 {
92 Dim1, i, j>(*this);
93 }
94
95 /* This returns a Tensor2_antisymmetric_Expr, since the indices are still
96 antisymmetric on the lower dimensions. */
97
98 template <char i, char j, int Dim>
99 typename std::enable_if<
100 (Tensor_Dim >= Dim),
102 i, j>>::type
103 operator()(const Index<i, Dim> index1, const Index<j, Dim> index2)
104 {
106 T, Dim, i, j>(*this);
107 }
108
109 template <char i, char j, int Dim>
110 typename std::enable_if<
111 (Tensor_Dim >= Dim),
113 Dim, i, j>>::type
114 operator()(const Index<i, Dim> index1, const Index<j, Dim> index2) const
115 {
117 const Tensor2_antisymmetric<T, Tensor_Dim>, T, Dim, i, j>(*this);
118 }
119
120 /* This is for expressions where a number is used for one slot, and
121 an index for another, yielding a Tensor1_Expr. The non-const
122 versions don't actually create a Tensor2_number_rhs_[01] object.
123 They create a Tensor1_Expr directly, which provides the
124 appropriate indexing operators. The const versions do create a
125 Tensor2_number_[01]. */
126
127 template <char i, int N, int Dim>
128 typename std::enable_if<
129 (Tensor_Dim >= Dim && Tensor_Dim > N),
132 Dim, i>>::type
133 operator()(const Index<i, Dim> index1, const Number<N>)
134 {
135 using TensorExpr
138 }
139
140 template <char i, int N, int Dim>
141 typename std::enable_if<
142 (Tensor_Dim >= Dim && Tensor_Dim > N),
145 T, Dim, i>>::type
146 operator()(const Index<i, Dim> index1, const Number<N>) const
147 {
148 using TensorExpr
150 return Tensor1_Expr<TensorExpr, T, Dim, i>(TensorExpr(*this));
151 }
152
153 template <char i, int N, int Dim>
154 typename std::enable_if<
155 (Tensor_Dim > N && Tensor_Dim >= Dim),
158 Dim, i>>::type
159 operator()(const Number<N>, const Index<i, Dim> index1)
160 {
161 using TensorExpr
164 }
165
166 template <char i, int N, int Dim>
167 typename std::enable_if<
168 (Tensor_Dim > N && Tensor_Dim >= Dim),
171 T, Dim, i>>::type
172 operator()(const Number<N> &n1, const Index<i, Dim> index1) const
173 {
174 using TensorExpr
176 return Tensor1_Expr<TensorExpr, T, Dim, i>(TensorExpr(*this));
177 }
178
179 /* Specializations for using actual numbers instead of Number<> */
180
181 template <char i, int Dim>
182 typename std::enable_if<
183 (Tensor_Dim >= Dim),
186 T, Dim, i>>::type
187 operator()(const Index<i, Dim> index1, const int N) const
188 {
189 using TensorExpr
191 return Tensor1_Expr<TensorExpr, T, Dim, i>(TensorExpr(*this, N));
192 }
193
194 template <char i, int Dim>
195 typename std::enable_if<
196 (Tensor_Dim >= Dim),
199 T, Dim, i>>::type
200 operator()(const int N, const Index<i, Dim> index1) const
201 {
202 using TensorExpr
204 return Tensor1_Expr<TensorExpr, T, Dim, i>(TensorExpr(*this, N));
205 }
206
207 /* These two operator()'s return the Tensor2 with internal
208 contractions, yielding a T. I have to specify one for both
209 const and non-const because otherwise the compiler will use the
210 operator() which gives a Tensor2_Expr<>. */
211
212 /* TODO Here is a good question. It wont create a problem if i put
213 a higher dimension Index in here but it would be
214 grammatically wrong. Im gonna add it for now, we can discuss it*/
215
216 template <char i, int Dim>
217 typename std::enable_if<(Tensor_Dim >= Dim), T>::type
218 operator()(const Index<i, Dim> index1, const Index<i, Dim> index2)
219 {
220 return 0;
221 }
222
223 template <char i, int Dim>
224 typename std::enable_if<(Tensor_Dim >= Dim), T>::type
225 operator()(const Index<i, Dim> index1, const Index<i, Dim> index2) const
226 {
227 return 0;
228 }
229 };
230}
231
232/// JSON compatible output. It only outputs unique, non-zero elments,
233/// so a 3x3 antisymmetric matrix only outputs 3 elements.
234
235namespace FTensor
236{
237 template <class T, int Tensor_Dim>
239 std::ostream &os, const FTensor::Tensor2_antisymmetric<T, Tensor_Dim> &t,
240 const int &i)
241 {
242 os << '[';
243 for(int j = i + 1; j + 1 < Tensor_Dim; ++j)
244 {
245 os << t(i, j) << ',';
246 }
247 if(Tensor_Dim > 0)
248 {
249 os << t(i, Tensor_Dim - 1);
250 }
251 os << ']';
252 return os;
253 }
254}
255
256template <class T, int Tensor_Dim>
257std::ostream &
258operator<<(std::ostream &os,
260{
261 os << '[';
262 for(int i = 0; i + 2 < Tensor_Dim; ++i)
263 {
265 os << ',';
266 }
267 if(Tensor_Dim > 1)
268 {
270 }
271 os << ']';
272 return os;
273}
274
275namespace FTensor
276{
277 template <class T, int Tensor_Dim>
280 const int &i)
281 {
282 char c;
283 is >> c;
284 for(int j = i + 1; j + 1 < Tensor_Dim; ++j)
285 {
286 is >> t.unsafe(i, j) >> c;
287 }
288 if(Tensor_Dim > 0)
289 {
290 is >> t.unsafe(i, Tensor_Dim - 1);
291 }
292 is >> c;
293 return is;
294 }
295}
296
297template <class T, int Tensor_Dim>
298std::istream &
300{
301 char c;
302 is >> c;
303 for(int i = 0; i + 2 < Tensor_Dim; ++i)
304 {
306 is >> c;
307 }
308 if(Tensor_Dim > 1)
309 {
311 }
312 is >> c;
313 return is;
314}
static Number< 2 > N2
static Number< 1 > N1
std::ostream & operator<<(std::ostream &os, const FTensor::Tensor2_antisymmetric< T, Tensor_Dim > &t)
std::istream & operator>>(std::istream &is, FTensor::Tensor2_antisymmetric< T, Tensor_Dim > &t)
T & unsafe(const int N1, const int N2)
T data[(Tensor_Dim *(Tensor_Dim - 1))/2]
T operator()(const int N1, const int N2) const
FTensor::Index< 'i', SPACE_DIM > i
const double c
speed of light (cm/ns)
FTensor::Index< 'j', 3 > j
const double T
Tensors class implemented by Walter Landry.
Definition FTensor.hpp:51
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
std::istream & Tensor2_antisymmetric_istream_row(std::istream &is, FTensor::Tensor2_antisymmetric< T, Tensor_Dim > &t, const int &i)
std::ostream & Tensor2_antisymmetric_ostream_row(std::ostream &os, const FTensor::Tensor2_antisymmetric< T, Tensor_Dim > &t, const int &i)
constexpr double t
plate stiffness
Definition plate.cpp:59
const int N
Definition speed_test.cpp:3