# WignerFamilies

This package implements methods described in Luscombe and Luban 1998, based on the work of Schulten and Gordon 1961, for generating families of Wigner 3j and 6j symbols by recurrence relation. These exact methods are orders of magnitude more efficient than strategies like prime factorization for problems which require every non-trivial symbol in a family, and really shine for large quantum numbers. WignerFamilies.jl is thread-safe and **very fast**, beating the standard Fortran routine DRC3JJ from SLATEC by a factor of 2-4 (see notebook).

## Installation

```
using Pkg
Pkg.add("WignerFamilies")
```

## Usage

WignerFamilies.jl currently computes the nontrivial 3j symbols over `j`

with the other
quantum numbers fixed, in the family of symbols,

It exposes `wigner3j_f(j₂, j₃, m₂, m₃)`

which returns a simple wrapper around a vector of
the type`WignerSymbolVector`

. This vector contains the computed symbols, indexed by the
quantum number `j`

. The type supports
half-integer quantum numbers as indices.

```
using WignerFamilies
# wigner3j for all j fixing j₂=100, j₃=60, m₂=70, m₃=-55, m₁=-m₂-m₃
w3j = wigner3j_f(100, 60, 70, -55)
js = collect(eachindex(w3j)) # indices are the quantum numbers
plot(js, w3j.symbols) # you can get the underlying array with w3j.symbols
```

This generates the symbols in Figure 1 of Luscombe and Luban 1998.

## Advanced Use

One can compute symbols in a fully non-allocating way by using the mutating `wigner3j_f!`

. This requires
one to initialize a `WignerF`

struct describing the problem, put a wrapper around the piece of memory
you want to deposit the symbols using WignerSymbolVector, and then calling the mutating method.

```
j₂, j₃, m₂, m₃ = 100, 100, -2, 2
w = WignerF(Float64, j₂, j₃, m₂, m₃)
buffer = zeros(Float64, length(w.nₘᵢₙ:w.nₘₐₓ))
w3j = WignerSymbolVector(buffer, w.nₘᵢₙ:w.nₘₐₓ)
WignerFamilies.wigner3j_f!(w, w3j)
```

This is the best way to get symbols if you're using them in a tight loop, since allocations really hurt in those cases. Typically you would preallocate a buffer and then give this package a `view`

into it.

```
using BenchmarkTools
@btime WignerFamilies.wigner3j_f!(w, w3j)
```

```
1.660 μs (0 allocations: 0 bytes)
```