qutip
qutip copied to clipboard
Qobj.extract_states() doesn't preserve the isherm attribute
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
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.