Defining symmetry sector(s)
In SymBasis.jl, you can generate bases that have one or more symmetries by defining the corresponding symmetry groups(s).
Predefined symmetry groups
SymBasis.jl provides predefined symmetry groups for commonly used symmetries. You can construct these symmetry groups using the sym function from the SymBasis.SymGroups submodule.
DoF-object-independent symmetry groups
Some symmetries are independent of the DoF-object, such as translational and reflection symmetries.
Translational symmetry
Translational symmetry is a symmetry where the system is invariant under translations. In a system with $N$ sites, the translation operator $T$ acts on a state $\vert a \rangle$ as follows:
\[\vert a(k) \rangle = \frac{1}{\sqrt{N_a}} \sum_{r=0}^{N-1} e^{-i k r} \hat{T}^r \vert a \rangle\]
where $N_a$ is the normalization factor, $k$ is the momentum quantum number, and $\hat{T}^r$ is the translation operator applied $r$ times. The translation operator $\hat{T}$ acts on the state $\vert a(k) \rangle$ as follows:
\[\hat{T} \vert a(k) \rangle = e^{i k} \vert a(k) \rangle\]
You can define a translation symmetry group for a system with a certain number of sites using the sym function and the Translational type as follows:
using SymBasis.DoFObjects
using SymBasis.SymGroups
dofo = dof_object(Spin(1 // 2)) # define, for example, a spin-1/2
N = 4 # number of sites
perm = mod1.((1:N) .+ 1, N) # permutation for translational symmetry
k = 0 # momentum quantum number
sg = sym(Translational(k, perm), dofo)SymGroup{2,Rational{Int64},UInt64,Int64,ComplexF64} with 4 cycle(s)
N: 4
DoF-object: DoFObject(Spin, B=2)
cycles: (perm = BitPermutation{UInt64},), (perm = BitPermutation{UInt64},), (perm = BitPermutation{UInt64},), (perm = BitPermutation{UInt64},)
factors: 4 element(s), eltype=ComplexF64
check: check_perm
apply: apply_perm
Spatial-reflection symmetry
Spatial-reflection symmetry is a symmetry where the system is invariant under spatial reflection. In a system with $N$ sites, the reflection operator $R$ acts on a state $\vert a \rangle$ as follows:
\[\vert a(p) \rangle = \frac{1}{\sqrt{N_a}} \sum_{r=0}^{1} p^r \hat{P}^r \vert a \rangle\]
where $N_a$ is the normalization factor, $p$ is the parity quantum number, and $\hat{P}^r$ is the reflection operator applied $r$ times. The reflection operator $\hat{P}$ acts on the state $\vert a(p) \rangle$ as follows:
\[\hat{P} \vert a(p) \rangle = p \vert a(p) \rangle\]
You can define a spatial reflection symmetry group for a system with a certain number of sites using the sym function and the SpatialReflection type as follows:
using SymBasis.DoFObjects
using SymBasis.SymGroups
dofo = DoFObject(:Pet, (:🐶, :🐱, :🦜)) # define, for example, a pet object
N = 4 # number of sites
perm = reverse(1:N) |> collect # permutation for reflection symmetry
p = -1 # parity number
sg = sym(SpatialReflection(p, perm), dofo)SymGroup{3,Symbol,UInt64,Int64,Int64} with 2 cycle(s)
N: 4
DoF-object: DoFObject(Pet, B=3)
cycles: (perm = [1, 2, 3, 4],), (perm = [4, 3, 2, 1],)
factors: 2 element(s), eltype=Int64
check: check_perm
apply: apply_perm
Rotational symmetry of space
Rotational symmetry is a symmetry where the system is invariant under discrete rotations in space. For a system where the rotation operator $\hat{R}$ has period $T_R$ (i.e. $\hat{R}^{T_R} = \hat{I}$), the representative state $\vert a(r) \rangle$ with rotation quantum number $r$ is constructed as follows:
\[\vert a(r) \rangle = \frac{1}{\sqrt{N_a}} \sum_{l=0}^{T_R-1} e^{-i 2\pi r l / T_R} \hat{R}^l \vert a \rangle\]
where $N_a$ is the normalization factor, $r \in \{0, 1, \ldots, T_R - 1\}$ is the rotation quantum number, and $l$ is the summation index. The rotation operator $\hat{R}$ acts on the representative state $\vert a(r) \rangle$ as an eigenstate:
\[\hat{R} \vert a(r) \rangle = e^{i 2\pi r / T_R} \vert a(r) \rangle\]
You can define a rotational symmetry group using the sym function and the Rotational type. The permutation supplied to Rotational should encode the action of $\hat{R}$ on site indices:
using SymBasis.DoFObjects
using SymBasis.SymGroups
dofo = DoFObject(:Pet, (:🐶, :🐱, :🦜)) # define, for example, a pet object
N = 4 # number of sites (2×2 square lattice)
perm = [2, 4, 1, 3] # permutation encoding a 90° rotation of the 2×2 lattice (T_R = 4)
r = 0 # rotation quantum number (r = 0, 1, 2, or 3)
sg = sym(Rotational(r, perm), dofo)SymGroup{3,Symbol,UInt64,Int64,ComplexF64} with 4 cycle(s)
N: 4
DoF-object: DoFObject(Pet, B=3)
cycles: (perm = [1, 2, 3, 4],), (perm = [2, 4, 1, 3],), (perm = [4, 3, 2, 1],), (perm = [3, 1, 4, 2],)
factors: 4 element(s), eltype=ComplexF64
check: check_perm
apply: apply_perm
DoF-object-dependent symmetry groups
Some symmetries depend on the DoF-object, such as total magnetization symmetry.
Quantum mechanical spins
Total magnetization symmetry
Total magnetization symmetry is a symmetry where the system is invariant under the total magnetization operator. In a system with $N$ sites, the total magnetization operator $\hat{S}^z$ acts on a state $\vert a(S^z) \rangle$ as follows:
\[\hat{S}^z \vert a(S^z) \rangle = \sum_{i=1}^{N} S_i^z \vert a(S^z) \rangle = S^z \vert a(S^z) \rangle\]
where $S_i^z$ is the magnetization of the $i$-th site, and $S^z$ is the total magnetization quantum number. You can define a total magnetization symmetry group for a system with a certain number of sites using the sym function and the TotalMagnetization type as follows:
using SymBasis.DoFObjects
using SymBasis.SymGroups
dofo = dof_object(Spin(1 // 1)) # define, for example, a spin-1
N = 5 # number of sites
Sz = 0 # total magnetization quantum number
sg = sym(TotalMagnetization(Sz, N), dofo)SymGroup{3,Rational{Int64},UInt64,Int64,Float64} with 3 cycle(s)
N: 5
DoF-object: DoFObject(Spin, B=3)
cycles: (N0 = 0, N1 = 5, N2 = 0, N = 5), (N0 = 1, N1 = 3, N2 = 1, N = 5), (N0 = 2, N1 = 1, N2 = 2, N = 5)
factors: 3 element(s), eltype=Float64
check: check_Nₛ
apply: apply_Nₛ
Spin-inversion symmetry
Spin-inversion symmetry is a symmetry where the system is invariant under the spin-inversion operator. The spin-inversion operator $\hat{P}_z$ flips all spin quantum numbers on every site:
\[\hat{P}_z \vert \sigma_1, \sigma_2, \ldots, \sigma_N \rangle = \vert -\sigma_1, -\sigma_2, \ldots, -\sigma_N \rangle\]
In a system with $N$ sites, the representative state $\vert a(z) \rangle$ is constructed as follows:
\[\vert a(z) \rangle = \frac{1}{\sqrt{N_a}} \sum_{r=0}^{1} z^r \hat{P}_z^r \vert a \rangle\]
where $N_a$ is the normalization factor and $z$ is the parity quantum number. The spin-inversion operator $\hat{P}_z$ acts on $\vert a(z) \rangle$ as follows:
\[\hat{P}_z \vert a(z) \rangle = z \vert a(z) \rangle\]
where $z$ is the parity quantum number. You can define a spin-inversion symmetry group for a system with a certain number of sites using the sym function and the SpinInversion type as follows:
using SymBasis.DoFObjects
using SymBasis.SymGroups
dofo = dof_object(Spin(1 // 2)) # define, for example, a spin-1/2
N = 4 # number of sites
z = -1 # parity number
sg = sym(SpinInversion(z, N), dofo)SymGroup{2,Rational{Int64},UInt64,Int64,Int64} with 2 cycle(s)
N: 4
DoF-object: DoFObject(Spin, B=2)
cycles: (is_flipped = false, sites = [1, 2, 3, 4], N0 = 2, N1 = 2, N = 4), (is_flipped = true, sites = [1, 2, 3, 4], N0 = 2, N1 = 2, N = 4)
factors: 2 element(s), eltype=Int64
check: check_flip
apply: apply_flip
Custom symmetry groups
In addition to the predefined symmetry groups, you can also define your own custom symmetry groups by specifying the appropriate parameters when constructing the symmetry group via the SymGroup constructor from the SymBasis.SymGroups submodule.
To define a custom symmetry group, you need to specify the following parameters:
dofo: The DoF-object that the symmetry group is associated with.cycles: A vector ofNamedTuples, where eachNamedTuplerepresents a cycle in the symmetry group. EachNamedTuplehas its own special fields that depend on the type of symmetry you want to define. For example, for a custom symmetry that is defined by a permutation, you would specify thepermfield in theNamedTupleto represent the permutation.check: A function that checks whether a given state is invariant under the symmetry operation. This function should take a cycle, a state and the previous boolean result of checking the previous cycle as input and return a boolean value indicating whether the state is invariant under the symmetry operation and the previous cycles.apply: A function that applies the symmetry operation to a given state. This function should take a cycle, a state and return the state obtained by applying the symmetry operation to the input state.factors: A vector of factors that are used to calculate the normalization factor for the basis states. The factors should be defined in such a way that they can be used to calculate the normalization factor for the basis states that are invariant under the symmetry operation.N: The number of sites in the system.
As an example, let's define a custom symmetry group for a DoF-object that represents a system containing pet emojis (🐶, 🐱, 🦜, 🐢), where the symmetry is defined by preventing the 🐱 from being next to 🐶. We can define this custom symmetry group as follows:
Let's first import the necessary submodules and then define our DoF-object for the system containing pet emojis:
using SymBasis.DigitBase
using SymBasis.DoFObjects
using SymBasis.SymGroups
dofo = DoFObject(:Pet, (:🐶, :🐱, :🦜, :🐢))DoFObject: Pet (B=4)
ldof: (:🐶, :🐱, :🦜, :🐢)
index types: T=UInt64, Ti=Int64Next, we define the number of sites:
N = 33Then, we define the cycles for the custom symmetry. In this case, we want to prevent the 🐱 from being next to 🐶, so we can define a cycle that represents this constraint:
cycles = [(; prevent=(UInt(0), UInt(1)), N=N)] # prevent the 🐱 from being next to 🐶1-element Vector{@NamedTuple{prevent::Tuple{UInt64, UInt64}, N::Int64}}:
(prevent = (0x0000000000000000, 0x0000000000000001), N = 3)Next, we can define the check function for the custom symmetry. This function will check if a given state is invariant under the symmetry operation, which in this case means checking if the 🐱 and 🐶 are next to each other in the state:
function check_cat_dog(
p::Tp,
state::BaseInt{T,Ti,B},
prev_bool::Bool
) where {
T<:Integer,
Ti<:Integer,
B,
Tp<:NamedTuple{(:prevent, :N),<:Tuple{NTuple{2,T},<:Integer}}
}
return prev_bool && !any(
map(2:(p.N-1)) do i
d_prev, d_curr, d_next = read(state, i - 1), read(state, i), read(state, i + 1)
(d_curr == p.prevent[1] && d_next == p.prevent[2]) ||
(d_curr == p.prevent[2] && d_next == p.prevent[1]) ||
(d_curr == p.prevent[1] && d_prev == p.prevent[2]) ||
(d_curr == p.prevent[2] && d_prev == p.prevent[1])
end
)
endcheck_cat_dog (generic function with 1 method)Then, we can define the apply function for the custom symmetry. This function will apply the symmetry operation to a given state. In this case, since the symmetry operation does not change the state, we can simply return the input state:
function apply_cat_dog(
p::Tp,
state::BaseInt{T,Ti,B}
) where {
T<:Integer,
Ti<:Integer,
B,
Tp<:NamedTuple{(:prevent, :N),<:Tuple{NTuple{2,T},<:Integer}}
}
return state
endapply_cat_dog (generic function with 1 method)Next, we define the factors for the custom symmetry. In this case, we can simply use a factor of 1 since the normalization factor for the basis states that are invariant under the symmetry operation is 1:
factors = [1,]1-element Vector{Int64}:
1Finally, we can construct the custom symmetry group using the SymGroup constructor:
sg = SymGroup(
dofo,
cycles,
check_cat_dog,
apply_cat_dog,
factors,
N
)SymGroup{4,Symbol,UInt64,Int64,Int64} with 1 cycle(s)
N: 3
DoF-object: DoFObject(Pet, B=4)
cycles: (prevent = (0x0000000000000000, 0x0000000000000001), N = 3)
factors: 1 element(s), eltype=Int64
check: check_cat_dog
apply: apply_cat_dog
Combining symmetry groups
You can also combine multiple symmetry groups to generate bases that conserve multiple symmetries simultaneously. This can be done using the ∘ function from the SymBasis.SymGroups submodule, which eventually returns a CombSymGroup type that represents the combined symmetries.
For example, if you want to combine the total magnetization symmetry and the translational symmetry, you can define the combined symmetry group as follows:
using SymBasis.DoFObjects
using SymBasis.SymGroups
dofo = dof_object(Spin(1 // 2)) # define, for example, a spin-1/2
N = 4 # number of sites
Sz = 0 # total magnetization quantum number
perm = mod1.((1:N) .+ 1, N) # permutation for translational symmetry
k = 0 # momentum quantum number
sg_total_magnetization = sym(TotalMagnetization(Sz, N), dofo)
sg_translational = sym(Translational(k, perm), dofo)
csg = sg_total_magnetization ∘ sg_translationalCombSymGroup{2,Rational{Int64},UInt64,Int64,ComplexF64} with size of cycles = (1, 4)
N: 4
DoF-object: DoFObject(Spin, B=2)
cycles: array of vectors; eltype=Vector{NamedTuple}
factors: size=(1, 4), eltype=ComplexF64
check: 2 function(s)
apply: 2 function(s)
preview @[1]: factor=1.0 - 0.0im
cycle=(N0 = 2, N1 = 2, N = 4), (perm = BitPermutation{UInt64},)
When combining multiple symmetry groups, it is important to ensure that the symmetries commute with each other in the basis. If the symmetries do not commute, the generated basis may not be correct. It is the user's responsibility to check for the commutation of symmetries after generating the basis using the is_commutative function from the SymBasis.Bases submodule.