!> Author: Jabir Ali Ouassou !> Category: Foundation !> This module defines the type 'spin', representing 2×2 complex matrices in !> spin space. The module overloads common arithmetic operators to work with !> the new data type, and defines and exports the Pauli matrices as constants. !> To make it easier to interact with common differential equation solvers, !> which often operate on real state vectors, the assignment operator is !> overloaded to make 'spin' easily importable/exportable to real vectors. module spin_m use :: math_m private ! Public interface public spin public inverse, trace, conjg, norm2, sum public pauli, pauli0, pauli1, pauli2, pauli3 ! Type declaration type spin complex(wp) :: matrix(2, 2) = 0.0_wp contains ! Overload constructors and operators generic :: spin => & cons_rscalar, cons_cscalar, & cons_cmatrix, cons_rvector, & cons_spin generic :: assignment(=) => & assr_rscalar, assr_cscalar, & assr_cmatrix, assr_rvector, & assl_cmatrix, assl_rvector generic :: operator(+) => & addl_rscalar, addr_rscalar, & addl_cscalar, addr_cscalar, & addl_cmatrix, addr_cmatrix, & add_spin generic :: operator(-) => & subl_rscalar, subr_rscalar, & subl_cscalar, subr_cscalar, & subl_cmatrix, subr_cmatrix, & sub_spin generic :: operator(*) => & mull_rscalar, mulr_rscalar, & mull_cscalar, mulr_cscalar, & mull_cmatrix, mulr_cmatrix, & mul_spin generic :: operator(/) => & divr_rscalar, divr_cscalar generic :: operator(**) => & expr_iscalar ! Specific methods for construction procedure, nopass, private :: cons_spin => spin_cons_spin procedure, nopass, private :: cons_rscalar => spin_cons_rscalar procedure, nopass, private :: cons_cscalar => spin_cons_cscalar procedure, nopass, private :: cons_cmatrix => spin_cons_cmatrix procedure, nopass, private :: cons_rvector => spin_cons_rvector ! Specific implementations of assignments procedure, pass(this), private :: assr_rscalar => spin_assr_rscalar procedure, pass(this), private :: assr_cscalar => spin_assr_cscalar procedure, pass(this), private :: assl_cmatrix => spin_assl_cmatrix procedure, pass(this), private :: assr_cmatrix => spin_assr_cmatrix procedure, pass(this), private :: assl_rvector => spin_assl_rvector procedure, pass(this), private :: assr_rvector => spin_assr_rvector ! Specific implementations of addition procedure, pass(this), private :: add_spin => spin_add_spin procedure, pass(this), private :: addl_rscalar => spin_addl_rscalar procedure, pass(this), private :: addr_rscalar => spin_addr_rscalar procedure, pass(this), private :: addl_cscalar => spin_addl_cscalar procedure, pass(this), private :: addr_cscalar => spin_addr_cscalar procedure, pass(this), private :: addl_cmatrix => spin_addl_cmatrix procedure, pass(this), private :: addr_cmatrix => spin_addr_cmatrix ! Specific implementations of subtraction procedure, pass(this), private :: sub_spin => spin_sub_spin procedure, pass(this), private :: subl_rscalar => spin_subl_rscalar procedure, pass(this), private :: subr_rscalar => spin_subr_rscalar procedure, pass(this), private :: subl_cscalar => spin_subl_cscalar procedure, pass(this), private :: subr_cscalar => spin_subr_cscalar procedure, pass(this), private :: subl_cmatrix => spin_subl_cmatrix procedure, pass(this), private :: subr_cmatrix => spin_subr_cmatrix ! Specific implementations of multiplication procedure, pass(this), private :: mul_spin => spin_mul_spin procedure, pass(this), private :: mull_rscalar => spin_mull_rscalar procedure, pass(this), private :: mulr_rscalar => spin_mulr_rscalar procedure, pass(this), private :: mull_cscalar => spin_mull_cscalar procedure, pass(this), private :: mulr_cscalar => spin_mulr_cscalar procedure, pass(this), private :: mull_cmatrix => spin_mull_cmatrix procedure, pass(this), private :: mulr_cmatrix => spin_mulr_cmatrix ! Specific implementations of division procedure, pass(this), private :: divr_rscalar => spin_divr_rscalar procedure, pass(this), private :: divr_cscalar => spin_divr_cscalar ! Specific implementations of exponentiation procedure, pass(this), private :: expr_iscalar => spin_expr_iscalar end type ! Public interfaces interface inverse module procedure spin_inv end interface interface trace module procedure spin_trace end interface interface sum module procedure spin_sum end interface interface conjg module procedure spin_conjg end interface interface norm2 module procedure spin_norm end interface ! Exported constants type(spin), parameter :: pauli0 = & spin(reshape([(1, 0), (0, 0), (0, 0), (1, 0)], [2, 2], order=[2, 1])) type(spin), parameter :: pauli1 = & spin(reshape([(0, 0), (1, 0), (1, 0), (0, 0)], [2, 2], order=[2, 1])) type(spin), parameter :: pauli2 = & spin(reshape([(0, 0), (0, -1), (0, 1), (0, 0)], [2, 2], order=[2, 1])) type(spin), parameter :: pauli3 = & spin(reshape([(1, 0), (0, 0), (0, 0), (-1, 0)], [2, 2], order=[2, 1])) type(spin), parameter, dimension(0:3) :: pauli = & [pauli0, pauli1, pauli2, pauli3] contains !--------------------------------------------------------------------------! ! SPECIFIC CONSTRUCTORS ! !--------------------------------------------------------------------------! pure function spin_cons_rscalar(other) result(this) !! Constructs a spin object from a real scalar. real(wp), intent(in) :: other type(spin) :: this this = other end function pure function spin_cons_cscalar(other) result(this) !! Constructs a spin object from a complex scalar. complex(wp), intent(in) :: other type(spin) :: this this = other end function pure function spin_cons_cmatrix(other) result(this) !! Constructs a spin object from a complex matrix. complex(wp), intent(in) :: other(2, 2) type(spin) :: this this = other end function pure function spin_cons_rvector(other) result(this) !! Constructs a spin object from a real vector. real(wp), intent(in) :: other(8) type(spin) :: this this = other end function pure function spin_cons_spin(other) result(this) !! Constructs a spin object from an existing one. type(spin), intent(in) :: other type(spin) :: this this = other end function !--------------------------------------------------------------------------! ! SPECIFIC IMPORT PROCEDURES ! !--------------------------------------------------------------------------! pure subroutine spin_assr_rscalar(this, other) !! Imports data to a spin object from a real scalar. class(spin), intent(inout) :: this real(wp), intent(in) :: other this%matrix = other*pauli0%matrix end subroutine pure subroutine spin_assr_cscalar(this, other) !! Imports data to a spin object from a complex scalar. class(spin), intent(inout) :: this complex(wp), intent(in) :: other this%matrix = other*pauli0%matrix end subroutine pure subroutine spin_assr_cmatrix(this, other) !! Imports data to a spin object from a complex matrix. class(spin), intent(inout) :: this complex(wp), intent(in) :: other(2, 2) this%matrix = other end subroutine pure subroutine spin_assr_rvector(this, other) !! Imports data to a spin object from a real vector. class(spin), intent(inout) :: this real(wp), intent(in) :: other(8) ! TODO: Rewrite this without using `cx` in the future. this%matrix = cx(reshape(other(1:7:2), [2, 2], order=[2, 1]), & reshape(other(2:8:2), [2, 2], order=[2, 1])) end subroutine !--------------------------------------------------------------------------! ! SPECIFIC EXPORT PROCEDURES ! !--------------------------------------------------------------------------! pure subroutine spin_assl_cmatrix(other, this) !! Exports data from a spin object to a complex matrix. class(spin), intent(in) :: this complex(wp), intent(out) :: other(2, 2) other = this%matrix end subroutine pure subroutine spin_assl_rvector(other, this) !! Exports data from a spin object to a real vector. class(spin), intent(in) :: this real(wp), intent(out) :: other(8) other(1:7:2) = re([this%matrix(1, :), this%matrix(2, :)]) other(2:8:2) = im([this%matrix(1, :), this%matrix(2, :)]) end subroutine !--------------------------------------------------------------------------! ! SPECIFIC EXPONENTIATION PROCEDURES ! !--------------------------------------------------------------------------! pure function spin_expr_iscalar(this, other) result(r) !! Exponentiates the spin object, where the power is a positive integer. class(spin), intent(in) :: this integer, intent(in) :: other type(spin) :: r integer :: n r = this do n = 2, other r%matrix = r%matrix*this end do end function !--------------------------------------------------------------------------! ! SPECIFIC MULTIPLICATION PROCEDURES ! !--------------------------------------------------------------------------! elemental function spin_mul_spin(this, other) result(r) !! Defines multiplication of two spin matrices. class(spin), intent(in) :: this class(spin), intent(in) :: other type(spin) :: r r%matrix = matmul(this%matrix, other%matrix) end function pure function spin_mull_rscalar(other, this) result(r) !! Defines left multiplication of a spin matrix by a real scalar. class(spin), intent(in) :: this real(wp), intent(in) :: other type(spin) :: r r%matrix = other*this%matrix end function pure function spin_mulr_rscalar(this, other) result(r) !! Defines right multiplication of a spin matrix by a real scalar. class(spin), intent(in) :: this real(wp), intent(in) :: other type(spin) :: r r%matrix = this%matrix*other end function pure function spin_mull_cscalar(other, this) result(r) !! Defines left multiplication of a spin matrix by a complex scalar. class(spin), intent(in) :: this complex(wp), intent(in) :: other type(spin) :: r r%matrix = other*this%matrix end function function spin_mulr_cscalar(this, other) result(r) !! Defines right multiplication of a spin matrix by a complex scalar. class(spin), intent(in) :: this complex(wp), intent(in) :: other type(spin) :: r r%matrix = this%matrix*other end function pure function spin_mull_cmatrix(other, this) result(r) !! Defines left multiplication of a spin matrix by a complex matrix. class(spin), intent(in) :: this complex(wp), intent(in) :: other(2, 2) type(spin) :: r r%matrix = matmul(other, this%matrix) end function pure function spin_mulr_cmatrix(this, other) result(r) !! Defines right multiplication of a spin matrix by a complex matrix. class(spin), intent(in) :: this complex(wp), intent(in) :: other(2, 2) type(spin) :: r r%matrix = matmul(this%matrix, other) end function !--------------------------------------------------------------------------! ! SPECIFIC DIVISION PROCEDURES ! !--------------------------------------------------------------------------! pure function spin_divr_rscalar(this, other) result(r) !! Defines division of a spin matrix by a real scalar. class(spin), intent(in) :: this real(wp), intent(in) :: other type(spin) :: r r%matrix = this%matrix/other end function pure function spin_divr_cscalar(this, other) result(r) !! Defines division of a spin matrix by a complex scalar. class(spin), intent(in) :: this complex(wp), intent(in) :: other type(spin) :: r r%matrix = this%matrix/other end function !--------------------------------------------------------------------------! ! SPECIFIC ADDITION PROCEDURES ! !--------------------------------------------------------------------------! elemental function spin_add_spin(this, other) result(r) !! Defines addition of two spin matrices. class(spin), intent(in) :: this class(spin), intent(in) :: other type(spin) :: r r%matrix = this%matrix + other%matrix end function pure function spin_addl_rscalar(other, this) result(r) !! Defines left addition of a spin matrix and a real scalar. class(spin), intent(in) :: this real(wp), intent(in) :: other type(spin) :: r r%matrix = other*pauli0%matrix + this%matrix end function pure function spin_addr_rscalar(this, other) result(r) !! Defines right addition of a spin matrix and a real scalar. class(spin), intent(in) :: this real(wp), intent(in) :: other type(spin) :: r r%matrix = this%matrix + other*pauli0%matrix end function pure function spin_addl_cscalar(other, this) result(r) !! Defines left addition of a spin matrix and a complex scalar. class(spin), intent(in) :: this complex(wp), intent(in) :: other type(spin) :: r r%matrix = other*pauli0%matrix + this%matrix end function pure function spin_addr_cscalar(this, other) result(r) !! Defines right addition of a spin matrix and a complex scalar. class(spin), intent(in) :: this complex(wp), intent(in) :: other type(spin) :: r r%matrix = this%matrix + other*pauli0%matrix end function pure function spin_addl_cmatrix(other, this) result(r) !! Defines left addition of a spin matrix and a complex matrix. class(spin), intent(in) :: this complex(wp), intent(in) :: other(2, 2) type(spin) :: r r%matrix = other + this%matrix end function pure function spin_addr_cmatrix(this, other) result(r) !! Defines right addition of a spin matrix and a complex matrix. class(spin), intent(in) :: this complex(wp), intent(in) :: other(2, 2) type(spin) :: r r%matrix = this%matrix + other end function !--------------------------------------------------------------------------! ! SPECIFIC SUBTRACTION PROCEDURES ! !--------------------------------------------------------------------------! elemental function spin_sub_spin(this, other) result(r) !! Defines subtraction of two spin matrices. class(spin), intent(in) :: this class(spin), intent(in) :: other type(spin) :: r r%matrix = this%matrix - other%matrix end function pure function spin_subl_rscalar(other, this) result(r) !! Defines left subtraction of a spin matrix and a real scalar. class(spin), intent(in) :: this real(wp), intent(in) :: other type(spin) :: r r%matrix = other*pauli0%matrix - this%matrix end function pure function spin_subr_rscalar(this, other) result(r) !! Defines right subtraction of a spin matrix and a real scalar. class(spin), intent(in) :: this real(wp), intent(in) :: other type(spin) :: r r%matrix = this%matrix - other*pauli0%matrix end function pure function spin_subl_cscalar(other, this) result(r) !! Defines left subtraction of a spin matrix and a complex scalar. class(spin), intent(in) :: this complex(wp), intent(in) :: other type(spin) :: r r%matrix = other*pauli0%matrix - this%matrix end function pure function spin_subr_cscalar(this, other) result(r) !! Defines right subtraction of a spin matrix and a complex scalar. class(spin), intent(in) :: this complex(wp), intent(in) :: other type(spin) :: r r%matrix = this%matrix - other*pauli0%matrix end function pure function spin_subl_cmatrix(other, this) result(r) !! Defines left subtraction of a spin matrix and a complex matrix. class(spin), intent(in) :: this complex(wp), intent(in) :: other(2, 2) type(spin) :: r r%matrix = other - this%matrix end function pure function spin_subr_cmatrix(this, other) result(r) !! Defines right subtraction of a spin matrix and a complex matrix. class(spin), intent(in) :: this complex(wp), intent(in) :: other(2, 2) type(spin) :: r r%matrix = this%matrix - other end function !--------------------------------------------------------------------------! ! MATRIX ALGEBRA ! !--------------------------------------------------------------------------! elemental function spin_norm(this) result(r) !! Calculate the Frobenius norm of the spin matrix. class(spin), intent(in) :: this real(wp) :: r, w(8) w = this r = norm2(w) end function elemental function spin_conjg(this) result(r) !! Calculate the complex conjugate of the spin matrix. class(spin), intent(in) :: this type(spin) :: r r%matrix = conjg(this%matrix) end function elemental function spin_trace(this) result(r) !! Calculate the trace of the spin matrix. class(spin), intent(in) :: this complex(wp) :: r r = this%matrix(1, 1) + this%matrix(2, 2) end function pure function spin_inv(this) result(r) !! Calculate the inverse of the spin matrix. class(spin), intent(in) :: this type(spin) :: r r%matrix = inverse(this%matrix) end function pure function spin_sum(this) result(r) !! Calculate the sum of an array of spin matrices. class(spin), intent(in) :: this(:) type(spin) :: r integer :: n do n = 1, size(this) r%matrix = r%matrix + this(n)%matrix end do end function end module