Observables

This is the training session for the preliminary understanding about QLM language for mostly in Quantum Chemistry

Class: Observable

This can be any hermitian or non-Hermitian operators

Stores a list of Pauli chains + their coefficients

$$ H\ =\ \sum_{k}^{} c_{k}P_{k}\ \text{with} \ P_{k}=I,X,Y,Z,XX,XZ,\ XYZ,... $$

Class: Term

This class contains a Pauli chain and its coefficient

 1from qat.core import Term, Observable
 2
 3# Define a term with 4 qubits and a Pauli string
 4term = Term(1.5,  # coefficient
 5            "XXYZ",  # Pauli chain for 4 qubits
 6            [0, 1, 2, 3])  # qubits on which each Pauli acts
 7
 8# Define an observable acting on 4 qubits with multiple terms
 9obs = Observable(4,  # total number of qubits
10                 pauli_terms=[Term(2.5, "ZZ", [0, 1]),
11                              Term(1.0, "YX", [2, 3]),
12                              Term(0.8, "XYZ", [0, 2, 3])])
13
14# Display the term and the observable
15print(term)
16print(obs)

Result with the Hamiltonian

$$H\ =\ 2.5\times Z_{0}Z_{1}+1\times Y_{2}X_{3}+0.8\times X_{0}Y_{2}Z_{3}$$
Term(_coeff=TNumber(is_abstract=False, type=1, int_p=None, double_p=1.5, string_p=None, matrix_p=None, serialized_p=None, complex_p=None), op='XXYZ', qbits=[0, 1, 2, 3], _do_validity_check=True)
2.5 * (ZZ|[0, 1]) +
1.0 * (YX|[2, 3]) +
0.8 * (XYZ|[0, 2, 3])

Transform to matrix representation to see that the Dense matrix is exponential in number of qubits

We can show its matrix representation for the Observable

1print(obs.to_matrix()) # a scipy sparse array
2print(obs.to_matrix(sparse=False)) # a numpy array

Dense matrix is exponential in number of qubits!

Class: Fermionic System

In the context of quantum chemistry, the hamiltonian is expressed in the fermionic second-quantized form witht the ‘$c$’ (small) for annihilation operator ‘$c^{\dag }$’ or creation operator

$$ H=\sum^{}_{p,q} h_{pq}c^{\dag }_{p}c_{q}+\frac{1}{2} \sum^{}_{p,q,r,s} h_{pqrs}c^{\dag }_{p}c^{\dag }_{q}c_{r}c_{s} $$

where $h_{pq}$ and $h_{pqrs}$ are the one and two electron integrals. The one-electron integrals are obtained from the kinetic energy and electron-nuclei interactions while the two-electron integrals are obtained from the electron-electron interactions, defined with the help of some basis functions.

1from qat.fermion import ElectronicStructureHamiltonian
2import numpy as np
3h_pq = np. array([[1., 2.],
4                    [2., 0.11]])
5h_pqrs = np.zeros ((2, 2, 2, 2))
6h_pqrs[0, 1, 0, 1] = -8.0
7ham = ElectronicStructureHamiltonian(h_pq, h_pqrs)
8print (ham)

Result with the Hamiltonian

$$H = c_0^\dagger c_0 + 2c_0^\dagger c_1 + 2c_1^\dagger c_0 + 4c_0^\dagger c_0 c_1^\dagger c_1 $$

In the Fock space representation, the operator can be transformed to the qubit space by three main common mapping methods: Jordan-Wigner , Parity and Bravyi-Kitaev found more details in this reference. . It is currently unknown which encoding method is the most noise-resilient - i.e. best for NISQ experiments. Numerical studies aiming to compare the Jordan-Wigner and Bravyi-Kitaev mappings, has found that the BK transformations was at less as efficient as the JW one, in finding the ground states of molecular systems. Most commonly, we directly use the Jordan Wigner transformation as it is the most straightforward qubit encoding; thus it is a one to one correspondence between Slater determinants and computational basis qubit states:

1ham_spin = ham.to_spin("jordan-wigner")
2print (ham_spin)
(1.5550000000000002+0j) * I^2 +
(1+0j) * (XX|[0, 1]) +
(1+0j) * (YY|[0, 1]) +
(1+0j) * (ZZ|[0, 1]) +
(-1.5+0j) * (Z|[0]) +
(-1.055+0j) * (Z|[1])

Now that we have defined the Hamiltonian in spin representatin, we can already start playing with it. We can give a try for running exact diagonalization. Firstly we can convert our Hamiltonian operator into a sparse matrix

1model_matrix_sp = ham_spin.get_matrix(sparse=True)

Since this is just a regular scipy sparse matrix, we can just use any sparse diagonalization routine in there to find the eigenstates.

1from scipy.sparse.linalg import eigsh
2eigval, eigvec = eigsh(model_matrix_sp, k = 2)
3print("eigenvalues with scipy sparse:", eigval)
4E_gs = eigval[0]

eigenvalues with scipy sparse: [5.11      2.60390825]

Reference

Made by Eviden "myQLM – Quantum Python Package"

About the author

Author's Photo
Huy Binh TRAN
Master 2 Quantum Devices at Institute Paris Polytechnic, France
LinkedIn