1#[cfg(test)]
2mod test;
3use crate::math::{Current, Reference};
4use crate::units::Dimensionless;
5
6use crate::math::assert::FiniteDifference;
7
8use std::{
9 array::from_fn,
10 fmt::{self, Debug, Display, Formatter},
11 iter::Sum,
12 marker::PhantomData,
13 ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Sub, SubAssign},
14};
15
16use super::{
17 Tensor, TensorArray,
18 rank_0::TensorRank0,
19 rank_2::{
20 TensorRank2, get_identity_1010_parts_1, get_identity_1010_parts_2,
21 get_identity_1010_parts_3, get_levi_civita_parts,
22 },
23};
24
25pub fn levi_civita<I, J, K>() -> TensorRank3<3, I, J, K> {
27 TensorRank3::from([
28 [[0.0, 0.0, 0.0], [0.0, 0.0, 1.0], [0.0, -1.0, 0.0]],
29 [[0.0, 0.0, -1.0], [0.0, 0.0, 0.0], [1.0, 0.0, 0.0]],
30 [[0.0, 1.0, 0.0], [-1.0, 0.0, 0.0], [0.0, 0.0, 0.0]],
31 ])
32}
33
34#[repr(transparent)]
38pub struct TensorRank3<const D: usize, I, J, K, U = Dimensionless>(
39 [TensorRank2<D, J, K, U>; D],
40 pub(super) PhantomData<I>,
41);
42
43impl<const D: usize, I, J, K, U> Clone for TensorRank3<D, I, J, K, U> {
44 fn clone(&self) -> Self {
45 Self(self.0.clone(), PhantomData)
46 }
47}
48
49impl<const D: usize, I, J, K, U> Debug for TensorRank3<D, I, J, K, U> {
50 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
51 self.0.fmt(f)
52 }
53}
54
55impl<const D: usize, I, J, K, U> PartialEq for TensorRank3<D, I, J, K, U> {
56 fn eq(&self, other: &Self) -> bool {
57 self.0 == other.0
58 }
59}
60
61impl<const D: usize, I, J, K, U> TensorRank3<D, I, J, K, U> {
62 fn canonical(&self) -> &TensorRank3<D, Reference, Reference, Reference, Dimensionless> {
63 unsafe {
64 &*(self as *const Self
65 as *const TensorRank3<D, Reference, Reference, Reference, Dimensionless>)
66 }
67 }
68 fn canonical_mut(
69 &mut self,
70 ) -> &mut TensorRank3<D, Reference, Reference, Reference, Dimensionless> {
71 unsafe {
72 &mut *(self as *mut Self
73 as *mut TensorRank3<D, Reference, Reference, Reference, Dimensionless>)
74 }
75 }
76 fn into_canonical(self) -> TensorRank3<D, Reference, Reference, Reference, Dimensionless> {
77 unsafe {
78 (&self as *const Self)
79 .cast::<TensorRank3<D, Reference, Reference, Reference, Dimensionless>>()
80 .read()
81 }
82 }
83}
84
85pub(super) fn relabel<const D: usize, I, J, K, U>(
86 tensor: TensorRank3<D, Reference, Reference, Reference, Dimensionless>,
87) -> TensorRank3<D, I, J, K, U> {
88 unsafe {
89 (&tensor as *const TensorRank3<D, Reference, Reference, Reference, Dimensionless>)
90 .cast::<TensorRank3<D, I, J, K, U>>()
91 .read()
92 }
93}
94
95impl<const D: usize> TensorRank3<D, Reference, Reference, Reference, Dimensionless> {
96 fn as_array_core(&self) -> [[[TensorRank0; D]; D]; D] {
97 let mut array = [[[0.0; D]; D]; D];
98 array
99 .iter_mut()
100 .zip(self.iter())
101 .for_each(|(entry_rank_2, tensor_rank_2)| *entry_rank_2 = tensor_rank_2.as_array());
102 array
103 }
104 fn zero_core() -> Self {
105 Self(from_fn(|_| TensorRank2::zero()), PhantomData)
106 }
107 fn add_assign_core(&mut self, tensor: Self) {
108 self.iter_mut()
109 .zip(tensor)
110 .for_each(|(self_i, tensor_i)| *self_i += tensor_i);
111 }
112 fn add_assign_ref_core(&mut self, tensor: &Self) {
113 self.iter_mut()
114 .zip(tensor.iter())
115 .for_each(|(self_i, tensor_i)| *self_i += tensor_i);
116 }
117 fn sub_assign_core(&mut self, tensor: Self) {
118 self.iter_mut()
119 .zip(tensor)
120 .for_each(|(self_i, tensor_i)| *self_i -= tensor_i);
121 }
122 fn sub_assign_ref_core(&mut self, tensor: &Self) {
123 self.iter_mut()
124 .zip(tensor.iter())
125 .for_each(|(self_i, tensor_i)| *self_i -= tensor_i);
126 }
127}
128
129impl<const D: usize, I, J, K, U> Default for TensorRank3<D, I, J, K, U> {
130 fn default() -> Self {
131 Self::zero()
132 }
133}
134
135impl<const D: usize, I, J, K, U> From<[[[TensorRank0; D]; D]; D]> for TensorRank3<D, I, J, K, U> {
136 fn from(array: [[[TensorRank0; D]; D]; D]) -> Self {
137 array.into_iter().map(|entry| entry.into()).collect()
138 }
139}
140
141pub const LEVI_CIVITA: TensorRank3<3, Current, Current, Current, Dimensionless> =
143 TensorRank3(get_levi_civita_parts(), PhantomData);
144
145pub(crate) const fn get_identity_1010_parts<I, J, K, U>() -> [TensorRank3<3, I, J, K, U>; 3] {
146 [
147 TensorRank3(get_identity_1010_parts_1(), PhantomData),
148 TensorRank3(get_identity_1010_parts_2(), PhantomData),
149 TensorRank3(get_identity_1010_parts_3(), PhantomData),
150 ]
151}
152
153impl<const D: usize, I, J, K, U> Display for TensorRank3<D, I, J, K, U> {
154 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
155 write!(f, "[")?;
156 self.iter()
157 .enumerate()
158 .try_for_each(|(i, entry)| write!(f, "{entry},\n\x1B[u\x1B[{}B\x1B[1D", i + 1))?;
159 write!(f, "\x1B[u\x1B[1A\x1B[{}C]", 16 * D + 1)
160 }
161}
162
163impl<const D: usize, I, J, K, U> FiniteDifference for TensorRank3<D, I, J, K, U> {
164 fn error_fd(&self, comparator: &Self, epsilon: TensorRank0) -> Option<(bool, usize)> {
165 let error_count = self
166 .iter()
167 .zip(comparator.iter())
168 .map(|(self_i, comparator_i)| {
169 self_i
170 .iter()
171 .zip(comparator_i.iter())
172 .map(|(self_ij, comparator_ij)| {
173 self_ij
174 .iter()
175 .zip(comparator_ij.iter())
176 .filter(|&(&self_ijk, &comparator_ijk)| {
177 self_ijk.differs(comparator_ijk, epsilon)
178 })
179 .count()
180 })
181 .sum::<usize>()
182 })
183 .sum();
184 if error_count > 0 {
185 Some((true, error_count))
186 } else {
187 None
188 }
189 }
190}
191
192impl<const D: usize, I, J, K, U> Tensor for TensorRank3<D, I, J, K, U> {
193 type Item = TensorRank2<D, J, K, U>;
194 type Unit = U;
195 fn iter(&self) -> impl Iterator<Item = &Self::Item> {
196 self.0.iter()
197 }
198 fn iter_mut(&mut self) -> impl Iterator<Item = &mut Self::Item> {
199 self.0.iter_mut()
200 }
201 fn len(&self) -> usize {
202 D
203 }
204 fn size(&self) -> usize {
205 D * D * D
206 }
207}
208
209impl<const D: usize, I, J, K, U> IntoIterator for TensorRank3<D, I, J, K, U> {
210 type Item = TensorRank2<D, J, K, U>;
211 type IntoIter = std::array::IntoIter<Self::Item, D>;
212 fn into_iter(self) -> Self::IntoIter {
213 self.0.into_iter()
214 }
215}
216
217impl<const D: usize, I, J, K, U> TensorArray for TensorRank3<D, I, J, K, U> {
218 type Array = [[[TensorRank0; D]; D]; D];
219 type Item = TensorRank2<D, J, K, U>;
220 fn as_array(&self) -> Self::Array {
221 self.canonical().as_array_core()
222 }
223 fn identity() -> Self {
224 panic!()
225 }
226 fn zero() -> Self {
227 relabel(TensorRank3::<
228 D,
229 Reference,
230 Reference,
231 Reference,
232 Dimensionless,
233 >::zero_core())
234 }
235}
236
237impl<const D: usize, I, J, K, U> FromIterator<TensorRank2<D, J, K, U>>
238 for TensorRank3<D, I, J, K, U>
239{
240 fn from_iter<Ii: IntoIterator<Item = TensorRank2<D, J, K, U>>>(into_iterator: Ii) -> Self {
241 let mut tensor_rank_3 = Self::zero();
242 tensor_rank_3
243 .iter_mut()
244 .zip(into_iterator)
245 .for_each(|(tensor_rank_3_i, value_i)| *tensor_rank_3_i = value_i);
246 tensor_rank_3
247 }
248}
249
250impl<const D: usize, I, J, K, U> Index<usize> for TensorRank3<D, I, J, K, U> {
251 type Output = TensorRank2<D, J, K, U>;
252 fn index(&self, index: usize) -> &Self::Output {
253 &self.0[index]
254 }
255}
256
257impl<const D: usize, I, J, K, U> IndexMut<usize> for TensorRank3<D, I, J, K, U> {
258 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
259 &mut self.0[index]
260 }
261}
262
263impl<const D: usize, I, J, K, U> Sum for TensorRank3<D, I, J, K, U> {
264 fn sum<Ii>(iter: Ii) -> Self
265 where
266 Ii: Iterator<Item = Self>,
267 {
268 iter.reduce(|mut acc, item| {
269 acc += item;
270 acc
271 })
272 .unwrap_or_else(Self::default)
273 }
274}
275
276impl<'a, const D: usize, I, J, K, U> Sum<&'a Self> for TensorRank3<D, I, J, K, U> {
277 fn sum<Ii>(iter: Ii) -> Self
278 where
279 Ii: Iterator<Item = &'a Self>,
280 {
281 iter.fold(Self::default(), |mut acc, item| {
282 acc += item;
283 acc
284 })
285 }
286}
287
288impl<const D: usize, I, J, K, U> Div<TensorRank0> for TensorRank3<D, I, J, K, U> {
289 type Output = Self;
290 fn div(mut self, tensor_rank_0: TensorRank0) -> Self::Output {
291 self /= &tensor_rank_0;
292 self
293 }
294}
295
296impl<const D: usize, I, J, K, U> Div<TensorRank0> for &TensorRank3<D, I, J, K, U> {
297 type Output = TensorRank3<D, I, J, K, U>;
298 fn div(self, tensor_rank_0: TensorRank0) -> Self::Output {
299 self.iter().map(|self_i| self_i / tensor_rank_0).collect()
300 }
301}
302
303impl<const D: usize, I, J, K, U> Div<&TensorRank0> for TensorRank3<D, I, J, K, U> {
304 type Output = Self;
305 fn div(mut self, tensor_rank_0: &TensorRank0) -> Self::Output {
306 self /= tensor_rank_0;
307 self
308 }
309}
310
311impl<const D: usize, I, J, K, U> DivAssign<TensorRank0> for TensorRank3<D, I, J, K, U> {
312 fn div_assign(&mut self, tensor_rank_0: TensorRank0) {
313 self.iter_mut().for_each(|self_i| *self_i /= &tensor_rank_0);
314 }
315}
316
317impl<const D: usize, I, J, K, U> DivAssign<&TensorRank0> for TensorRank3<D, I, J, K, U> {
318 fn div_assign(&mut self, tensor_rank_0: &TensorRank0) {
319 self.iter_mut().for_each(|self_i| *self_i /= tensor_rank_0);
320 }
321}
322
323impl<const D: usize, I, J, K, U> Mul<TensorRank0> for TensorRank3<D, I, J, K, U> {
324 type Output = Self;
325 fn mul(mut self, tensor_rank_0: TensorRank0) -> Self::Output {
326 self *= &tensor_rank_0;
327 self
328 }
329}
330
331impl<const D: usize, I, J, K, U> Mul<&TensorRank0> for TensorRank3<D, I, J, K, U> {
332 type Output = Self;
333 fn mul(mut self, tensor_rank_0: &TensorRank0) -> Self::Output {
334 self *= tensor_rank_0;
335 self
336 }
337}
338
339impl<const D: usize, I, J, K, U> Mul<TensorRank0> for &TensorRank3<D, I, J, K, U> {
340 type Output = TensorRank3<D, I, J, K, U>;
341 fn mul(self, tensor_rank_0: TensorRank0) -> Self::Output {
342 self.iter().map(|self_i| self_i * tensor_rank_0).collect()
343 }
344}
345
346impl<const D: usize, I, J, K, U> Mul<&TensorRank0> for &TensorRank3<D, I, J, K, U> {
347 type Output = TensorRank3<D, I, J, K, U>;
348 fn mul(self, tensor_rank_0: &TensorRank0) -> Self::Output {
349 self.iter().map(|self_i| self_i * tensor_rank_0).collect()
350 }
351}
352
353impl<const D: usize, I, J, K, U> MulAssign<TensorRank0> for TensorRank3<D, I, J, K, U> {
354 fn mul_assign(&mut self, tensor_rank_0: TensorRank0) {
355 self.iter_mut().for_each(|self_i| *self_i *= &tensor_rank_0);
356 }
357}
358
359impl<const D: usize, I, J, K, U> MulAssign<&TensorRank0> for TensorRank3<D, I, J, K, U> {
360 fn mul_assign(&mut self, tensor_rank_0: &TensorRank0) {
361 self.iter_mut().for_each(|self_i| *self_i *= tensor_rank_0);
362 }
363}
364
365impl<const D: usize, I, J, K, U> Add for TensorRank3<D, I, J, K, U> {
366 type Output = Self;
367 fn add(mut self, tensor_rank_3: Self) -> Self::Output {
368 self += tensor_rank_3;
369 self
370 }
371}
372
373impl<const D: usize, I, J, K, U> Add<&Self> for TensorRank3<D, I, J, K, U> {
374 type Output = Self;
375 fn add(mut self, tensor_rank_3: &Self) -> Self::Output {
376 self += tensor_rank_3;
377 self
378 }
379}
380
381impl<const D: usize, I, J, K, U> Add<TensorRank3<D, I, J, K, U>> for &TensorRank3<D, I, J, K, U> {
382 type Output = TensorRank3<D, I, J, K, U>;
383 fn add(self, mut tensor_rank_3: TensorRank3<D, I, J, K, U>) -> Self::Output {
384 tensor_rank_3 += self;
385 tensor_rank_3
386 }
387}
388
389impl<const D: usize, I, J, K, U> AddAssign for TensorRank3<D, I, J, K, U> {
390 fn add_assign(&mut self, tensor_rank_3: Self) {
391 self.canonical_mut()
392 .add_assign_core(tensor_rank_3.into_canonical());
393 }
394}
395
396impl<const D: usize, I, J, K, U> AddAssign<&Self> for TensorRank3<D, I, J, K, U> {
397 fn add_assign(&mut self, tensor_rank_3: &Self) {
398 self.canonical_mut()
399 .add_assign_ref_core(tensor_rank_3.canonical());
400 }
401}
402
403impl<const D: usize, I, J, K, U> Sub for TensorRank3<D, I, J, K, U> {
404 type Output = Self;
405 fn sub(mut self, tensor_rank_3: Self) -> Self::Output {
406 self -= tensor_rank_3;
407 self
408 }
409}
410
411impl<const D: usize, I, J, K, U> Sub<&Self> for TensorRank3<D, I, J, K, U> {
412 type Output = Self;
413 fn sub(mut self, tensor_rank_3: &Self) -> Self::Output {
414 self -= tensor_rank_3;
415 self
416 }
417}
418
419impl<const D: usize, I, J, K, U> Sub for &TensorRank3<D, I, J, K, U> {
420 type Output = TensorRank3<D, I, J, K, U>;
421 fn sub(self, tensor_rank_3: Self) -> Self::Output {
422 tensor_rank_3
423 .iter()
424 .zip(self.iter())
425 .map(|(tensor_rank_3_i, self_i)| self_i - tensor_rank_3_i)
426 .collect()
427 }
428}
429
430impl<const D: usize, I, J, K, U> SubAssign for TensorRank3<D, I, J, K, U> {
431 fn sub_assign(&mut self, tensor_rank_3: Self) {
432 self.canonical_mut()
433 .sub_assign_core(tensor_rank_3.into_canonical());
434 }
435}
436
437impl<const D: usize, I, J, K, U> SubAssign<&Self> for TensorRank3<D, I, J, K, U> {
438 fn sub_assign(&mut self, tensor_rank_3: &Self) {
439 self.canonical_mut()
440 .sub_assign_ref_core(tensor_rank_3.canonical());
441 }
442}