Package: wigners
Calculation of Wigner symbols and related constantsThis package computes Wigner 3j coefficients and Clebsch-Gordan coefficients in
pure Rust. The calculation is based on the prime factorization of the different
factorials involved in the coefficients, keeping the values in a rational root
form (sign * \sqrt{s / n}) for as long as possible. This idea for the
algorithm is described in:H. T. Johansson and C. Forssén, SIAM Journal on Scientific Compututing 38 (2016) 376-384This implementation takes a lot of inspiration from theWignerSymbolsJulia implementation
(and even started as a direct translation of it), many thanks to them! This
package is available under the same license as the Julia package.UsageFrom pythonpip install wignersAnd then call one of the exported function:importwignersw3j=wigners.wigner_3j(j1,j2,j3,m1,m2,m3)cg=wigners.clebsch_gordan(j1,m1,j2,m1,j3,m3)# full array of Clebsch-Gordan coefficients, computed in parallelcg_array=wigners.clebsch_gordan_array(ji,j2,j3)# we have an internal cache for recently computed CG coefficients, if you# need to clean it up you can use this functionwigners.clear_wigner_3j_cache()From rustAdd this crate to yourCargo.tomldependencies section:wigners="0.3"And then call one of the exported function:letw3j=wigners::wigner_3j(j1,j2,j3,m1,m2,m3);letcg=wigners::clebsch_gordan(j1,m1,j2,m1,j3,m3);wigners::clear_wigner_3j_cache();LimitationsOnly Wigner 3j symbols for full integers (no half-integers) are implemented,
since that's the only part I need for my own work.6j and 9j symbols can also be computed with this approach; and support for
half-integers should be feasible as well. I'm open to pull-request implementing
these!BenchmarksThis benchmark measure the time to compute all possible Wigner 3j symbols up to
a fixed maximal angular momentum; clearing up any cached values from previous
angular momentum before starting the loop. In pseudo code, the benchmark looks
like this:if cached_wigner_3j:
    clear_wigner_3j_cache()

# only measure the time taken by the loop
start = time.now()
for j1 in range(max_angular):
    for j2 in range(max_angular):
        for j3 in range(max_angular):
            for m1 in range(-j1, j1 + 1):
                for m2 in range(-j2, j2 + 1):
                    for m3 in range(-j3, j3 + 1):
                        w3j = wigner_3j(j1, j2, j3, m1, m2, m3)

elapsed = start - time.now()Here are the results on an Apple M1 Max (10 cores) CPU:angular momentumwigners (this)wigner-symbols v0.5WignerSymbols.jl v2.0wigxjpf v1.11sympy v1.1140.190 ms7.50 ms2.58 ms0.228 ms28.7 ms84.46 ms227 ms47.0 ms7.36 ms1.36 s1234.0 ms1.94 s434 ms66.2 ms23.1 s16156 ms9.34 s1.98 s333 ms/20531 ms/6.35 s1.21 s/A second set of benchmarks checks computing Wigner symbols for largej, with the
correspondingmvarying from -10 to 10, i.e. in pseudo code:if cached_wigner_3j:
    clear_wigner_3j_cache()

# only measure the time taken by the loop
start = time.now()
for m1 in range(-10, 10 + 1):
    for m2 in range(-10, 10 + 1):
        for m3 in range(-10, 10 + 1):
            w3j = wigner_3j(j1, j2, j3, m1, m2, m3)

elapsed = start - time.now()(j1, j2, j3)wigners (this)wigner-symbols v0.5WignerSymbols.jl v2.0wigxjpf v1.11sympy v1.11(300, 100, 250)38.7 ms16.5 ms32.9 ms7.60 ms2.31 sTo run the benchmarks yourself on your own machine, execute the following commands:cdbenchmarks
cargobench# this gives the results for wigners, wigner-symbols and wigxjpfpythonsympy-bench.py# this gives the results for sympyjuliawigner-symbol.jl# this gives the results for WignerSymbols.jlComparison towigner-symbolsThere is another Rust implementation of wigner symbols: thewigner-symbolscrate.wigner-symbolsalso implements 6j and 9j symbols, but it was not usable for my
case since it relies onrugfor arbitrary
precision integers and through it on theGMPlibrary. The
GMP library might be problematic for you for one of these reason:it is relatively slow (see the benchmarks above)it is distributed under LGPL (this crate is distributed under Apache/MIT);it is written in C and C++; and as such is hard to cross-compile or compile to WASM;it does not support the MSVC compiler on windows, only the GNU compilersAs you can see in the benchmarks above, this usage of GMP becomes an advantage
for large j, where the algorithm used in this crate does not scale as well.LicenseThis crate is distributed under both the MIT license and the Apache 2.0 license.