1use std::cmp::Ordering;
4use std::ops::Range;
5use rug::{Integer, Rational};
6use super::{SignedSqrt, Wigner3jm, Wigner6j, Wigner9j, Wigner12jSecond};
7
8#[inline]
9pub fn sort2<T: Ord>(a: T, b: T) -> (T, T) {
10 if b < a {
11 (b, a)
12 } else {
13 (a, b)
14 }
15}
16
17#[inline]
18pub fn sort3<T: Ord>(a: T, b: T, c: T) -> (T, T, T) {
19 let (a, b) = sort2(a, b);
20 if c < a {
21 (c, a, b)
22 } else if c < b {
23 (a, c, b)
24 } else {
25 (a, b, c)
26 }
27}
28
29#[inline]
30pub fn sort4<T: Ord>(a: T, b: T, c: T, d: T) -> (T, T, T, T) {
31 let (a, b) = sort2(a, b);
32 let (c, d) = sort2(c, d);
33 if c < a {
34 if d < a {
35 (c, d, a, b)
36 } else if d < b {
37 (c, a, d, b)
38 } else {
39 (c, a, b, d)
40 }
41 } else if c < b {
42 if d < b {
43 (a, c, d, b)
44 } else {
45 (a, c, b, d)
46 }
47 } else {
48 (a, b, c, d)
49 }
50}
51
52#[inline]
60pub fn ordering_to_i32(ordering: Ordering) -> i32 {
61 match ordering {
62 Ordering::Less => -1,
63 Ordering::Equal => 0,
64 Ordering::Greater => 1,
65 }
66}
67
68#[inline]
70pub fn binomial(n: i32, k: i32) -> Integer {
71 Integer::from(n).binomial(k as u32)
72}
73
74#[inline]
76pub fn falling_factorial(n: i32, k: i32) -> Integer {
77 let mut r = Integer::from(1);
78 for i in n - k .. n {
79 r *= Integer::from(i + 1);
80 }
81 r
82}
83
84#[inline]
86pub fn factorial(n: i32) -> Integer {
87 Integer::factorial(n as u32).into()
88}
89
90#[inline]
91pub fn phase(phi: i32) -> i32 {
92 if phi % 2 == 0 {
93 1
94 } else {
95 -1
96 }
97}
98
99#[inline]
101pub fn triangle_condition(tj1: i32, tj2: i32, tj3: i32) -> bool {
102 let d = tj1 + tj2 - tj3;
103 d >= 0 && d % 2 == 0 && tj3 - (tj1 - tj2).abs() >= 0
104}
105
106pub fn wigner_3jm_raw_c(this: Wigner3jm) -> SignedSqrt {
108 let Wigner3jm { tj1, tm1, tj2, tm2, tj3, tm3 } = this;
109 let jmr1 = (tj1 + tm1) % 2;
110 let jmr2 = (tj2 + tm2) % 2;
111 if
112 tm1 + tm2 + tm3 == 0 &&
113 tm1.abs() <= tj1 &&
114 tm2.abs() <= tj2 &&
115 tm3.abs() <= tj3 &&
116 jmr1 == 0 &&
117 jmr2 == 0 &&
118 triangle_condition(tj1, tj2, tj3)
119 {
120 wigner_3jm_raw(this)
121 } else {
122 Default::default()
123 }
124}
125
126pub fn wigner_3jm_raw(this: Wigner3jm) -> SignedSqrt {
129 let Wigner3jm { tj1, tm1, tj2, tm2, tj3, tm3 } = this;
130 let jjj1 = (tj1 - tj2 + tj3) / 2;
131 let jjj2 = (tj2 - tj3 + tj1) / 2;
132 let jjj3 = (tj3 - tj1 + tj2) / 2;
133 let jjj = (tj1 + tj2 + tj3) / 2 + 1;
134 let jm1 = (tj1 + tm1) / 2;
135 let jm2 = (tj2 + tm2) / 2;
136 let jsm1 = (tj1 - tm1) / 2;
137 let jm3 = (tj3 + tm3) / 2;
138 let kmin = sort3(0, tj1 - tj3 + tm2, tj2 - tj3 - tm1).2 / 2;
139 let kmax = sort3(jjj2, jsm1, jm2).0;
140 let z1 = Rational::from((
141 binomial(tj1, jjj1) * binomial(tj2, jjj2) * binomial(tj3, jjj3),
142 binomial(tj1, jm1) * binomial(tj2, jm2) * binomial(tj3, jm3),
143 )) * triangular_factor_raw(jjj, jjj1, jjj2, jjj3);
144 let z2 = if kmin > kmax {
145 Integer::default()
146 } else {
147 let c0 = Integer::from(phase(kmin))
148 * binomial(jjj2, kmin)
149 * binomial(jjj1, jsm1 - kmin)
150 * binomial(jjj3, jm2 - kmin);
151 let mut s = c0.clone();
152 let mut c = c0;
153 for k in kmin + 1 .. kmax + 1 {
154 c = -c
155 * Integer::from(jjj2 - k + 1) / Integer::from(k)
156 * Integer::from(jsm1 - k + 1) / Integer::from(jjj1 - (jsm1 - k))
157 * Integer::from(jm2 - k + 1) / Integer::from(jjj3 - (jm2 - k));
158 s += &c;
159 }
160 s
161 };
162 SignedSqrt::new(z2, z1)
163}
164
165pub fn wigner_6j_raw(this: Wigner6j) -> SignedSqrt {
167 let Wigner6j { tj1, tj2, tj3, tj4, tj5, tj6 } = this;
168 let z1 =
169 triangular_factor(tj1, tj5, tj6)
170 * triangular_factor(tj4, tj2, tj6)
171 * triangular_factor(tj4, tj5, tj3)
172 / triangular_factor(tj1, tj2, tj3);
173 let z2 = tetrahedral_sum(tj1, tj5, tj6, tj4, tj2, tj3);
174 SignedSqrt::new(z2, z1)
175}
176
177pub fn wigner_9j_raw(this: Wigner9j) -> SignedSqrt {
179 let Wigner9j { tj1, tj2, tj3, tj4, tj5, tj6, tj7, tj8, tj9 } = this;
180 let tkmin = sort3(
181 (tj8 - tj4).abs(),
182 (tj2 - tj6).abs(),
183 (tj1 - tj9).abs(),
184 ).2;
185 let tkmax = sort3(
186 tj8 + tj4,
187 tj2 + tj6,
188 tj1 + tj9,
189 ).0;
190 let z2 = (0 .. (tkmax - tkmin) / 2 + 1).map(|i| {
191 let tk = tkmin + i * 2;
192 Integer::from(phase(tk) * (tk + 1))
193 * tetrahedral_sum(tj1, tj2, tj3, tj6, tj9, tk)
194 * tetrahedral_sum(tj6, tj4, tj5, tj8, tj2, tk)
195 * tetrahedral_sum(tj8, tj9, tj7, tj1, tj4, tk)
196 }).sum();
197 let z1 =
198 triangular_factor(tj1, tj2, tj3) *
199 triangular_factor(tj4, tj5, tj6) *
200 triangular_factor(tj7, tj8, tj9) *
201 triangular_factor(tj1, tj4, tj7) *
202 triangular_factor(tj2, tj5, tj8) *
203 triangular_factor(tj3, tj6, tj9);
204 SignedSqrt::new(z2, z1)
205}
206
207pub fn wigner_12j_second_raw(this: Wigner12jSecond) -> SignedSqrt {
209 let Wigner12jSecond { tj1, tj2, tj3, tj4, tj5, tj6, tj7, tj8, tj9, tj10, tj11, tj12 } = this;
210 let tkmin = sort4(
211 (tj1 - tj3).abs(),
212 (tj2 - tj4).abs(),
213 (tj9 - tj10).abs(),
214 (tj11 - tj12).abs(),
215 ).2;
216 let tkmax = sort4(
217 tj1 + tj3,
218 tj2 + tj4,
219 tj9 + tj10,
220 tj11 + tj12,
221 ).0;
222
223 let z2: Integer = (0 .. (tkmax - tkmin) / 2 + 1).map(|i| {
224 let tk = tkmin + i * 2;
225 Integer::from(tk + 1)
226 * tetrahedral_sum(tj9, tj1, tj5, tj3, tj10, tk)
227 * tetrahedral_sum(tj3, tj12, tj6, tj11, tj1, tk)
228 * tetrahedral_sum(tj4, tj10, tj7, tj9, tj2, tk)
229 * tetrahedral_sum(tj11, tj2, tj7, tj4, tj12, tk)
230 }).sum();
231
232 let z1 =
233 triangular_factor(tj9, tj1, tj5)
234 * triangular_factor(tj3, tj10, tj5)
235 * triangular_factor(tj3, tj12, tj6)
236 * triangular_factor(tj11, tj1, tj6)
237 * triangular_factor(tj4, tj10, tj7)
238 * triangular_factor(tj9, tj2, tj7)
239 * triangular_factor(tj11, tj2, tj8)
240 * triangular_factor(tj4, tj12, tj8);
241
242 SignedSqrt::new(Integer::from(phase(tj5 - tj6 - tj7 + tj8)) * z2, z1)
243}
244
245
246#[inline]
254pub fn triangular_factor(tj1: i32, tj2: i32, tj3: i32) -> Rational {
255 let jjja = (tj3 - tj1 + tj2) / 2;
256 let jjjb = (tj1 - tj2 + tj3) / 2;
257 let jjjc = (tj2 - tj3 + tj1) / 2;
258 let jjj = (tj1 + tj2 + tj3) / 2 + 1;
259 triangular_factor_raw(jjj, jjja, jjjb, jjjc)
260}
261
262#[inline]
264pub fn triangular_factor_raw(jd: i32, ja: i32, jb: i32, jc: i32) -> Rational {
265 let (ju, jv, jw) = sort3(ja, jb, jc);
266 Rational::from((
267 factorial(ju) * factorial(jv),
268 falling_factorial(jd, jd - jw),
269 ))
270}
271
272pub fn tetrahedral_sum(
283 tja: i32,
284 tje: i32,
285 tjf: i32,
286 tjd: i32,
287 tjb: i32,
288 tjc: i32,
289) -> Integer
290{
291 let jjja = (tjc - tja + tjb) / 2;
292 let jjjb = (tja - tjb + tjc) / 2;
293 let jjjc = (tjb - tjc + tja) / 2;
294 let jabc = (tja + tjb + tjc) / 2;
295 let jaef = (tja + tje + tjf) / 2;
296 let jdbf = (tjd + tjb + tjf) / 2;
297 let jdec = (tjd + tje + tjc) / 2;
298 let kmin = *[jabc, jdec, jdbf, jaef].iter().max().unwrap();
299 let kmax = *[
300 tja + tjd + tjb + tje,
301 tjb + tje + tjc + tjf,
302 tja + tjd + tjc + tjf,
303 ].iter().max().unwrap() / 2;
304 (kmin .. kmax + 1).map(|k| {
305 Integer::from(phase(k))
306 * binomial(k + 1, k - jabc)
307 * binomial(jjja, k - jaef)
308 * binomial(jjjb, k - jdbf)
309 * binomial(jjjc, k - jdec)
310 }).sum()
311}
312
313#[inline]
314pub fn intersect_ranges(a: Range<i32>, b: Range<i32>) -> Range<i32> {
315 a.start.max(b.start) .. a.end.min(b.end)
316}
317
318pub struct Step<I> {
319 pub iter: I,
320 pub step: usize,
321}
322
323impl<I: Iterator> Iterator for Step<I> {
324 type Item = I::Item;
325 #[inline]
326 fn next(&mut self) -> Option<Self::Item> {
327 let item = self.iter.next();
328 if item.is_some() && self.step >= 2 {
329 self.iter.nth(self.step - 2);
330 }
331 item
332 }
333}
334
335#[inline]
336pub fn get_triangular_tjs(tj_max: i32, tj1: i32, tj2: i32) -> Step<Range<i32>> {
337 Step {
338 iter: (tj1 - tj2).abs() .. tj_max.min(tj1 + tj2) + 1,
339 step: 2,
340 }
341}
342
343#[inline]
344pub fn get_bitriangular_tjs(
345 tj_max: i32,
346 tj1: i32,
347 tj2: i32,
348 tj3: i32,
349 tj4: i32,
350) -> Step<Range<i32>>
351{
352 Step {
353 iter: if (tj1 + tj2 + tj3 + tj4) % 2 != 0 {
354 0 .. 0
355 } else {
356 intersect_ranges(
357 get_triangular_tjs(tj_max, tj1, tj2).iter,
358 get_triangular_tjs(tj_max, tj3, tj4).iter,
359 )
360 },
361 step: 2,
362 }
363}
364
365#[inline]
367pub fn get_tms(tj: i32) -> Step<Range<i32>> {
368 Step { iter: -tj .. tj + 1, step: 2 }
369}
370
371pub fn get_3tjms(
374 tj_max: i32,
375 callback: &mut dyn FnMut(Wigner3jm),
376) {
377 for tj1 in 0 .. tj_max + 1 {
378 for tj2 in 0 .. tj_max + 1 {
379 for tj3 in get_triangular_tjs(tj_max, tj1, tj2) {
380 for tm1 in get_tms(tj1) {
381 for tm2 in get_tms(tj2) {
382 let tm3 = -(tm1 + tm2);
383 if tm3.abs() > tj3 {
384 continue;
385 }
386 callback(Wigner3jm { tj1, tm1, tj2, tm2, tj3, tm3 });
387 }
388 }
389 }
390 }
391 }
392}
393
394pub fn get_6tjs(
397 tj_max: i32,
398 callback: &mut dyn FnMut(Wigner6j),
399) {
400 for tj1 in 0 .. tj_max + 1 {
401 for tj2 in 0 .. tj_max + 1 {
402 for tj3 in get_triangular_tjs(tj_max, tj1, tj2) {
403 for tj4 in 0 .. tj_max + 1 {
404 for tj5 in get_triangular_tjs(tj_max, tj4, tj3) {
405 for tj6 in get_bitriangular_tjs(tj_max, tj1, tj5, tj4, tj2) {
406 callback(Wigner6j { tj1, tj2, tj3, tj4, tj5, tj6 });
407 }
408 }
409 }
410 }
411 }
412 }
413}
414
415pub fn get_9tjs(
418 tj_max: i32,
419 callback: &mut dyn FnMut(Wigner9j),
420) {
421 for tj1 in 0 .. tj_max + 1 {
422 for tj2 in 0 .. tj_max + 1 {
423 for tj3 in get_triangular_tjs(tj_max, tj1, tj2) {
424 for tj4 in 0 .. tj_max + 1 {
425 for tj5 in 0 .. tj_max + 1 {
426 for tj6 in get_triangular_tjs(tj_max, tj4, tj5) {
427 for tj7 in get_triangular_tjs(tj_max, tj1, tj4) {
428 for tj8 in get_triangular_tjs(tj_max, tj2, tj5) {
429 for tj9 in get_bitriangular_tjs(tj_max, tj7, tj8, tj3, tj6) {
430 callback(Wigner9j { tj1, tj2, tj3, tj4, tj5, tj6, tj7, tj8, tj9 });
431 }
432 }
433 }
434 }
435 }
436 }
437 }
438 }
439 }
440}
441
442pub fn get_12tjs_second(
445 tj_max: i32,
446 callback: &mut dyn FnMut(Wigner12jSecond),
447) {
448 for tj1 in 0 .. tj_max + 1 {
449 for tj2 in 0 .. tj_max + 1 {
450 for tj3 in 0 .. tj_max + 1 {
451 for tj5 in 0 .. tj_max + 1 {
452 for tj6 in 0 .. tj_max + 1 {
453 for tj9 in get_triangular_tjs(tj_max, tj1, tj5) {
454 for tj10 in get_triangular_tjs(tj_max, tj3, tj5) {
455 for tj11 in get_triangular_tjs(tj_max, tj1, tj6) {
456 for tj12 in get_triangular_tjs(tj_max, tj3, tj6) {
457 for tj7 in get_triangular_tjs(tj_max, tj2, tj9) {
458 for tj8 in get_triangular_tjs(tj_max, tj2, tj11) {
459 for tj4 in get_bitriangular_tjs(tj_max, tj7, tj10, tj8, tj12) {
460 callback(Wigner12jSecond { tj1, tj2, tj3, tj4, tj5, tj6, tj7, tj8, tj9, tj10, tj11, tj12 });
461 }
462 }
463 }
464 }
465 }
466 }
467 }
468 }
469 }
470 }
471 }
472 }
473}