sov-kernel-monster / src /bob_hamiltonian.f90
SNAPKITTYWEST's picture
chore: push full sov-kernel-monster content from local build
9425aed verified
Raw
History Blame Contribute Delete
11.1 kB
! BOB Quantum Civilization Engine - Hamiltonian Construction
! Module: bob_hamiltonian
! Purpose: Pauli operators, tensor products, Hamiltonian assembly for quantum simulation
! Standard: Fortran 2018
module bob_hamiltonian
use bob_kinds
use bob_errors
use bob_state
implicit none
private
! Public interface
public :: bob_hamiltonian_operator
public :: bob_pauli_matrix
public :: bob_tensor_product
public :: bob_kron
public :: bob_ising_hamiltonian
public :: bob_heisenberg_hamiltonian
public :: bob_tfim_hamiltonian
public :: bob_xy_hamiltonian
public :: bob_expectation
public :: bob_variance
public :: bob_ground_state
! Pauli matrices (2x2)
complex(cwp), parameter :: PAULI_I(2,2) = reshape([CONE, CZERO, CZERO, CONE], [2,2])
complex(cwp), parameter :: PAULI_X(2,2) = reshape([CZERO, CONE, CONE, CZERO], [2,2])
complex(cwp), parameter :: PAULI_Y(2,2) = reshape([CZERO, -CI, CI, CZERO], [2,2])
complex(cwp), parameter :: PAULI_Z(2,2) = reshape([CONE, CZERO, CZERO, -CONE], [2,2])
type, public :: bob_hamiltonian_operator
integer(i8) :: dim = 0
complex(cwp), allocatable :: matrix(:,:)
integer(i8) :: num_qubits = 0
character(len=:), allocatable :: name
logical(lk) :: is_hermitian = .true.
real(wp) :: energy_offset = ZERO
contains
procedure, public :: init => ham_init
procedure, public :: destroy => ham_destroy
procedure, public :: add_term => ham_add_term
procedure, public :: build_matrix => ham_build_matrix
procedure, public :: expectation => ham_expectation
procedure, public :: ground_state => ham_ground_state
end type bob_hamiltonian_operator
contains
!> Get Pauli matrix by name
pure function bob_pauli_matrix(name) result(mat)
character(*), intent(in) :: name
complex(cwp) :: mat(2,2)
select case (name)
case ('I','i','identity'); mat = PAULI_I
case ('X','x','sigma_x'); mat = PAULI_X
case ('Y','y','sigma_y'); mat = PAULI_Y
case ('Z','z','sigma_z'); mat = PAULI_Z
case default
call bob_set_error(BOB_ERROR_INVALID_ARGUMENT, "Unknown Pauli: "//name, "bob_pauli_matrix")
mat = CZERO
end select
end function bob_pauli_matrix
!> Kronecker product A ⊗ B
pure function bob_kron(A, B) result(C)
complex(cwp), intent(in) :: A(:,:), B(:,:)
complex(cwp), allocatable :: C(:,:)
integer :: m1, n1, m2, n2, i, j, k, l
m1 = size(A,1); n1 = size(A,2); m2 = size(B,1); n2 = size(B,2)
allocate(C(m1*m2, n1*n2)); C = CZERO
do i = 1, m1; do j = 1, n1
if (abs(A(i,j)) > TOL_NORM) then
do k = 1, m2; do l = 1, n2
C((i-1)*m2+k, (j-1)*n2+l) = A(i,j) * B(k,l)
end do; end do
end if
end do; end do
end function bob_kron
!> Tensor product: embed operator on specified qubits into full Hilbert space
function bob_tensor_product(operators, qubits, num_qubits) result(op)
complex(cwp), intent(in) :: operators(:,:,:) ! (2,2,n_ops)
integer(i8), intent(in) :: qubits(:)
integer(i8), intent(in) :: num_qubits
complex(cwp), allocatable :: op(:,:)
integer(i8) :: n_ops, i, j, target
complex(cwp), allocatable :: current(:,:), next(:,:)
n_ops = size(qubits)
if (n_ops == 0) then; allocate(op(1,1)); op = CONE; return; end if
allocate(current(1,1)); current = CONE
do i = 1, num_qubits
target = -1
do j = 1, n_ops; if (qubits(j) == i) then; target = j; exit; end if; end do
if (target > 0) then
next = bob_kron(current, operators(:,:,target))
else
next = bob_kron(current, PAULI_I)
end if
if (allocated(current)) deallocate(current)
allocate(current(size(next,1), size(next,2))); current = next
if (allocated(next)) deallocate(next)
end do
op = current
end function bob_tensor_product
subroutine ham_init(this, num_qubits, name)
class(bob_hamiltonian_operator), intent(inout) :: this
integer(i8), intent(in) :: num_qubits
character(*), intent(in) :: name
integer :: stat
this%num_qubits = num_qubits
this%dim = ishft(1_i8, int(num_qubits))
this%name = name
if (allocated(this%matrix)) deallocate(this%matrix)
allocate(this%matrix(this%dim, this%dim), stat=stat)
if (stat /= 0) call bob_set_error(BOB_ERROR_ALLOCATION, "H matrix alloc", name)
this%matrix = CZERO
end subroutine ham_init
subroutine ham_destroy(this)
class(bob_hamiltonian_operator), intent(inout) :: this
if (allocated(this%matrix)) deallocate(this%matrix)
this%dim = 0; this%num_qubits = 0
end subroutine ham_destroy
subroutine ham_add_term(this, op_matrix, coeff, qubits, term_name)
class(bob_hamiltonian_operator), intent(inout) :: this
complex(cwp), intent(in) :: op_matrix(:,:)
real(wp), intent(in) :: coeff
integer(i8), intent(in) :: qubits(:)
character(*), intent(in), optional :: term_name
complex(cwp), allocatable :: full_op(:,:)
full_op = bob_tensor_product(reshape(op_matrix, [2,2,1]), qubits, this%num_qubits)
this%matrix = this%matrix + coeff * full_op
if (allocated(full_op)) deallocate(full_op)
end subroutine ham_add_term
function ham_build_matrix(this) result(H)
class(bob_hamiltonian_operator), intent(in) :: this
complex(cwp), allocatable :: H(:,:)
allocate(H(this%dim, this%dim)); H = this%matrix
end function ham_build_matrix
function ham_expectation(this, state) result(expval)
class(bob_hamiltonian_operator), intent(in) :: this
type(bob_quantum_state), intent(in) :: state
real(wp) :: expval
complex(cwp), allocatable :: Hpsi(:)
if (.not. state%is_valid .or. state%dim /= this%dim) then
call bob_set_error(BOB_ERROR_DIMENSION_MISMATCH, "State/H dim mismatch", "ham_expectation")
expval = ZERO; return
end if
allocate(Hpsi(state%dim))
Hpsi = matmul(this%matrix, state%amplitudes)
expval = real(dot_product(conjg(state%amplitudes), Hpsi))
end function ham_expectation
function bob_variance(H, state) result(var)
complex(cwp), intent(in) :: H(:,:)
type(bob_quantum_state), intent(in) :: state
real(wp) :: var
complex(cwp), allocatable :: Hpsi(:), H2psi(:)
real(wp) :: e1, e2
allocate(Hpsi(state%dim), H2psi(state%dim))
Hpsi = matmul(H, state%amplitudes)
H2psi = matmul(H, Hpsi)
e1 = real(dot_product(conjg(state%amplitudes), Hpsi))
e2 = real(dot_product(conjg(state%amplitudes), H2psi))
var = e2 - e1*e1
end function bob_variance
!> Ground state via power iteration
function bob_ground_state(H, max_iter, tol) result(ground)
complex(cwp), intent(in) :: H(:,:)
integer, intent(in), optional :: max_iter
real(wp), intent(in), optional :: tol
type(bob_quantum_state) :: ground
integer(i8) :: dim, iter, max_i
real(wp) :: tol_v
complex(cwp), allocatable :: psi(:), psi_new(:)
real(wp) :: norm, overlap
dim = size(H,1)
call ground%init(int(log(real(dim))/log(TWO)))
max_i = 1000; if (present(max_iter)) max_i = max_iter
tol_v = 1.0e-10_wp; if (present(tol)) tol_v = tol
psi = ground%amplitudes
do iter = 1, max_i
psi_new = matmul(H, psi)
norm = sqrt(real(dot_product(conjg(psi_new), psi_new)))
if (norm > ZERO) psi_new = psi_new / norm
overlap = abs(dot_product(conjg(psi), psi_new))
psi = psi_new
if (abs(overlap - ONE) < tol_v) exit
end do
ground%amplitudes = psi; ground%is_normalized = .true.
end function bob_ground_state
!> Transverse Field Ising Model: H = -J Σ Z_i Z_{i+1} - h Σ X_i
function bob_tfim_hamiltonian(num_qubits, J, h) result(H)
integer(i8), intent(in) :: num_qubits
real(wp), intent(in) :: J, h
type(bob_hamiltonian_operator) :: H
integer(i8) :: i
complex(cwp), allocatable :: ZZ(:,:,:)
call H%init(num_qubits, "TFIM")
allocate(ZZ(2,2,2)); ZZ(:,:,1) = PAULI_Z; ZZ(:,:,2) = PAULI_Z
do i = 1, num_qubits - 1
call H%add_term(ZZ, -J, [i, i+1])
end do
do i = 1, num_qubits
call H%add_term(PAULI_X, -h, [i])
end do
end function bob_tfim_hamiltonian
!> Heisenberg Model: H = Σ (Jx X_i X_{i+1} + Jy Y_i Y_{i+1} + Jz Z_i Z_{i+1})
function bob_heisenberg_hamiltonian(num_qubits, Jx, Jy, Jz) result(H)
integer(i8), intent(in) :: num_qubits
real(wp), intent(in) :: Jx, Jy, Jz
type(bob_hamiltonian_operator) :: H
integer(i8) :: i
complex(cwp), allocatable :: XX(:,:,:), YY(:,:,:), ZZ(:,:,:)
call H%init(num_qubits, "Heisenberg")
allocate(XX(2,2,2)); XX(:,:,1)=PAULI_X; XX(:,:,2)=PAULI_X
allocate(YY(2,2,2)); YY(:,:,1)=PAULI_Y; YY(:,:,2)=PAULI_Y
allocate(ZZ(2,2,2)); ZZ(:,:,1)=PAULI_Z; ZZ(:,:,2)=PAULI_Z
do i = 1, num_qubits - 1
call H%add_term(XX, Jx, [i, i+1])
call H%add_term(YY, Jy, [i, i+1])
call H%add_term(ZZ, Jz, [i, i+1])
end do
end function bob_heisenberg_hamiltonian
!> XY Model: H = J Σ (X_i X_{i+1} + Y_i Y_{i+1}) + h Σ Z_i
function bob_xy_hamiltonian(num_qubits, J, h) result(H)
integer(i8), intent(in) :: num_qubits
real(wp), intent(in) :: J, h
type(bob_hamiltonian_operator) :: H
integer(i8) :: i
complex(cwp), allocatable :: XX(:,:,:), YY(:,:,:)
call H%init(num_qubits, "XY")
allocate(XX(2,2,2)); XX(:,:,1)=PAULI_X; XX(:,:,2)=PAULI_X
allocate(YY(2,2,2)); YY(:,:,1)=PAULI_Y; YY(:,:,2)=PAULI_Y
do i = 1, num_qubits - 1
call H%add_term(XX, J, [i, i+1])
call H%add_term(YY, J, [i, i+1])
end do
do i = 1, num_qubits
call H%add_term(PAULI_Z, h, [i])
end do
end function bob_xy_hamiltonian
function ham_ground_state(this, max_iter, tol) result(ground)
class(bob_hamiltonian_operator), intent(in) :: this
integer, intent(in), optional :: max_iter
real(wp), intent(in), optional :: tol
type(bob_quantum_state) :: ground
ground = bob_ground_state(this%matrix, max_iter, tol)
end function ham_ground_state
end module bob_hamiltonian