mirror of
https://github.com/tgorordo/WignerSymbols.jl.git
synced 2026-06-13 02:02:14 -07:00
3j and 6j working and tested
This commit is contained in:
parent
b9eb46d5cd
commit
56b02ebcf2
3 changed files with 137 additions and 20 deletions
|
|
@ -10,10 +10,10 @@ clebschgordan(j₁, m₁, j₂, m₂, j₃, m₃ = m₁+m₂) = clebschgordan(Fl
|
|||
function clebschgordan(T::Type{<:AbstractFloat}, j₁, m₁, j₂, m₂, j₃, m₃ = m₁+m₂)
|
||||
s = wigner3j(T, j₁, j₂, j₃, m₁, m₂, -m₃)
|
||||
iszero(s) && return s
|
||||
if isodd(j₁ - j₂ + m₃)
|
||||
if isodd(convert(Int,j₁ - j₂ + m₃))
|
||||
s *= -one(s)
|
||||
end
|
||||
s /= sqrt(convert(T, j₃+j₃+1))
|
||||
s *= sqrt(convert(T, j₃+j₃+one(j₃)))
|
||||
return s
|
||||
end
|
||||
|
||||
|
|
@ -34,8 +34,8 @@ function wigner3j(T::Type{<:AbstractFloat}, j₁, j₂, j₃, m₁, m₂, m₃ =
|
|||
β₂ = convert(Int, j₁ - m₁ )
|
||||
β₃ = convert(Int, j₂ + m₂ )
|
||||
|
||||
# extra sign in definition
|
||||
sgn = isodd(j₁ - j₃ - m₃) ? -sgn : sgn
|
||||
# extra sign in definition: α₁ - α₂ = j₁ + m₂ - j₂ + m₁ = j₁ - j₂ + m₃
|
||||
sgn = isodd(α₁ - α₂) ? -sgn : sgn
|
||||
|
||||
# dictionary lookup or compute
|
||||
if haskey(Wigner3j, (β₁, β₂, β₃, α₁, α₂))
|
||||
|
|
@ -44,7 +44,8 @@ function wigner3j(T::Type{<:AbstractFloat}, j₁, j₂, j₃, m₁, m₂, m₃ =
|
|||
s1 = Δ²(j₁, j₂, j₃)
|
||||
s2 = prod(map(primefactorial, (β₂, β₁ - α₁, β₁ - α₂, β₃, β₃ - α₁, β₂ - α₂)))
|
||||
|
||||
snum, rnum = splitsquare(s1.num * s2)
|
||||
|
||||
snum, rnum = splitsquare(s1.num*s2)
|
||||
sden, rden = splitsquare(s1.den)
|
||||
s = convert(BigInt, snum) // convert(BigInt, sden)
|
||||
r = convert(BigInt, rnum) // convert(BigInt, rden)
|
||||
|
|
@ -118,6 +119,7 @@ function δ(j₁, j₂, j₃)
|
|||
end
|
||||
|
||||
# triangle coefficient
|
||||
Δ(j₁, j₂, j₃) = Δ(Float64, j₁, j₂, j₃)
|
||||
function Δ(T::Type{<:AbstractFloat}, j₁, j₂, j₃)
|
||||
if !δ(j₁, j₂, j₃)
|
||||
throw(DomainError())
|
||||
|
|
@ -139,7 +141,7 @@ end
|
|||
|
||||
# reorder parameters determining the 3j symbol to canonical order:
|
||||
# j₁ >= j₂ >= j₃ and m₁ >= 0 or m₁ == 0 && m₂ >= 0
|
||||
function reorder3j(j₁, j₂, j₃, m₁, m₂, m₃, sign = one(UInt8))
|
||||
function reorder3j(j₁, j₂, j₃, m₁, m₂, m₃, sign = one(Int8))
|
||||
if j₁ < j₂
|
||||
return reorder3j(j₂, j₁, j₃, m₂, m₁, m₃, -sign)
|
||||
elseif j₂ < j₃
|
||||
|
|
@ -150,7 +152,7 @@ function reorder3j(j₁, j₂, j₃, m₁, m₂, m₃, sign = one(UInt8))
|
|||
return reorder3j(j₁, j₂, j₃, -m₁, -m₂, -m₃, -sign)
|
||||
else
|
||||
# sign doesn't matter if total J=j₁ + j₂ + j₃ is even
|
||||
if iseven(j₁ + j₂ + j₃)
|
||||
if iseven(convert(UInt,j₁ + j₂ + j₃))
|
||||
sign = one(sign)
|
||||
end
|
||||
return (j₁, j₂, j₃, m₁, m₂, m₃, sign)
|
||||
|
|
@ -183,14 +185,14 @@ function compute3jseries(β₁, β₂, β₃, α₁, α₂)
|
|||
nums = Vector{T}(length(krange))
|
||||
dens = Vector{T}(length(krange))
|
||||
for (i, k) in enumerate(krange)
|
||||
num = iseven(k) ? primefactorial(1) : -primefactorial(1)
|
||||
num = iseven(k) ? one(T) : -one(T)
|
||||
den = primefactorial(k)*primefactorial(k-α₁)*primefactorial(k-α₂)*
|
||||
primefactorial(β₁-k)*primefactorial(β₂-k)*primefactorial(β₃-k)
|
||||
nums[i], dens[i] = divgcd!(num, den)
|
||||
end
|
||||
den = commondenominator!(nums, dens)
|
||||
totalnum = sumlist!(nums)
|
||||
totalden = convert(BigInt, PrimeFactorization(den))
|
||||
totalden = convert(BigInt, den)
|
||||
return totalnum//totalden
|
||||
end
|
||||
|
||||
|
|
@ -209,7 +211,7 @@ function compute6jseries(β₁, β₂, β₃, α₁, α₂, α₃, α₄)
|
|||
end
|
||||
den = commondenominator!(nums, dens)
|
||||
totalnum = sumlist!(nums)
|
||||
totalden = convert(BigInt, PrimeFactorization(den))
|
||||
totalden = convert(BigInt, den)
|
||||
return totalnum//totalden
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -56,12 +56,9 @@ struct PrimeFactorization{T<:Unsigned} <: Integer
|
|||
end
|
||||
PrimeFactorization(powers::Vector{T}) where {T<:Unsigned} = PrimeFactorization{T}(powers, one(Int8))
|
||||
|
||||
Base.copy(a::PrimeFactorization) = PrimeFactorization(copy(a.powers), a.sign)
|
||||
Base.:(==)(a::P, b::P) where {P<:PrimeFactorization} = a.powers == b.powers && a.sign == b.sign
|
||||
|
||||
# define our own factor function, returning an instance of PrimeFactorization
|
||||
function primefactor(n::Integer)
|
||||
iszero(n) && return PrimeFactorization(UInt8[], zero(UInt8))
|
||||
iszero(n) && return PrimeFactorization(UInt8[], zero(Int8))
|
||||
sn = n < 0 ? -one(Int8) : one(Int8)
|
||||
n = abs(n)
|
||||
m = length(factortable)
|
||||
|
|
@ -104,7 +101,16 @@ function primefactorial(n::Integer)
|
|||
@inbounds return PrimeFactorization(copy(factorialtable[n+1]))
|
||||
end
|
||||
|
||||
# Conversion from PrimeFactorization to `BigInt` using `bigprime`
|
||||
# Methods for PrimeFactorization:
|
||||
Base.copy(a::PrimeFactorization) = PrimeFactorization(copy(a.powers), a.sign)
|
||||
|
||||
Base.one(::Type{PrimeFactorization{T}}) where {T<:Unsigned} = PrimeFactorization(Vector{T}())
|
||||
Base.zero(::Type{PrimeFactorization{T}}) where {T<:Unsigned} = PrimeFactorization(Vector{T}(), zero(Int8))
|
||||
|
||||
Base.promote_rule(P::Type{<:PrimeFactorization},::Type{<:Integer}) = P
|
||||
Base.promote_rule(P::Type{<:PrimeFactorization},::Type{BigInt}) = BigInt
|
||||
|
||||
Base.convert(P::Type{<:PrimeFactorization}, n::Integer) = convert(P, primefactor(n))
|
||||
function Base.convert(::Type{BigInt}, a::PrimeFactorization)
|
||||
A = big(a.sign)
|
||||
for (n, e) in enumerate(a.powers)
|
||||
|
|
@ -114,6 +120,24 @@ function Base.convert(::Type{BigInt}, a::PrimeFactorization)
|
|||
end
|
||||
return A
|
||||
end
|
||||
Base.convert(::Type{PrimeFactorization{T}}, a::PrimeFactorization{T}) where {T<:Unsigned} = a
|
||||
Base.convert(::Type{PrimeFactorization{T1}}, a::PrimeFactorization{T2}) where {T1<:Unsigned, T2<:Unsigned} = PrimeFactorization(map(T1, a.powers), a.sign)
|
||||
|
||||
Base.:(==)(a::PrimeFactorization, b::PrimeFactorization) = a.powers == b.powers && a.sign == b.sign
|
||||
function Base.:<(a::PrimeFactorization, b::PrimeFactorization)
|
||||
if a.sign != b.sign
|
||||
return a.sign < b.sign
|
||||
elseif a.sign < 0
|
||||
return <(-b, -a)
|
||||
else
|
||||
ag, bg = divgcd(a, b)
|
||||
if length(ag.powers) <= length(bg.powers) && all(k->ag.powers[k]<bg.powers[k], 1:length(ag.powers))
|
||||
return true
|
||||
else
|
||||
return convert(BigInt, ag) < convert(BigInt, bg)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Methods for PrimeFactorization: only fast multiplication, and lcm and gcd.
|
||||
# Addition and subtraction will require conversion to BigInt
|
||||
|
|
@ -181,15 +205,15 @@ end
|
|||
# given a list of numerators and denominators, compute the common denominator and
|
||||
# the rescaled numerator after putting all fractions at the same common denominator
|
||||
function commondenominator!(nums::Vector{P}, dens::Vector{P}) where {P<:PrimeFactorization}
|
||||
isempty(nums) && return one(P)
|
||||
# accumulate lcm of denominator
|
||||
den = copy(dens[1])
|
||||
den = PrimeFactorization(copy(dens[1].powers))
|
||||
for i = 2:length(dens)
|
||||
_vmax!(den.powers, dens[i].powers)
|
||||
end
|
||||
# rescale numerators
|
||||
for i = 1:length(nums)
|
||||
powers = _vsub!(_vadd!(nums[i].powers, den.powers), dens[i].powers)
|
||||
nums[i] = PrimeFactorization(powers, nums[i].sign)
|
||||
_vsub!(_vadd!(nums[i].powers, den.powers), dens[i].powers)
|
||||
end
|
||||
return den
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue