AngularMomentumAlgebra.OrbitalRadialMatrixElementType
OrbitalRadialMatrixElement(a,b)

Represents the radial overlap between the orbitals a and b in a N-body matrix element expansion. This is different from EnergyExpressions.OrbitalMatrixElement, which represents integration over all coordinates. An OrbitalRadialMatrixElement might result when integrating over the spin–angular degrees of freedom of a matrix element.

Examples

julia> AngularMomentumAlgebra.OrbitalRadialMatrixElement(so"1s₀α", RadialOperator(), so"2p₀α")
⟨1s₀α|r|2p₀α⟩ᵣ
AngularMomentumAlgebra.OrbitalRadialOverlapType
OrbitalRadialOverlap(a,b)

Represents the radial overlap between the orbitals a and b in a N-body matrix element expansion. This is different from EnergyExpressions.OrbitalOverlap, which represents integration over all coordinates. An OrbitalRadialOverlap might result when integrating over the spin–angular degrees of freedom of a matrix element. As an example, with spin-orbitals on the form

$$$\phi_{n\ell m_\ell s m_s}(\spatialspin) = \frac{P_{n\ell m_\ell s m_s}(r)}{r} Y^\ell_m(\theta,\phi) \chi_{m_s}(s), \quad \spatialspin = \{\vec{r},s\},$$$

in the spin-restricted case, we have

$$$\int\diff{r} \conj{P_{\textrm{1s}_0\alpha}}(r) P_{\textrm{1s}_0\beta}(r) = 1$$$

(provided $P$ is normalized) whereas integration over all coordinates (spatial and spin)

$$$\int\diff{\spatialspin} \conj{\phi_{\textrm{1s}_0\alpha}}(\spatialspin) \phi_{\textrm{1s}_0\beta}(\spatialspin) = 0$$$

by symmetry.

Examples

julia> AngularMomentumAlgebra.OrbitalRadialOverlap(so"1s₀α", so"1s₀β")
⟨1s₀α|1s₀β⟩ᵣ
AngularMomentumAlgebra.RadialGradientOperatorType
RadialGradientOperator(k)

This represents the matrix element of the radial component of the gradient operator:

$$$$$\tag{V13.2.23} \int_0^\infty\diff{r}r^2 \conj{\Psi}_{n'\ell'}(r) \left(\partial_r+\frac{k}{r}\right) \Psi_{n\ell}(r)$$$$$
AngularMomentumAlgebra.RadialOperatorType
RadialOperator()

This represents the matrix element of the radial component of the dipole operator:

$$$\expect{r} = \int_0^\infty\diff{r}r^2 \conj{\Psi}_{n'\ell'}(r) r \Psi_{n\ell}(r)$$$
AngularMomentumAlgebra.TensorOperatorType
TensorOperator{N}(T)

Create an NBodyOperator out of a tensor component (either a TensorComponent or a TensorScalarProduct, which implicitly only has one component, 0).

Example

julia> 𝐉 = TotalAngularMomentum()
𝐉̂⁽¹⁾

julia> 𝐉₀ = TensorComponent(𝐉, 0)
𝐉̂⁽¹⁾₀

julia> A = TensorOperator{1}(𝐉₀)
[𝐉̂⁽¹⁾₀]

julia> cfgs = scs"1s2"
1-element Vector{SpinConfiguration{SpinOrbital{Orbital{Int64}, Tuple{Int64, HalfIntegers.Half{Int64}}}}}:
1s₀α 1s₀β

julia> Matrix(A, cfgs)
1×1 SparseArrays.SparseMatrixCSC{NBodyMatrixElement, Int64} with 1 stored entry:
0.5⟨1s₀α|1s₀α⟩ - 0.5⟨1s₀β|1s₀β⟩
AngularMomentumAlgebra.TensorProductType
TensorProduct{K}(T, U)

A tensor of rank K formed from the product of the tensors T and U, according to

$$$$$\tag{V3.1.20} \tensor{X}^{(K)}_Q \equiv \{\tensor{T}^{(k_1)}\tensor{U}^{(k_2)}\}^{(K)}_Q \defd \tensor{T}^{(k_1)}_{q_1} \tensor{U}^{(k_2)}_{q_2} C_{k_1q_1k_2q_2}^{KQ}$$$$$
AngularMomentumAlgebra.TensorScalarProductType
TensorScalarProduct(T, U)

A tensor of rank 0 (and thus implicitly 0 projection) formed from the product of the tensors T and U (which have to have the same rank), according to

$$$$$\tag{V3.1.30,35} (\tensor{T}^{(k)} \cdot \tensor{U}^{(k)}) \defd (-)^k\angroot{k} \{\tensor{T}^{(k)} \tensor{U}^{(k)}\}^{(0)}_0 \equiv (-)^q \tensor{T}^{(k)}_{q} \tensor{U}^{(k)}_{-q}$$$$$
Base.MatrixMethod
Matrix(op::QuantumOperator,
spin_cfgs::Vector{<:Configuration{<:SpinOrbital}}[, overlaps])

Generate the energy-expression associated with the quantum operator op, in the basis of the spin-configurations spin_cfgs, with an optional set of orbital overlaps, specifying any desired non-orthogonalities. The energy expression is generated in a basis-agnostic way by EnergyExpressions.jl and each term is then integrated over the spin-angular coordinates using integrate_spinor.

AngularMomentumAlgebra.cartesian_tensor_componentMethod
cartesian_tensor_component(t::Tensor{1}, c)

This returns the Cartesian tensor component c (valid choices are :x, :y, or :z) of the rank-1 tensor t, as a linear combination of its "natural" TensorComponents 1, 0, and -1. The transform matrix is M(+1, 0, -1 ← x, y, z) given in Table 1.2 on p. 14 of Varshalovich (1988).

Examples

julia> cartesian_tensor_component(Gradient(), :x)
- 0.707107 𝛁̂⁽¹⁾₁ + 0.707107 𝛁̂⁽¹⁾₋₁
AngularMomentumAlgebra.couplingsMethod
couplings(j₁, m₁, j₂, m₂)

Return all j, m for which the Clebsch–Gordan coefficient ⟨j₁m₁ j₂m₂|jm⟩ is non-zero.

AngularMomentumAlgebra.couplingsMethod
couplings(tensor::Dipole, (n, ℓ))

Generate all quantum numbers n′ℓ′ for which ⟨n′ℓ′||::Dipole||nℓ⟩ does not vanish.

AngularMomentumAlgebra.couplingsMethod
couplings(tensor::Gradient, (n, ℓ))

Generate all quantum numbers n′ℓ′ for which ⟨n′ℓ′||::Gradient||nℓ⟩ does not vanish.

AngularMomentumAlgebra.couplingsMethod
couplings(tensor::OrbitalAngularMomentum, ℓ)

Generate all quantum numbers ℓ′ for which ⟨ℓ′||::OrbitalAngularMomentum||ℓ⟩ does not vanish.

AngularMomentumAlgebra.couplingsMethod
couplings(tensor::ReducedGradient, (n, ℓ))

Generate all quantum numbers n′ℓ′ for which ⟨n′ℓ′||::ReducedGradient||nℓ⟩ does not vanish.

AngularMomentumAlgebra.couplingsMethod
couplings(tensor::SpinAngularMomentum, s)

Generate all quantum numbers s′ for which ⟨s′||::SpinAngularMomentum||s⟩ does not vanish.

AngularMomentumAlgebra.couplingsMethod
couplings(tensor::TotalAngularMomentum, (ℓ, s, J))

Generate all quantum numbers ℓ′s′J′ for which ⟨ℓ′s′J′||::TotalAngularMomentum||ℓsJ⟩ does not vanish.

AngularMomentumAlgebra.couplingsMethod
couplings(tensor::CoulombTensor{k}, (n, ℓ)) where k

Generate all quantum numbers n′ℓ′ for which ⟨n′ℓ′||::CoulombTensor{k}||nℓ⟩ does not vanish.

AngularMomentumAlgebra.couplingsMethod
couplings(tensor::SphericalTensor{k}, ℓ) where k

Generate all quantum numbers ℓ′ for which ⟨ℓ′||::SphericalTensor{k}||ℓ⟩ does not vanish.

AngularMomentumAlgebra.generate_couplingsMethod
generate_copulings(TensorType, selection_rules, selection_rules_linenum)

Generate a function that given the quantum numbers γj generates lists of all permissible γj′ for which the reduced matrix element ⟨γj′||::TensorType||γj⟩ does not vanish. This is deduced from the selection_rules, given at line number selection_rules_linenum.

AngularMomentumAlgebra.generate_iszeroMethod
generate_iszero(TensorType, selection_rules, selection_rules_linenum)

Generate a function for testing if the matrix element of TensorType vanishes, given a set a quantum number deduced from selection_rules, given at line number selection_rules_linenum.

AngularMomentumAlgebra.generate_rmeMethod
generate_rme(TensorType, selection_rules, doc, rme, rme_linenum)

Generate a function for computing the reduced matrix element of TensorType, given a set a quantum number deduced from selection_rules, along with the docstring and the definition rme, given at line number rme_linenum.

AngularMomentumAlgebra.identify_quantum_numbersMethod
identify_quantum_numbers(selection_rules)

Given the block of selection rules, identify the quantum numbers pertaining to the tensor under consideration. It is assumed that the left-hand side consists of a primed quantum number only, which is specified to be equal to an expression or belonging to a set/interval.

AngularMomentumAlgebra.integrate_spinorMethod
integrate_spinor(me)

Perform the spin-angular integration of the matrix element me, leaving only a radial integral multiplied by a spin-angular coefficient. The spin-angular integral is dependent on the specific combination of spin-orbitals and the operator (expressed as a tensor); the default implementation is to leave me as-is, corresponding to a spin-angular integral of unity.

AngularMomentumAlgebra.integrate_spinorMethod
integrate_spinor(integral::NBodyTermFactor)

Dummy method that returns integral unchanged, used for all NBodyTermFactors that are not to be multipole-expanded.

AngularMomentumAlgebra.integrate_spinorMethod
integrate_spinor(me::OrbitalMatrixElement{2,<:Any,<:CoulombInteraction,<:Any})

Perform the spin-angular integration of the two-electron matrix element me, by first multipole-expanding the Coulomb interaction and then integrating all the resulting terms over the spin-angular coordinates (see multipole_expand).

AngularMomentumAlgebra.many_electron_scalar_productMethod
many_electron_scalar_product(𝐓::Tensor{k}, 𝐔::Tensor{k}=𝐓) where k

Create the total tensor acting on a many-electron state according to

\begin{aligned} (\tensor{T}^{(k)} \cdot \tensor{U}^{(k)}) &= \sum_{i,j} [\tensor{t}^{(k)}(i) \cdot \tensor{u}^{(k)}(j)] \\ &\equiv \sum_i [\tensor{t}^{(k)}(i) \cdot \tensor{u}^{(k)}(i)] + \sum_{i\ne j} 2[\tensor{t}^{(k)}(i) \cdot \tensor{u}^{(k)}(j)], \end{aligned} \tag{H11-32*}

where $\tensor{t}^{(k)}(i)$ and $\tensor{u}^{(k)}(j)$ act only on electron $i$ and $j$, respectively [cf. John E. Harriman: Theoretical Foundations of Electron Spin Resonance (1978); note that Harriman uses another normalization of the ladder operators compared to ours: Eq. (V3.1.1), which explains why his Eq. (H11-32) is missing a factor of $2$].

Examples

julia> 𝐉 = TotalAngularMomentum()
𝐉̂⁽¹⁾

julia> A = many_electron_scalar_product(𝐉)
[𝐉̂⁽¹⁾]² + 2.0[𝐉̂⁽¹⁾(1)⋅𝐉̂⁽¹⁾(2)]

julia> 𝐋 = OrbitalAngularMomentum()
𝐋̂⁽¹⁾

julia> 𝐒 = SpinAngularMomentum()
𝐒̂⁽¹⁾

julia> B = many_electron_scalar_product(𝐋, 𝐒)
[𝐋̂⁽¹⁾⋅𝐒̂⁽¹⁾] + 2.0[𝐋̂⁽¹⁾(1)⋅𝐒̂⁽¹⁾(2)]

julia> cfgs = rscs"1s2"
1-element Vector{SpinConfiguration{SpinOrbital{RelativisticOrbital{Int64}, Tuple{HalfIntegers.Half{Int64}}}}}:
1s(-1/2) 1s(1/2)

julia> Matrix(A, cfgs)
1×1 SparseArrays.SparseMatrixCSC{NBodyMatrixElement, Int64} with 1 stored entry:
0.75⟨1s(-1/2)|1s(-1/2)⟩ + 0.75⟨1s(1/2)|1s(1/2)⟩ - ⟨1s(-1/2)|1s(1/2)⟩⟨1s(1/2)|1s(-1/2)⟩ - 0.5⟨1s(-1/2)|1s(-1/2)⟩⟨1s(1/2)|1s(1/2)⟩

julia> Matrix(B, cfgs)
1×1 SparseArrays.SparseMatrixCSC{NBodyMatrixElement, Int64} with 0 stored entries:
⋅
AngularMomentumAlgebra.matrix_elementMethod
matrix_element((γj₁′, m₁′), (γj₂′, m₂′), 𝐓ᵏq, (γj₁, m₁), (γj₂, m₂))

Compute the matrix element of the irreducible tensor 𝐓ᵏq acting on coordinates 1 and 2, by first coupling γj₁′m₁′γj₂′m₂′ and γj₁m₁γj₂m₂ to all permissible j′m′ and jm, respectively, according to

\begin{aligned} &\matrixel{γ_1'j_1'm_1';γ_2'j_2'm_2'}{\tensor{P}^{(k)}_q(1,2)}{γ_1j_1m_1;γ_2j_2m_2} \\ =& (-)^{2k} \frac{1}{\angroot{j'}} \sum_{jmj'm'} C_{j_1m_1;j_2m_2}^{jm} C_{j_1'm_1';j_2'm_2'}^{j'm'} C_{jm;kq}^{j'm'}\\ &\times \redmatrixel{γ_1'j_1'γ_2'j_2'j'}{\tensor{P}^{(k)}(1,2)}{γ_1j_1γ_2j_2j} \\ \equiv& \sum_{jmj'm'} C_{j_1m_1;j_2m_2}^{jm} C_{j_1'm_1';j_2'm_2'}^{j'm'} \matrixel{γ_1'j_1'γ_2'j_2'j'm'}{\tensor{P}^{(k)}(1,2)}{γ_1j_1γ_2j_2jm} \end{aligned} \tag{V13.1.23} \label{eqn:coupling}

The non-vanishing terms of the sum are found using AngularMomentumAlgebra.couplings.

Examples

julia> 𝐉 = TotalAngularMomentum()
𝐉̂⁽¹⁾

julia> 𝐉₀ = TensorComponent(𝐉, 0)
𝐉̂⁽¹⁾₀

julia> matrix_element((1,1), (half(1),half(1)),
𝐉₀, (1,1), (half(1), half(1)))
1.5

julia> matrix_element((1,-1), (half(1),half(1)),
𝐉₀, (1,-1), (half(1), half(1)))
-0.4999999999999999

julia> 𝐉₁ = TensorComponent(𝐉, 1)
𝐉̂⁽¹⁾₁

julia> matrix_element((1,1), (half(1),half(1)),
𝐉₁, (1,0), (half(1), half(1)))
-1.0

julia> 𝐉² = 𝐉⋅𝐉
(𝐉̂⁽¹⁾⋅𝐉̂⁽¹⁾)

julia> matrix_element((1,1), (half(1),half(1)),
𝐉², (1,1), (half(1), half(1)))
3.7500000000000004

julia> half(3)*(half(3)+1) # J(J+1)
3.75
AngularMomentumAlgebra.matrix_elementMethod
matrix_element(system,
a::SpinOrbital{<:Orbital},
𝐓ᵏq::TensorComponent,
b::SpinOrbital{<:Orbital})

The matrix element of a tensor acting on system, which is a subsystem, evaluated in the basis uncoupled spin-orbitals, is given by

\begin{aligned} &\matrixel{n_1'j_1'm_1';n_2'j_2'm_2'}{\tensor{T}^{(k)}_q(1)}{n_1j_1m_1;n_2j_2m_2} \\ =& \delta_{n_2'n_2}\delta_{j_2'j_2}\delta_{m_2'm_2} \\ &\matrixel{n_1'j_1'm_1'}{\tensor{T}^{(k)}_q(1)}{n_1j_1m_1}. \end{aligned} \label{eqn:tensor-matrix-element-subsystem-uncoupled} \tag{V13.1.39}
AngularMomentumAlgebra.matrix_elementMethod
matrix_element(system,
a::SpinOrbital{<:RelativisticOrbital},
𝐓ᵏq::TensorComponent,
b::SpinOrbital{<:RelativisticOrbital})

The matrix element of a tensor acting on system, which is a subsystem, evaluated in the basis coupled spin-orbitals, needs to be computed via the uncoupling formula $\eqref{eqn:uncoupling}$.

AngularMomentumAlgebra.matrix_elementMethod
matrix_element((γj′, m′), X::TensorScalarProduct, (γj, m))

Calculate the matrix element of a scalar product tensor according to:

\begin{aligned} \matrixel{n'j'm'}{[\tensor{P}^{(k)}\cdot\tensor{Q}^{(k)}]}{njm} =& \delta_{jj'}\delta_{mm'} \frac{1}{\angroot{j}^2}\\ &\times\sum_{n_1j_1} (-)^{-j+j_1} \redmatrixel{n'j}{\tensor{P}^{(k)}}{n_1j_1} \redmatrixel{n_1j_1}{\tensor{Q}^{(k)}}{nj} \end{aligned} \label{eqn:scalar-product-tensor-matrix-element} \tag{V13.1.11}

The permissible values of $n_1j_1$ in the summation are found using AngularMomentumAlgebra.couplings; it is assumed that the summation only consists of a finite amount of terms and that

$$$\redmatrixel{n'j}{\tensor{P}^{(k)}}{n_1j_1}\neq0 \iff \redmatrixel{n_1j_1}{\tensor{P}^{(k)}}{n'j}\neq0,$$$

i.e. that $\tensor{P}^{(k)}$ is (skew)symmetric.

Examples

julia> 𝐒 = SpinAngularMomentum()
𝐒̂⁽¹⁾

julia> 𝐒² = 𝐒⋅𝐒
(𝐒̂⁽¹⁾⋅𝐒̂⁽¹⁾)

julia> matrix_element((half(1), half(1)),
𝐒², (half(1), half(1)))
0.7499999999999998

julia> half(1)*(half(1)+1) # S(S+1)
0.75

julia> 𝐉 = TotalAngularMomentum()
𝐉̂⁽¹⁾

julia> 𝐉² = 𝐉⋅𝐉
(𝐉̂⁽¹⁾⋅𝐉̂⁽¹⁾)

julia> matrix_element(((1, half(1), half(3)), half(3)),
𝐉², ((1, half(1), half(3)), half(3)))
3.7500000000000004

julia> half(3)*(half(3)+1) # J(J+1)
3.75
AngularMomentumAlgebra.matrix_elementMethod
matrix_element((s₁,s₂)::Tuple{<:System,<:System},
(a,b)::Tuple{<:SpinOrbital{<:Orbital},
<:SpinOrbital{<:Orbital}},
X::TensorScalarProduct,
(c,d)::Tuple{<:SpinOrbital{<:Orbital},
<:SpinOrbital{<:Orbital}})

The matrix element of a tensor scalar product, where the factors act on the orbital pairs a,c and b,d, respectively, evaluated in the basis of uncoupled spin-orbitals, is computed using $\eqref{eqn:scalar-product-tensor-matrix-element-diff-coords-uncoupled}$.

AngularMomentumAlgebra.matrix_elementMethod
matrix_element((s₁,s₂)::Tuple{<:System,<:System},
(a,b)::Tuple{<:SpinOrbital{<:RelativisticOrbital},
<:SpinOrbital{<:RelativisticOrbital}},
X::TensorScalarProduct,
(c,d)::Tuple{<:SpinOrbital{<:RelativisticOrbital},
<:SpinOrbital{<:RelativisticOrbital}})

The matrix element of a tensor scalar product, where the factors act on the orbital pairs a,c and b,d, respectively, evaluated in the basis of coupled spin-orbitals, is computed using $\eqref{eqn:scalar-product-tensor-matrix-element-diff-coords-uncoupled}$ together with $\eqref{eqn:uncoupling}$ applied to each matrix element between single orbitals; the individual spin-orbitals couple $\ell$ and $s$ to form a total $j$, but they are not further coupled to e.g. a term.

AngularMomentumAlgebra.matrix_elementMethod
matrix_element((γj₁′, γj₂′, j′, m′), 𝐓ᵏq, (γj₁, γj₂, j, m))

Compute the matrix element of the tensor 𝐓ᵏq which acts on coordinate 1 only in the coupled basis, by employing the uncoupling formula

\begin{aligned} &\matrixel{γ_1'j_1'γ_2'j_2'j'm'}{\tensor{T}^{(k)}_q(1)}{γ_1j_1γ_2j_2jm}\\ =& \delta_{j_2'j_2}\delta_{γ_2'γ_2} (-)^{j+j_1'+j_2-k} \angroot{j} C_{jm;kq}^{j'm'}\\ &\times \wignersixj{j_1&j_2&j\\j'&k&j_1'} \redmatrixel{γ_1'j_1'}{\tensor{T}^{(k)}(1)}{γ_1j_1} \end{aligned} \tag{V13.1.40} \label{eqn:uncoupling}

Examples

julia> 𝐋₀ = TensorComponent(OrbitalAngularMomentum(), 0)
𝐋̂⁽¹⁾₀

julia> matrix_element((1, half(1), half(3), half(3)),
𝐋₀, (1, half(1), half(3), half(3)))
0.9999999999999999

julia> matrix_element((1, 1), 𝐋₀, (1, 1)) # For comparison
0.9999999999999999

julia> 𝐒₀ = TensorComponent(SpinAngularMomentum(), 0)
𝐒̂⁽¹⁾₀

julia> matrix_element((half(1), 1, half(3), half(3)),
𝐒₀, (half(1), 1, half(3), half(3)))
0.49999999999999994

julia> matrix_element((half(1),half(1)), 𝐒₀, (half(1),half(1)))
0.49999999999999994
AngularMomentumAlgebra.matrix_elementMethod
matrix_element((γj′, m′), Tᵏq::TensorComponent, (γj, m))

Calculate the matrix element ⟨γ′j′m′|Tᵏq|γjm⟩ via Wigner–Eckart's theorem:

\begin{aligned} \matrixel{\gamma'j'm'}{\tensor{T}^{(k)}_q}{\gamma jm} &\defd (-)^{2k} \frac{1}{\angroot{j'}} C_{jm;kq}^{j'm'} \redmatrixel{\gamma' j'}{\tensor{T}^{(k)}}{\gamma j} \\ &= (-)^{j'-m'} \begin{pmatrix} j'&k&j\\ -m'&q&m \end{pmatrix} \redmatrixel{\gamma'j'}{\tensor{T}^{(k)}}{\gamma j}, \end{aligned} \label{eqn:wigner-eckart} \tag{V13.1.2}

where the reduced matrix element $\redmatrixel{n'j'}{\tensor{T}^{(k)}}{nj}$ does not depend on $m,m'$. j′ and j are the total angular momenta with m′ and m being their respective projections. γ′ and γ are all other quantum numbers needed to fully specify the quantum system; their presence depend on the quantum system.

Examples

julia> matrix_element((2, 1), TensorComponent(OrbitalAngularMomentum(), 1), (2, 0))
-1.7320508075688774

julia> matrix_element((0, 0), TensorComponent(SphericalTensor(1), 0), (1, 0))
0.5773502691896256

julia> matrix_element(((1,half(1),half(1)), -half(1)),
TensorComponent(TotalAngularMomentum(), -1),
((1,half(1),half(1)), half(1)))
0.7071067811865475
AngularMomentumAlgebra.matrix_elementMethod
matrix_element((γj₁′, ::Tuple{}, j′, m′), 𝐓ᵏq, (γj₁, ::Tuple{}, j, m))

Compute the matrix element of the tensor 𝐓ᵏq which acts on coordinate 1, in the special case that the second coordinate is immaterial for the tensor 𝐓ᵏ (an example is the principal quantum number $n$, which does not affect the matrix elements of 𝐉).

Examples

julia> 𝐉₀ = TensorComponent(TotalAngularMomentum(), 0)
𝐉̂⁽¹⁾₀

julia> a = ((0, half(1), half(1)), (), half(1), half(1))
((0, 1/2, 1/2), (), 1/2, 1/2)

julia> matrix_element(a, 𝐉₀, a)
0.49999999999999994
AngularMomentumAlgebra.matrix_elementMethod
matrix_element((s₁,s₂)::Tuple{<:SubSystem,<:SubSystem},
a::SpinOrbital{<:Orbital},
X::TensorScalarProduct,
b::SpinOrbital{<:Orbital})

The matrix element of a tensor scalar product, where the factors act on different subsystems, evaluated in the basis of uncoupled spin-orbitals, is computed using $\eqref{eqn:scalar-product-tensor-matrix-element-diff-coords-uncoupled}$.

AngularMomentumAlgebra.matrix_elementMethod
matrix_element((s₁,s₂)::Tuple{<:SubSystem,<:SubSystem},
a::SpinOrbital{<:RelativisticOrbital},
X::TensorScalarProduct,
b::SpinOrbital{<:RelativisticOrbital})

The matrix element of a tensor scalar product, where the factors act on different subsystems, evaluated in the basis of coupled spin-orbitals, is computed using $\eqref{eqn:scalar-product-tensor-matrix-element-diff-coords-coupled}$.

AngularMomentumAlgebra.matrix_elementMethod
matrix_element(::Union{FullSystem,TotalAngularMomentumSubSystem},
a::SpinOrbital{<:Orbital},
𝐓ᵏq::TensorComponent,
b::SpinOrbital{<:Orbital})

The matrix element of a tensor acting on the full system or the total angular momentum, evaluated in the basis of uncoupled spin-orbitals, is computed by transforming to the coupled system via $\eqref{eqn:coupling}$.

AngularMomentumAlgebra.matrix_elementMethod
matrix_element(::Union{FullSystem,TotalAngularMomentumSubSystem},
a::SpinOrbital{<:RelativisticOrbital},
𝐓ᵏq::TensorComponent,
b::SpinOrbital{<:RelativisticOrbital})

The matrix element of a tensor acting on the full system or the total angular momentum, evaluated in the basis of coupled spin-orbitals, is simply computed using the Wigner–Eckart theorem $\eqref{eqn:wigner-eckart}$.

AngularMomentumAlgebra.matrix_elementMethod
matrix_element(systems::Tuple{S,S},
a::SpinOrbital{<:Orbital},
X::TensorScalarProduct,
b::SpinOrbital{<:Orbital}) where {S<:SubSystem}

The matrix element of a tensor scalar product, where both factors act on the same subsystem, evaluated in the basis of uncoupled spin-orbitals, is just a special case of $\eqref{eqn:tensor-matrix-element-subsystem-uncoupled}$ combined with $\eqref{eqn:scalar-product-tensor-matrix-element}$.

AngularMomentumAlgebra.matrix_elementMethod
matrix_element(::Tuple{S,S},
a::SpinOrbital{<:Orbital},
X::TensorScalarProduct,
b::SpinOrbital{<:Orbital}) where {S<:Union{FullSystem,TotalAngularMomentumSubSystem}}

The matrix element of a tensor scalar product, where both factors act on the full system or the total angular momentum, evaluated in the basis of uncoupled spin-orbitals, is computed by transforming to the coupled system via $\eqref{eqn:coupling}$, which then dispatches to $\eqref{eqn:scalar-product-tensor-matrix-element}$.

AngularMomentumAlgebra.matrix_elementMethod
matrix_element(systems::Tuple{S,S},
a::SpinOrbital{<:RelativisticOrbital},
X::TensorScalarProduct,
b::SpinOrbital{<:RelativisticOrbital}) where {S<:SubSystem}

The matrix element of a tensor scalar product, where both factors act on the same subsystem, evaluated in the basis of coupled spin-orbitals, is computed using

\begin{aligned} &\matrixel{n_1'j_1'n_2'j_2'j'm'}{[\tensor{P}^{(k)}(1)\cdot\tensor{Q}^{(k)}(1)]}{n_1j_1n_2j_2jm}\\ =&\delta_{n_2'n_2}\delta_{j_2'j_2}\delta_{j_1'j_1}\delta_{j'j}\delta_{m'm} \frac{1}{\angroot{j_1}^2} (-)^{-j_1}\\ &\times \sum_{JN}(-)^J \redmatrixel{n_1'j_1}{\tensor{P}^{(k)}(1)}{NJ} \redmatrixel{NJ}{\tensor{Q}^{(k)}(1)}{n_1j_1}. \end{aligned} \tag{V13.1.43}

Apart from the additional factor $\delta_{n_2'n_2}\delta_{j_2'j_2}$, this expression is equivalent to $\eqref{eqn:scalar-product-tensor-matrix-element}$.

AngularMomentumAlgebra.matrix_elementMethod
matrix_element(::Tuple{S,S},
a::SpinOrbital{<:RelativisticOrbital},
X::TensorScalarProduct,
b::SpinOrbital{<:RelativisticOrbital}) where {S<:Union{FullSystem,TotalAngularMomentumSubSystem}}

The matrix element of a tensor scalar product, where both factors act on the full system or the total angular momentum, evaluated in the basis of coupled spin-orbitals, is computed using $\eqref{eqn:scalar-product-tensor-matrix-element}$.

AngularMomentumAlgebra.matrix_element2Method
matrix_element2(γjm₁′, γjm₂′, X::TensorScalarProduct, γjm₁, γjm₂)

The matrix element of a scalar product of two tensors acting on different coordinates is given by (in the uncoupled basis)

\begin{aligned} &\matrixel{\gamma_1'j_1'm_1';\gamma_2'j_2'm_2'}{[\tensor{P}^{(k)}(1)\cdot\tensor{Q}^{(k)}(2)]}{\gamma_1j_1m_1;\gamma_2j_2m_2}\\ =& \frac{1}{\angroot{j_1'j_2'}} \sum_\alpha(-)^{-\alpha} C_{j_1m_1;k,\alpha}^{j_1'm_1'} C_{j_2m_2;k,-\alpha}^{j_2'm_2'}\\ &\times \redmatrixel{\gamma_1'j_1'}{\tensor{P}^{(k)}(1)}{\gamma_1j_1} \redmatrixel{\gamma_2'j_2'}{\tensor{Q}^{(k)}(2)}{\gamma_2j_2} \\ \equiv& \sum_\alpha (-)^{-\alpha} \matrixel{\gamma_1'j_1'm_1'}{\tensor{P}^{(k)}_{\alpha}(1)}{\gamma_1j_1m_1} \matrixel{\gamma_2'j_2'm_2'}{\tensor{Q}^{(k)}_{-\alpha}(2)}{\gamma_2j_2m_2} \end{aligned} \tag{V13.1.26} \label{eqn:scalar-product-tensor-matrix-element-diff-coords-uncoupled}

Since the Clebsch–Gordan coefficients can be rewritten using 3j symbols and the 3j symbols vanish unless $m_1 + \alpha - m_1' = m_2 - \alpha - m_2' = 0$, we have

$$$\alpha = m_1' - m_1 = m_2-m_2'$$$

This case occurs in two-body interactions, such as the Coulomb interaction, where $1',1$ and $2',2$ are pairs of orbitals and the scalar product tensor is a term in the multipole expansion in terms of Spherical tensors:

julia> 𝐂⁰ = SphericalTensor(0)
𝐂̂⁽⁰⁾

julia> matrix_element2((0, 0), (0, 0), 𝐂⁰⋅𝐂⁰, (0,0), (0, 0)) # ⟨1s₀,1s₀|𝐂⁰⋅𝐂⁰|1s₀,1s₀⟩
1.0

julia> 𝐂¹ = SphericalTensor(1)
𝐂̂⁽¹⁾

julia> matrix_element2((0, 0), (1, 0), 𝐂¹⋅𝐂¹, (1,0), (2, 0)) # ⟨1s₀,2p₀|𝐂¹⋅𝐂¹|2p₀,3d₀⟩
0.29814239699997186

julia> matrix_element2((0, 0), (1, 1), 𝐂¹⋅𝐂¹, (1,0), (2, 1)) # ⟨1s₀,2p₁|𝐂¹⋅𝐂¹|2p₀,3d₁⟩
0.25819888974716104

but also in the case of the operator $\tensor{L}\cdot\tensor{S}$ and coordinates $1$ and $2$ correspond to orbital and spin angular momenta, respectively. We can verify this using the classical result known from spin–orbit splitting:

\begin{aligned} J^2 &= (\tensor{L}+\tensor{S})^2 = L^2 + 2\tensor{L}\cdot\tensor{S} + S^2\\ \implies \expect{\tensor{L}\cdot\tensor{S}} &= \frac{1}{2}(\expect{J^2} - \expect{L^2} - \expect{S^2}) = \frac{1}{2}[J(J+1) - L(L+1) - S(S+1)] \end{aligned}

In the uncoupled basis, $J$ is not a good quantum number (it is not a constant of motion), except for pure states, i.e. those with maximal $\abs{m_\ell + m_s}$:

julia> X = OrbitalAngularMomentum()⋅SpinAngularMomentum()
(𝐋̂⁽¹⁾⋅𝐒̂⁽¹⁾)

julia> matrix_element2((1, 1), (half(1), half(1)),
X, (1,1), (half(1), half(1)))
0.4999999999999999

julia> 1/2*(half(3)*(half(3)+1)-1*(1+1)-half(1)*(half(1)+1)) # 1/2(J(J+1)-L(L+1)-S(S+1))
0.5
AngularMomentumAlgebra.matrix_element2Method
matrix_element2((γj₁′, γj₂′, j′, m′), X::TensorScalarProduct, (γj₁, γj₂, j, m))

The matrix element of a scalar product of two tensors acting on different coordinates is given by (in the coupled basis)

\begin{aligned} &\matrixel{n_1'j_1'n_2'j_2'j'm'}{[\tensor{P}^{(k)}(1)\cdot\tensor{Q}^{(k)}(2)]}{n_1j_1n_2j_2jm}\\ =& \delta_{j'j}\delta_{m'm} (-)^{j+j_1+j_2'} \wignersixj{j_1'&j_1&k\\j_2&j_2'&j}\\ &\times \redmatrixel{n_1'j_1'}{\tensor{P}^{(k)}(1)}{n_1j_1} \redmatrixel{n_2'j_2'}{\tensor{Q}^{(k)}(2)}{n_2j_2}. \end{aligned} \tag{V13.1.29} \label{eqn:scalar-product-tensor-matrix-element-diff-coords-coupled}
julia> X = OrbitalAngularMomentum()⋅SpinAngularMomentum()
(𝐋̂⁽¹⁾⋅𝐒̂⁽¹⁾)

julia> matrix_element2((1, half(1), half(3), half(3)),
X, (1, half(1), half(3), half(3)))
0.4999999999999999
AngularMomentumAlgebra.multipole_expandMethod
multipole_expand(integral::OrbitalMatrixElement{2,A,<:CoulombInteraction,B})

Multipole-expand the two-body integral resulting from the Coulomb repulsion between two electrons.

AngularMomentumAlgebra.multipole_expand_scalar_productFunction
multipole_expand_scalar_product(a, b, P, Q, c, d)

Multipole-expand the matrix element ⟨ab|P⋅Q|cd⟩, where the tensor P acts on orbitals a & c, and the tensor Q acts on orbitals b & d. The definition is taken from Eq. (13.1.26) of Varshalovich (1988).

AngularMomentumAlgebra.quantum_numbersMethod
quantum_numbers(::FullSystem, o::SpinOrbital{<:Orbital})

The full system of an uncoupled spin-orbital is $n\ell m_\ell; s m_s$, where $;$ denotes that the spatial and spin subsystems are separable.

AngularMomentumAlgebra.quantum_numbersMethod
quantum_numbers(::OrbitalAngularMomentumSubSystem, o::SpinOrbital{<:RelativisticOrbital})

The orbital angular momentum subsystem of a coupled spin-orbital is just $\ell$; $m_\ell$ is not a good quantum number.

AngularMomentumAlgebra.quantum_numbersMethod
quantum_numbers(::SpatialSubSystem, o::SpinOrbital{<:RelativisticOrbital})

The spatial subsystem of a coupled spin-orbital is just $n\ell m_\ell$; $m_\ell$ is not a good quantum number.

AngularMomentumAlgebra.quantum_numbersMethod
quantum_numbers(::TotalAngularMomentumSubSystem, o::SpinOrbital{<:Orbital})

The total angular momentum of an uncoupled spin-orbital is not a good quantum number; only its projection is known. The system is specified by $\ell m_\ell; s m_s$, where $;$ denotes that the spatial and spin subsystems are separable.

AngularMomentumAlgebra.quantum_numbersMethod
quantum_numbers(::TotalAngularMomentumSubSystem, o::SpinOrbital{<:RelativisticOrbital})

The total angular momentum subsystem of a coupled spin-orbital just $\ell s j m_j$.

AngularMomentumAlgebra.ranksMethod
ranks(a, ::Type{CoulombTensor}, b)

Return which tensor ranks for Coulomb tensors that fulfill the triangle condition between spin-orbitals a and b.

AngularMomentumAlgebra.ranksMethod
ranks(a, ::Type{SphericalTensor}, b)

Return which tensor ranks for spherical tensors that fulfill the triangle condition between spin-orbitals a and b.

AngularMomentumAlgebra.recursepmMethod
recursepm(lhs, rhs)

Recursively expand lhs and rhs for instances of ± and ∓ and join all resulting cases into a short-circuiting || test.

AngularMomentumAlgebra.recursepmMethod
recursepm(e::Expr)

Recursively expand the expression e for instances of ± and ∓, generating + and - minus branches.

AngularMomentumAlgebra.rmeMethod
rme(ℓ′, 𝐋̂, ℓ)

Calculate the reduced matrix element of the orbital angular momentum:

$$$$$\tag{V13.2.67} \redmatrixel{\ell'}{\tensor{L}}{\ell} \defd \delta_{\ell'\ell}\sqrt{\ell(\ell+1)(2\ell+1)}$$$$$

Examples

julia> rme(1, OrbitalAngularMomentum(), 1)
2.449489742783178

julia> rme(1, OrbitalAngularMomentum(), 2)
0
AngularMomentumAlgebra.rmeMethod
rme(s′, ::SpinAngularMomentum, s)

Calculate the reduced matrix element of the spin angular momentum:

$$$$$\tag{V13.2.95} \redmatrixel{s'}{\tensor{S}}{s} \defd \delta_{ss'} \sqrt{s(s+1)(2s+1)}$$$$$

Examples

julia> rme(half(1), SpinAngularMomentum(), half(1))
1.224744871391589

julia> rme(half(1), SpinAngularMomentum(), half(3))
0
AngularMomentumAlgebra.rmeMethod
rme((ℓ′,s′,J′), ::TotalAngularMomentum, (ℓ,s,J))

Calculate the reduced matrix element of the total angular momentum:

$$$$$\tag{V13.2.38} \redmatrixel{\ell's'J'}{\tensor{J}}{\ell s J} \defd \delta_{\ell\ell'}\delta_{ss'}\delta_{JJ'} \sqrt{J(J+1)(2J+1)}$$$$$

Examples

julia> rme((1,half(1),half(3)), TotalAngularMomentum(), (1,half(1),half(3)))
3.872983346207417

julia> rme((1,half(1),half(3)), TotalAngularMomentum(), (1,half(1),half(1)))
0
AngularMomentumAlgebra.rmeMethod
rme(ℓ′,𝐂̂ᵏ,ℓ)

Calculate the reduced matrix element of the spherical tensor of rank k:

\begin{aligned} \redmatrixel{\ell'}{\tensor{C}^{(k)}}{\ell} &= \angroot{\ell} C_{\ell 0;k,0}^{\ell'0} = (-)^{\ell-k} \angroot{\ell\ell'} \wignerthreej{\ell&k&\ell'\\0&0&0}. \end{aligned} \tag{V13.2.107}
AngularMomentumAlgebra.triangle_rangeMethod
triangle_range(a,b)

Find all k such that |a-b| ≤ k ≤ a + b. This is useful when expanding matrix elements of tensors between angular momenta a and b in multipoles k; triangle_range can then be used to decided which multipole terms are required.

AngularMomentumAlgebra.wrap_show_debugMethod
wrap_show_debug(expr)

Wrap expr with a @show macro call if DEBUG_TENSOR_DSL exists as an environment flag, otherwise return expr as-is. This is applied at compile time, so no overhead is incurred.

AngularMomentumAlgebra.∏Method
∏(ℓs...)

Calculates √((2ℓ₁+1)(2ℓ₂+1)...(2ℓₙ+1)), which is a common factor in angular momentum algebra.

Base.diffMethod
diff(ab::OrbitalRadialOverlap, o::Conjugate{O})

Vary the orbital radial overlap ⟨a|b⟩ᵣ with respect to ⟨o|.

Base.diffMethod
diff(ab::OrbitalRadialOverlap, o::O)

Vary the orbital radial overlap ⟨a|b⟩ᵣ with respect to |o⟩.

EnergyExpressions.isdependentMethod
isdependent(o::OrbitalRadialMatrixElement, orbital)

Returns true if the OrbitalRadialMatrixElement o depends on orbital.

Examples

julia> isdependent(OrbitalRadialMatrixElement(:a,I,:b), :a)
false

true

true
EnergyExpressions.isdependentMethod
isdependent(o::OrbitalRadialOverlap, orbital)

Returns true if the OrbitalRadialOverlap o depends on orbital.

Examples

julia> isdependent(OrbitalRadialOverlap(:a,:b), :a)
false

true

true
EnergyExpressions.numbodiesMethod
numbodies(::OrbitalRadialOverlap)

Returns the number of bodies coupled by the zero-body operator in the orbital overlap, i.e. 0.

LinearAlgebra.dotMethod
dot(a::SpinOrbital,
𝐓ᵏq::Union{TensorComponent,TensorScalarProduct},
b::SpinOrbital)

Compute the matrix element ⟨a|𝐓ᵏq|b⟩ in the basis of spin-orbitals, dispatching to the correct low-level function matrix_element, depending on the value of system(𝐓ᵏq).

Examples with coupled orbitals

julia> a,b,c,d = (SpinOrbital(ro"2p", half(3)),
SpinOrbital(ro"2p", half(1)),
SpinOrbital(ro"2s", half(1)),
SpinOrbital(ro"3d", half(3)))
(2p(3/2), 2p(1/2), 2s(1/2), 3d(3/2))

julia> 𝐋, 𝐒, 𝐉 = OrbitalAngularMomentum(), SpinAngularMomentum(), TotalAngularMomentum()
(𝐋̂⁽¹⁾, 𝐒̂⁽¹⁾, 𝐉̂⁽¹⁾)

julia> 𝐋², 𝐒², 𝐉² = 𝐋⋅𝐋, 𝐒⋅𝐒, 𝐉⋅𝐉
((𝐋̂⁽¹⁾⋅𝐋̂⁽¹⁾), (𝐒̂⁽¹⁾⋅𝐒̂⁽¹⁾), (𝐉̂⁽¹⁾⋅𝐉̂⁽¹⁾))

julia> dot(a, cartesian_tensor_component(𝐉, :x), b),
1/2*√((3/2+1/2+1)*(3/2-1/2)) # 1/2√((J+M+1)*(J-M))
(0.8660254037844386, 0.8660254037844386)

julia> dot(a, cartesian_tensor_component(𝐉, :z), a), a.m[1]
(1.5, 3/2)

julia> dot(a, TensorComponent(𝐋, 0), a)
0.9999999999999999

- 0.408248(∂ᵣ + 2/r)

julia> dot(c, cartesian_tensor_component(SphericalTensor(1), :x), a)
-0.40824829046386296

julia> orbitals = rsos"2[p]"
6-element Array{SpinOrbital{RelativisticOrbital{Int64},Tuple{Half{Int64}}},1}:
2p-(-1/2)
2p-(1/2)
2p(-3/2)
2p(-1/2)
2p(1/2)
2p(3/2)

julia> map(o -> dot(o, 𝐉², o), orbitals)
6-element Array{Float64,1}:
0.7499999999999998
0.7499999999999998
3.7500000000000004
3.7500000000000004
3.7500000000000004
3.7500000000000004

julia> 1/2*(1/2+1),3/2*(3/2+1) # J(J+1)
(0.75, 3.75)

julia> dot(a, 𝐋², a), 1*(1+1)
(2.0, 2)

julia> dot(d, 𝐋², d), 2*(2+1)
(5.999999999999999, 6)

julia> dot(a, 𝐒², a), 1/2*(1/2+1)
(0.7499999999999998, 0.75)

julia> dot(a, 𝐋⋅𝐒, a)
0.4999999999999999

Examples with uncoupled orbitals

julia> a,b,c,d = (SpinOrbital(o"2p", 1, half(1)),
SpinOrbital(o"2p", -1, half(1)),
SpinOrbital(o"2s", 0, half(1)),
SpinOrbital(o"3d", 2, -half(1)))
(2p₁α, 2p₋₁α, 2s₀α, 3d₂β)

julia> 𝐋,𝐒,𝐉 = OrbitalAngularMomentum(),SpinAngularMomentum(),TotalAngularMomentum()
(𝐋̂⁽¹⁾, 𝐒̂⁽¹⁾, 𝐉̂⁽¹⁾)

julia> 𝐋²,𝐒²,𝐉² = 𝐋⋅𝐋,𝐒⋅𝐒,𝐉⋅𝐉
((𝐋̂⁽¹⁾⋅𝐋̂⁽¹⁾), (𝐒̂⁽¹⁾⋅𝐒̂⁽¹⁾), (𝐉̂⁽¹⁾⋅𝐉̂⁽¹⁾))

julia> dot(a, cartesian_tensor_component(𝐉, :z), a), sum(a.m)
(1.5, 3/2)

julia> dot(a, TensorComponent(𝐋, 0), a)
0.9999999999999999

julia> # Same as previous, but with spin down
dot(a, TensorComponent(𝐋, 0), SpinOrbital(o"2p", 1, -half(1)))
0

julia> dot(d, TensorComponent(𝐋, 0), d)
1.9999999999999998

julia> dot(d, TensorComponent(𝐒, 0), d)
-0.49999999999999994

- 0.408248(∂ᵣ + 2/r)

julia> dot(c, cartesian_tensor_component(SphericalTensor(1), :x), a)
-0.40824829046386285

julia> orbitals = sos"2[p]"
6-element Array{SpinOrbital{Orbital{Int64},Tuple{Int64,Half{Int64}}},1}:
2p₋₁α
2p₋₁β
2p₀α
2p₀β
2p₁α
2p₁β

julia> # Only 2p₋₁β and 2p₁α are pure states, with J = 3/2 => J(J + 1) = 3.75
map(o -> dot(o, 𝐉², o), orbitals)
6-element Array{Float64,1}:
1.7499999999999998
3.7500000000000004
2.75
2.75
3.7500000000000004
1.7499999999999998

julia> dot(a, 𝐋², a), 1*(1+1)
(2.0, 2)

julia> dot(d, 𝐋², d), 2*(2+1)
(5.999999999999999, 6)

julia> dot(a, 𝐒², a), half(1)*(half(1)+1)
(0.7499999999999998, 0.75)

julia> dot(a, 𝐋⋅𝐒, a)
0.4999999999999999
LinearAlgebra.dotMethod
dot(T::Tensor, U::Tensor)

Form the scalar product of the two tensors T and U, which need to have the same rank.

Examples

julia> SphericalTensor(4)⋅SphericalTensor(4)
(𝐂̂⁽⁴⁾⋅𝐂̂⁽⁴⁾)
LinearAlgebra.dotMethod
dot((a,b)::Tuple, X::TensorScalarProduct, (c,d)::Tuple)

Compute the matrix element ⟨a(1)b(2)|𝐓(1)⋅𝐔(2)|c(1)d(2)⟩ in the basis of spin-orbitals, dispatching the correct low-level function matrix_element depending on the value of system(X), where X is the scalar product tensor.

Examples

julia> 𝐊⁰,𝐊² = CoulombTensor(0),CoulombTensor(2)
(𝐊̂⁽⁰⁾, 𝐊̂⁽²⁾)

julia> a,b = SpinOrbital(o"1s", 0, half(1)),SpinOrbital(o"3d", 0, half(1))
(1s₀α, 3d₀α)

julia> dot((a,b), 𝐊⁰⋅𝐊⁰, (a,b))
1.0

julia> dot((a,b), 𝐊²⋅𝐊², (b,a))
0.19999999999999998

julia> a,b = SpinOrbital(ro"1s", half(1)),SpinOrbital(ro"3d", half(1))
(1s(1/2), 3d(1/2))

julia> dot((a,b), 𝐊⁰⋅𝐊⁰, (a,b))
1.0

julia> dot((a,b), 𝐊²⋅𝐊², (b,a))
0.12
AngularMomentumAlgebra.@linearly_combinableMacro
@linearly_combinable TT

Turns the type TT into a linearly combinable type, i.e. defines arithmetic operators.

Examples

julia> @linearly_combinable Symbol

julia> 4*(:x) - 5*(:y)
4 :x - 5 :y
AngularMomentumAlgebra.@δMacro
@δ (a,b)[, (c,d) ...]

Kronecker $\delta_{ab}\delta_{cd}...$ that tests each pair of values for equality and quick-returns 0 at the first inequality. Thus intended usage is within a function body, and not as part of an expression.

Example

julia> import AngularMomentumAlgebra: @δ

julia> function my_function(a,b)
@δ a,b # Quick-returns unless a and b are equal
sin(a)
end
my_function (generic function with 1 method)

julia> my_function(1,1)
0.8414709848078965

julia> my_function(1,0)
0