qutip icon indicating copy to clipboard operation
qutip copied to clipboard

Qobj.extract_states() doesn't preserve the isherm attribute

Open BenjaminDAnjou opened this issue 1 year ago • 1 comments

Bug Description

The method extract_states() of the Qobj class doesn't preserve the isherm attribute of the operators it truncates. Maybe I'm forgetting an edge case, but it seems to me that taking any subset of states from an Hermitian operator should results in an Hermitian operator.

Code to Reproduce the Bug

# Imports
import qutip as qt
import numpy as np
import scqubits as scq

# Maximum number of transmon states
k_t_max = 201
ncut = int((k_t_max-1)/2)
# Number of states to truncate to
k_t_trunc = 100


# Transmon Hamiltonian from scqubits
transmon = scq.Transmon(EJ=22.975, EC=0.194, ng=0, ncut=ncut)

# Form a qutip object
H_t = qt.Qobj(transmon.hamiltonian())

# At this stage, the Hamiltonian has the Hermitian attribute
print("Is the Hamiltonian Hermitian? Answer: {}".format(H_t.isherm))

# And the anti-Hermitian part is truly 0
diff = H_t - H_t.dag()
print("The norm of the anti-Hermitian part is {}".format(diff.norm()))

# Calculate the eigenvalues and eigenvectors
evals_t, evecs_t = H_t.eigenstates()

# Diagonalize the Hamiltonian
H_t = H_t.transform(evecs_t)

# At this stage, the Hamiltonian still has the Hermitian attribute
print("Is the Hamiltonian still Hermitian after diagonalization? Answer: {}".format(H_t.isherm))

# However, the transformation gave a residual non-Hermitian part
diff = H_t - H_t.dag()
print("The norm of the anti-Hermitian part after diagonalization is {}".format(diff.norm()))

# Truncate the Hamiltonian
H_t = H_t.extract_states(range(k_t_trunc))

# At this stage, the Hamiltonian has lost the Hermitian attribute
print("Is the Hamiltonian still Hermitian after truncation? Answer: {}".format(H_t.isherm))

# And it still has a non-zero Hermitian part
diff = H_t - H_t.dag()
print("The norm of the anti-Hermitian part after truncation is {}".format(diff.norm()))

Code Output

Is the Hamiltonian Hermitian? Answer: True
The norm of the anti-Hermitian part is 0.0
Is the Hamiltonian still Hermitian after diagonalization? Answer: True
The norm of the anti-Hermitian part after diagonalization is 1.2427378357318259e-11
Is the Hamiltonian still Hermitian after truncation? Answer: False
The norm of the anti-Hermitian part after truncation is 6.2142895453943875e-12

Expected Behaviour

Extracting a state of states from an Hermitian operator should yield an Hermitian operator.

Your Environment

QuTiP Version:      4.7.2
Numpy Version:      1.24.3
Scipy Version:      1.10.1
Cython Version:     0.29.35
Matplotlib Version: 3.7.1
Python Version:     3.10.6
Number of CPUs:     12
BLAS Info:          OPENBLAS
OPENMP Installed:   False
INTEL MKL Ext:      False
Platform Info:      Darwin (arm64)

Additional Context

No response

BenjaminDAnjou avatar Jul 19 '23 18:07 BenjaminDAnjou

Thanks for reporting this issue. It does seem to be a bug. I will take a closer look at the extract_states method and propose a change.

AGaliciaMartinez avatar Aug 04 '23 16:08 AGaliciaMartinez