Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
BenjaminDAnjou opened this issue Jul 19, 2023 · 1 comment
Closed

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

BenjaminDAnjou opened this issue Jul 19, 2023 · 1 comment
Milestone

Comments

@BenjaminDAnjou
Copy link

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

@AGaliciaMartinez
Copy link
Member

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants