Digital quantum simulation for spin and fermionic systems
The qat.fermion
module contains tools for the study of spin and fermionic systems. Please see the main page
for more information on how to use the module.
Table of Contents
The Hamiltonians classes
SpinHamiltonian
, FermionHamiltonian
and
ElectronicStructureHamiltonian
are essentially Observable
classes with
additional functionalities. Let us detail the additional features they contain.
SpinHamiltonian
- class qat.fermion.hamiltonians.SpinHamiltonian(nqbits: int, terms: List[Term], constant_coeff: float = 0.0, do_clean_up: bool = True)
Implementation of a spin Hamiltonian.
- Parameters
nqbits (int) – the total number of qubits
terms (List[Term]) – the list of terms
constant_coeff (float) – constant term
- nbqbits
the total number of qubits
- Type
int
- constant_coeff
constant term
- Type
float
- matrix
the corresponding matrix (None by default, can be set by calling get_matrix method)
- Type
np.ndarray
Example
from qat.core import Term from qat.fermion import SpinHamiltonian hamiltonian = SpinHamiltonian(2, [Term(0.3, "X", [0]), Term(-0.4, "ZY", [0, 1])]) print(f"H = {hamiltonian}") print(f"H matrix: {hamiltonian.get_matrix()}")
H = 0.3 * (X|[0]) + -0.4 * (ZY|[0, 1]) H matrix: [[0. +0.j 0. +0.4j 0.3+0.j 0. +0.j ] [0. -0.4j 0. +0.j 0. +0.j 0.3+0.j ] [0.3+0.j 0. +0.j 0. +0.j 0. -0.4j] [0. +0.j 0.3+0.j 0. +0.4j 0. +0.j ]]
- copy()
Deepcopy the current class.
- Returns
Copy of the SpinHamiltonian.
- Return type
- dag() SpinHamiltonian
Compute the conjugate transpose of the Hamiltonian.
- Returns
Conjugate transpose of the SpinHamiltonian operator
- Return type
- get_matrix(sparse: bool = False) ndarray
This function returns the matrix corresponding to \(H\) in the computational basis.
- Parameters
sparse (Optional[bool]) – Whether to return in sparse representation.
False. (Defaults to) –
- Returns
The matrix of the SpinHamiltonian.
- Return type
np.ndarray
Warning
This method should not be used if the SpinHamiltonian is too large.
FermionHamiltonian
- class qat.fermion.hamiltonians.FermionHamiltonian(nqbits: int, terms: List[Term], constant_coeff: float = 0.0, do_clean_up: bool = True, normal_order: bool = True)
Implementation of a fermionic Hamiltonian.
- Parameters
nqbits (int) – The total number of qubits
terms (List[Term]) – The list of terms
constant_coeff (float) – Constant term
do_clean_up (bool, optional) – If the terms should be simplified. Default to True.
normal_order (bool, optional) – If the fermionic terms should be normal (or Wick) ordered. Default to True. True is recommended always.
- nbqbits
The total number of qubits
- Type
int
- constant_coeff
Constant term.
- Type
float
- matrix
The corresponding matrix (None by default, can be set by calling get_matrix method).
- Type
np.ndarray
- normal_order
If the fermionic terms should be normal (or Wick) ordered.
- Type
bool
Note
Fermionic Hamiltonians are by default automatically normally ordered.
Example
from qat.core import Term from qat.fermion import FermionHamiltonian hamiltonian = FermionHamiltonian(2, [Term(0.3, "Cc", [0, 1]), Term(1.4, "CcCc", [0, 1, 1, 0])]) print(f"H = {hamiltonian}") print(f"H matrix: {hamiltonian.get_matrix()}")
H = 0.3 * (Cc|[0, 1]) + 1.4 * (Cc|[0, 0]) + 1.4 * (CCcc|[0, 1, 0, 1]) H matrix: [[0. +0.j 0. +0.j 0. +0.j 0. +0.j] [0. +0.j 0. +0.j 0. +0.j 0. +0.j] [0. +0.j 0.3+0.j 1.4+0.j 0. +0.j] [0. +0.j 0. +0.j 0. +0.j 0. +0.j]]
- copy()
Deepcopy the current class.
- Returns
Copy of the FermionHamiltonian.
- Return type
- dag() FermionHamiltonian
Compute the conjugate transpose of the Hamiltonian.
- Returns
Conjugate transpose of the Hamiltonian.
- Return type
- get_matrix(sparse: bool = False) ndarray
This function returns the matrix corresponding to \(H\) in the computational basis.
- Parameters
sparse (Optional[bool]) – Whether to return in sparse representation.
False. (Defaults to) –
- Returns
The matrix of the FermionHamiltonian.
- Return type
numpy.ndarray
Warning
This method should not be used if the Hamiltonian is too large.
- to_electronic()
Converts a fermionic Hamiltonian to a electronic-structure Hamiltonian. This can be done only if the Hamiltonian contains only single and double interaction operators (i.e. only “Cc” and “CCcc” fermionic operators).
- Returns
Electronic-structure Hamiltonian.
- Return type
- to_spin(method: Optional[str] = 'jordan-wigner')
Maps the fermionic Hamiltonian to a spin Hamiltonian.
- Parameters
method (str, optional) –
Method to use for the transformation to a spin representation. Available methods are :
”jordan-wigner” : Jordan-Wigner transform (default),
”bravyi-kitaev” : Bravyi-Kitaev transform,
”parity” : Parity transform.
- Returns
Hamiltonian in spin representation.
- Return type
ElectronicStructureHamiltonian
- class qat.fermion.hamiltonians.ElectronicStructureHamiltonian(hpq: ndarray, hpqrs: Optional[ndarray] = None, constant_coeff: float = 0.0, do_clean_up: bool = True)
A container for the electronic-structure Hamiltonian, defined as
\[H = \sum_{pq} h_{pq}a_p^\dagger a_q + \frac{1}{2} \sum_{pqrs} h_{pqrs}a_p^\dagger a_q^\dagger a_r a_s + c \mathbb{I}\]- Parameters
hpq (np.ndarray) – Array \(h_{pq}\). Must be 2D.
hpqrs (np.ndarray) – Array \(h_{pqrs}\). Must be 4D.
constant_coeff (float) – Constant coefficient \(c.\)
- hpq
Array \(h_{pq}\).
- Type
np.ndarray
- hpqrs
Array \(h_{pqrs}\).
- Type
np.ndarray
- constant_coeff
Constant coefficient \(c\).
- Type
float
Example
import numpy as np from qat.fermion import ElectronicStructureHamiltonian h_pq = 0.2 * np.array([[0, 1], [1, 0]]) h_pqrs = np.zeros((2, 2, 2, 2)) h_pqrs[0, 1, 1, 0] = 0.7 h_pqrs[1, 0, 0, 1] = 0.7 hamiltonian = ElectronicStructureHamiltonian(h_pq, h_pqrs, -6) print(f"H = {hamiltonian}") eigvals = np.linalg.eigvalsh(hamiltonian.get_matrix()) print(f"eigenvalues = {eigvals}")
H = -6 * I^2 + 0.2 * (Cc|[0, 1]) + 0.2 * (Cc|[1, 0]) + -0.7 * (CCcc|[0, 1, 0, 1]) eigenvalues = [-6.2 -6. -5.8 -5.3]
- copy()
Deepcopy the current class.
- Returns
Copy of the ElectronicStructureHamiltonian.
- Return type
- dag() ElectronicStructureHamiltonian
Compute the conjugate transpose of the Hamiltonian.
- Returns
Conjugate transpose of the Hamiltonian.
- Return type
- get_matrix(sparse: bool = False) ndarray
This function returns the matrix corresponding to \(H\) in the computational basis.
- Parameters
sparse (Optional[bool]) – Whether to return in sparse representation.
False. (Defaults to) –
- Returns
The matrix of the FermionHamiltonian.
- Return type
numpy.ndarray
Warning
This method should not be used if the Hamiltonian is too large.
- to_fermion() FermionHamiltonian
Convert current ElectronicStructureHamiltonian to a FermionHamiltonian.
- Returns
Fermionic Hamiltonian.
- Return type
- to_spin(method: Optional[str] = 'jordan-wigner')
Maps the fermionic Hamiltonian to a spin Hamiltonian.
- Parameters
method (str, optional) –
Method to use for the transformation to a spin representation. Available methods are :
”jordan-wigner” : Jordan-Wigner transform (default),
”bravyi-kitaev” : Bravyi-Kitaev transform,
”parity” : Parity transform.
- Returns
Hamiltonian in spin representation.
- Return type
Atomic and molecular studies study
MolecularHamiltonian
- class qat.fermion.chemistry.wrapper.MolecularHamiltonian(one_body_integrals: ndarray, two_body_integrals: ndarray, constant_coeff: ndarray)
MolecularHamiltonian helper class. It represents the electronic-structure Hamiltonian defined using one- and two-body integrals.
This electronic-structure Hamiltonian is defined by:
\[H=\sum_{uv\sigma}I_{uv}c^{\dagger}_{u\sigma}c_{v\sigma}+\frac{1}{2}\sum_{uvwx}\sum_{\sigma \sigma'} I_{uvwx}c^{\dagger}_{u\sigma}c^{\dagger}_{v\sigma'}c_{w\sigma'}c_{x\sigma}+r\mathbb{I}\]with \(r\) the core repulsion constant, and with \(I_{uv}\) and \(I_{uvwx}\) the one- and two-body integrals defined by:
\[ \begin{align}\begin{aligned}I_{uv} = \int dr \phi^{*}_{u}(r)h_{1}[\phi_{v}(r)]\\I_{uvwx} = \int dr dr' \phi^{*}_{u}(r)\phi^{*}_{v}(r')v[\phi_{w}(r)\phi_{x}(r')]\end{aligned}\end{align} \]Here, \(\{\phi_{i}(r)\}_{i=0...N-1}\) is the single-particle basis, with \(N\) the size, which depends on the basis chosen. \(h_{1} = h_{kin} + h_{pot}\) is the one-body Hamiltonian, and \(v\) the Coulomb operator.
Note
This electronic-structure Hamiltonian definition is different than the one used in
ElectronicStructureHamiltonian
.- Parameters
one_body_integrals (np.ndarray) – One-body integral \(I_{uv}\).
two_body_integrals (np.ndarray) – Two-body integral \(I_{uvwx}\).
constant_coeff (np.ndarray) – Constant coefficient \(r\) (core repulsion).
- nqbits
The total number of qubits.
- Type
int
- one_body_integrals
One-body integral \(I_{uv}\).
- Type
np.ndarray
- two_body_integrals
Two-body integral \(I_{uvwx}\).
- Type
np.ndarray
- constant_coeff
Constant coefficient \(r\) (core repulsion).
- Type
np.ndarray
Example
import numpy as np from qat.fermion.chemistry import MolecularHamiltonian # Initialize random one- and two-body integrals, and a constant one_body_integral = np.random.randn(2, 2) two_body_integral = np.random.randn(2, 2, 2, 2) constant = np.random.rand() # Define the MolecularHamiltonian mol_h = MolecularHamiltonian(one_body_integral, two_body_integral, constant) print(mol_h)
MolecularHamiltonian( - constant_coeff : 0.4458217765541531 - integrals shape * one_body_integrals : (2, 2) * two_body_integrals : (2, 2, 2, 2) )
- get_electronic_hamiltonian() ElectronicStructureHamiltonian
Converts the MolecularHamiltonian to an ElectronicStructureHamiltonian. To do so, it converts from \(I_{uv},I_{uvwx}\) to \(h_{pq},h_{pqrs}\), with
\[ \begin{align}\begin{aligned}h_{u\sigma, v\sigma'} = I_{u, v} \delta_{\sigma, \sigma'}\\h_{u\sigma_1, v\sigma_2, w\sigma_2', x\sigma_1'} = I_{uvwx} \left((1-\delta_{\sigma,\sigma'}) + \delta_{\sigma,\sigma'} (1-\delta_{u,v})(1-\delta_{w,x}) \right)\end{aligned}\end{align} \]and where the one- and two-body integrals are defined as:
\[I_{uv}\equiv(u|h|v)=\int\mathrm{d}r\phi_{u}^{*}(r)T\phi_{v}(r)\]\[I_{uvwx}\equiv(ux|vw)=\iint\mathrm{d}r_{1}\mathrm{d}r_{2}\phi_{u}^{*}(r_{1})\phi_{x}(r_{1})v(r_{12})\phi_{v}^{*}(r_{2})\phi_{w}(r_{2})\]with \(T\) (resp. \(v\)) the one- (resp. two-) body potentials, and \(\phi_u(r)\) is the molecular orbital wavefunction.
The \(h\) integrals are used to construct hamiltonians of the ElectronicStructureHamiltonian type.
- Returns
ElectronicStructureHamiltonian
Electronic structure hamiltonian.
- select_active_space(noons: List[float], n_electrons: int, threshold_1: Optional[float] = 0.02, threshold_2: Optional[float] = 0.001) Tuple[MolecularHamiltonian, List[int], List[int]]
Selects the right active space and freezes core electrons according to their NOONs \(n_i\).
This function is an implementation of the Complete Active Space (CAS) approach. It divides orbital space into sets of active and inactive orbitals, the occupation number of the latter remaining unchanged during the computation.
The active space indices are defined as:
\[\mathcal{A} = \{i, n_i \in [\varepsilon_2, 2 - \varepsilon_1[\} \cup \{i, n_i \geq 2-\varepsilon_1, 2(i+1)\geq N_e \}\]The inactive occupied orbitals are defined as:
\[\mathcal{O} = \{i, n_i \geq 2 -\varepsilon_1, 2(i+1) < N_e \}\]The restriction of the one- and two-body integrals (and update of the core energy) is then carried out according to:
\[\forall u,v \in \mathcal{A},\; I^{(a)}_{uv} = I_{uv} + \sum_{i\in \mathcal{O}} 2 I_{i,u,v,i} - I_{i,u,i,v}\]\[\forall u,v,w,x \in \mathcal{A}, I^{(a)}_{uvwx} = I_{uvwx}\]\[E_\mathrm{core}^{(a)} = E_\mathrm{core} + \sum_{i\in\mathcal{O}} I_{ii} + \sum_{ij\in\mathcal{O}} 2 I_{ijji} - I_{ijij}\]- Parameters
noons (List[float]) – the natural-orbital occupation numbers \(n_i\), sorted in descending order (from high occupations to low occupations)
n_electrons (int) – The number of electrons \(N_e\).
threshold_1 (Optional[float]) – The upper threshold \(\varepsilon_1\) on the NOON of an active orbital.
threshold_2 (Optional[float]) – The lower threshold \(\varepsilon_2\) on the NOON of an active orbital.
- Returns
the molecular Hamiltonian in active space \(H^{(a)}\)
the list of indices corresponding to the active orbitals, \(\mathcal{A}\)
the list of indices corresponding to the occupied orbitals, \(\mathcal{O}\)
- Return type
Tuple[MolecularHamiltonian, List[int], List[int]]
- transform_basis(transformation_matrix: ndarray) MolecularHamiltonian
Change one and two body integrals (indices p, q…) to new basis (indices i, j…) using transformation U such that
\[\hat{c}_{i}=\sum_{q}U_{qi}c_{q}\]i.e
\[ \begin{align}\begin{aligned}\hat{I}_{ij} =\sum_{pq}U_{pi}I_{pq}U_{jq}^{\dagger}\\\hat{I}_{ijkl}=\sum_{pqrs}U_{pi}U_{qj}I_{pqrs}U_{kr}^{\dagger}U_{ls}^{\dagger}\end{aligned}\end{align} \]- Parameters
transformation_matrix (np.array) – transformation matrix \(U\)
- Returns
MolecularHamiltonian updated to the new basis.
- Return type
molecular_hamiltonian (MolecularHamiltonian)
MoleculeInfo
- class qat.fermion.chemistry.wrapper.MoleculeInfo(hamiltonian: MolecularHamiltonian, n_electrons: int, noons: Union[ndarray, List[float]], orbital_energies: ndarray)
MoleculeInfo helper class. This class is a even higher level version of the
MolecularHamiltonian
.- Parameters
hamiltonian (MolecularHamiltonian) – The MolecularHamiltonian of the studied molecule.
n_electrons (int) – Number of electrons.
noons (Union[np.ndarray, List[float]]) – Natural orbital occupation number.
orbital_energies (np.ndarray) – Orbital energies.
- nqbits
The total number of qubits.
- Type
int
- one_body_integrals
One-body integrals \(I_{uv}\).
- Type
np.ndarray
- two_body_integrals
Two-body integrals \(I_{uvwx}\).
- Type
np.ndarray
- constant_coeff
Constant coefficient \(r\) (core repulsion).
- Type
np.ndarray
- hamiltonian
The
MolecularHamiltonian
of the studied molecule.- Type
- n_electrons
Number of electrons.
- Type
int
- noons
Natural orbital occupation number.
- Type
Union[np.ndarray, List[float]]
- orbital_energies
Orbital energies.
- Type
np.ndarray
Example
import numpy as np from qat.fermion.chemistry import MolecularHamiltonian, MoleculeInfo # For illustration purpose, initialize random one- and two-body integrals, and a constant one_body_integral = np.random.randn(2, 2) two_body_integral = np.random.randn(2, 2, 2, 2) constant = np.random.rand() noons = list(np.random.randn(10)) orbital_energies = list(np.random.randn(10)) # Define the MolecularHamiltonian mol_h = MolecularHamiltonian(one_body_integral, two_body_integral, constant) # Define MoleculeInfo molecule = MoleculeInfo( mol_h, n_electrons=4, noons=noons, orbital_energies=orbital_energies ) print(molecule)
MoleculeInfo( - MolecularHamiltonian( * constant_coeff : 0.39602295629162243 * integrals shape ** one_body_integrals : (2, 2) ** two_body_integrals : (2, 2, 2, 2) ) - n_electrons = 4 - noons = [-0.186582129027263, -0.6319046952566567, 1.2045296799168843, -0.3710105342909814, 0.06325102218392561, -0.9871636300821159, 2.223023481244258, 1.1106468318529636, -0.6471906814774011, 0.3262667857408898] - orbital energies = [1.7337245287275505, -0.24174492479485374, -0.4590523786306649, 0.4280186393763065, 1.925966057671262, -0.12121361475661792, -0.4346778898905092, -0.4371028614926137, 0.9183126448475859, -0.6436276083065122] )
- restrict_active_space(threshold_1: Optional[float] = 0.02, threshold_2: Optional[float] = 0.001)
Same method as the
MolecularHamiltonian
methodselect_active_space()
, except it also modifies all the molecule parameters accordingly (NOONs, orbital energies, and number of electrons).For more information, see
select_active_space()
documentation.- Parameters
threshold_1 (Optional[float]) – The upper threshold \(\varepsilon_1\) on the NOON of an active orbital.
threshold_2 (Optional[float]) – The lower threshold \(\varepsilon_2\) on the NOON of an active orbital.
Common many-body Hamiltonians
We present here Hamiltonian constructors for common many-body Hamiltonians.
The Hubbard model
- qat.fermion.hamiltonians.make_hubbard_model(t_mat: ndarray, U: float, mu: float) ElectronicStructureHamiltonian
Constructs Hubbard model
\[H = \sum_{ij,\sigma} t_{ij} c^\dagger_i c_j + U \sum_i n_{i\uparrow} n_{i \downarrow} - \mu \sum_i n_i\]- Parameters
t_mat (np.ndarray) – Hopping matrix (n_sites x n_sites).
U (float) – Hubbard U.
mu (float) – Chemical potential.
- Returns
The Hubbard Hamiltonian.
- Return type
Notes
Spin-orbital labeling convention: \(i \equiv (k, \sigma) = 2 k + \sigma\) with \(i\): site index and \(\sigma\): spin index.
The single-impurity Anderson Model
- qat.fermion.hamiltonians.make_anderson_model(u: float, mu: float, v: ndarray, epsilon: ndarray) ElectronicStructureHamiltonian
Returns the canonical second quantized form
\[H_{\mathrm{CSQ}} = \sum_{p,q} h_{pq} f_p^\dagger f_q + \frac{1}{2}\sum_{p,q,r,s} h_{pqrs} f_p^\dagger f_q^\dagger f_r f_s\]of a single impurity coupled with \(n_b\) bath modes Anderson model Hamiltonian
\[\begin{split}H_{\mathrm{SIAM}} = U c_{\uparrow}^\dagger c_{\uparrow} c_{\downarrow}^\dagger c_{\downarrow} - \mu(c_{\uparrow}^\dagger c_{\uparrow}+c_{\downarrow}^\dagger c_{\downarrow}) + \sum_{i=1..n_b} \sum_{\sigma=\uparrow,\downarrow} V_i (c_{\sigma}^\dagger a_{i,\sigma} + \mathrm{h.c.}) \\ + \sum_{i=1..n_b} \sum_{\sigma=\uparrow,\downarrow} \epsilon_i a_{i,\sigma}^\dagger a_{i,\sigma}.\end{split}\]- Parameters
U (float) – Coulomb repulsion intensity.
mu (float) – Chemical potential.
V (np.ndarray) – Tunneling energies. This vector has the same size as the number of bath mode.
epsilon (np.ndarray) – Bath modes energies. This vector has the same size as the number of bath mode.
- Returns
ElectronicStructureHamiltonian
object constructed from \(h_{pq}\) (matrix of size \((2n_b+2) \times (2n_b+2)\)) and \(h_{pqrs}\) (4D tensor with size \(2n_b+2\) in each dimension)
Note
Convention: \(f_0\) corresponds to \(c_{\uparrow}\) (annihilation in the ‘up’ mode of the impurity), \(f_1\) corresponds to \(c_{\downarrow}\) (annihilation in the ‘down’ mode of the impurity), \(f_2\) corresponds to \(a_{1,\uparrow}\) (annihilation in the ‘up’ mode of the 1st bath mode), \(f_3\) corresponds to \(a_{1,\downarrow}\) (annihilation in the ‘down’ mode of the 1st bath mode), and so on.
The generalized impurity Hamiltonian
- qat.fermion.hamiltonians.make_embedded_model(u: float, mu: float, D: ndarray, lambda_c: ndarray, t_loc: Optional[ndarray] = None, int_kernel: Optional[ndarray] = None, grouping: Optional[str] = 'spins') ElectronicStructureHamiltonian
Returns the canonical second quantized form
\[H_{\mathrm{CSQ}} = \sum_{p,q} h_{pq} f_p^\dagger f_q + \frac{1}{2}\sum_{p,q,r,s} h_{pqrs} f_p^\dagger f_q^\dagger f_r f_s + c\mathbb{I}\]of an embedded hamiltonian
\[\begin{split}H_{\mathrm{emb}} = U \sum \limits_{i,j,k,l=1}^{2M} I_{ijkl} f^{\dagger}_i f_j f^{\dagger}_k f_l - \mu \sum \limits_{i=1}^{M} f^{\dagger}_{i} f_{j} + \sum \limits_{i, j=1}^{M} t^{\mathrm{loc}}_{ij} f^{\dagger}_i f_j \\ + \sum \limits_{i,j=1}^{M} (D_{ij} f^{\dagger}_{i} f_{M+j} + \mathrm{h.c.}) \\ + \sum \limits_{i,j=1}^{M} \lambda^c_{ij} f_{M+i} f^{\dagger}_{M+j}\end{split}\]where \(M\) is the number of orbitals (imp+bath). Indices here correspond to the spin-orbitals ordering referred to as ‘cluster’ (see below).
- Parameters
U (float) – Onsite repulsion on impurity sites.
mu (float) – Chemical potential.
D (np.ndarray) – Hopping matrix (i.e. hybridization) between the correlated orbitals and the uncorrelated bath.
lambda_c (np.ndarray) – Hopping matrix of the uncorrelated sites.
t_loc (Optional[np.ndarray]) – Hopping matrix of the correlated sites.
int_kernel (Optional[np.ndarray]) – Array \(I\) with 1 at position \(i, j, k, l\) where \(U\) must be put (conv. for associated term: \(c^{\dagger}c^{\dagger}cc\)). Defaults to None, in which case \(U\) is put before terms \(c^{\dagger}_{2i}c^{\dagger}_{2i+1}c_{2i}c_{2i+1}, i=1..M/2\) if grouping is ‘clusters’, \(c^{\dagger}_{i}c^{\dagger}_{i+M}c_{i}c_{i+M}, i=1..M/2\) if grouping is ‘spins’. This array must be a 4D array.
grouping (Optional[str]) – Defines how spin-orbitals indices are ordered (see below), defaults to ‘spins’.
- Returns
The two grouping strategies are the following:
“clusters”: the first \(M\) orbitals SO are \((\uparrow, \mathrm{imp}_0), (\downarrow, \mathrm{imp}_0),..., (\uparrow, \mathrm{imp}_{M-1}), (\downarrow, \mathrm{imp}_{M-1})\) and the last \(M\) orbitals are bath orbitals with similar ordering.
“spins”: the first \(M\) orbitals are \((\uparrow, \mathrm{imp}_0), (\uparrow, \mathrm{imp}_1), ..., (\uparrow, \mathrm{bath}_{M-2}), (\uparrow, \mathrm{bath}_{M-1})\) and the last \(M\) orbitals are down orbitals with similar ordering.
The spin-fermion transforms
Jordan-Wigner transform
- qat.fermion.transforms.transform_to_jw_basis(fermion_hamiltonian: Union[FermionHamiltonian, ElectronicStructureHamiltonian]) SpinHamiltonian
Transform to Jordan-Wigner (JW) basis.
- Parameters
fermion_hamiltonian (Union[FermionHamiltonian, ElectronicStructureHamiltonian]) – The fermionic hamiltonian.
- Returns
Hamiltonian in spin representation.
- Return type
Examples:
from qat.core import Term from qat.fermion import FermionHamiltonian from qat.fermion.transforms import transform_to_jw_basis hamiltonian = FermionHamiltonian( 2, [Term(0.3, "Cc", [0, 1]), Term(1.4, "CcCc", [0, 1, 1, 0])]) spin_hamiltonian = transform_to_jw_basis(hamiltonian) print(f"H = {hamiltonian} \n") print(f"H(spin) = {spin_hamiltonian}")
H = 0.3 * (Cc|[0, 1]) + 1.4 * (Cc|[0, 0]) + 1.4 * (CCcc|[0, 1, 0, 1]) H(spin) = (0.35+0j) * I^2 + -0.075j * (YX|[0, 1]) + (0.075+0j) * (YY|[0, 1]) + (0.075+0j) * (XX|[0, 1]) + 0.075j * (XY|[0, 1]) + (-0.35+0j) * (ZZ|[0, 1]) + (-0.35+0j) * (Z|[0]) + (0.35+0j) * (Z|[1])
Bravyi-Kitaev transform
- qat.fermion.transforms.transform_to_bk_basis(fermion_hamiltonian: Union[FermionHamiltonian, ElectronicStructureHamiltonian]) SpinHamiltonian
Transform to Bravyi-Kitaev (BK) basis.
- Parameters
fermion_hamiltonian (Union[FermionHamiltonian, ElectronicStructureHamiltonian]) – The fermionic hamiltonian.
- Returns
Hamiltonian in BK spin representation.
- Return type
Examples:
from qat.core import Term from qat.fermion import FermionHamiltonian from qat.fermion.transforms import transform_to_bk_basis hamiltonian = FermionHamiltonian( 2, [Term(0.3, "Cc", [0, 1]), Term(1.4, "CcCc", [0, 1, 1, 0])]) spin_hamiltonian = transform_to_bk_basis(hamiltonian) print(f"H = {hamiltonian} \n") print(f"H(spin) = {spin_hamiltonian}")
H = 0.3 * (Cc|[0, 1]) + 1.4 * (Cc|[0, 0]) + 1.4 * (CCcc|[0, 1, 0, 1]) H(spin) = (0.35+0j) * I^2 + -0.075j * (Y|[0]) + (-0.075+0j) * (XZ|[0, 1]) + (0.075+0j) * (X|[0]) + 0.075j * (YZ|[0, 1]) + (-0.35+0j) * (Z|[1]) + (-0.35+0j) * (Z|[0]) + (0.35+0j) * (ZZ|[0, 1])
Parity basis transform
- qat.fermion.transforms.transform_to_parity_basis(fermion_hamiltonian: Union[FermionHamiltonian, ElectronicStructureHamiltonian]) SpinHamiltonian
Transform to parity basis.
- Parameters
fermion_hamiltonian (Union[FermionHamiltonian, ElectronicStructureHamiltonian]) – The fermionic hamiltonian.
- Returns
Hamiltonian in parity spin representation.
- Return type
Examples:
from qat.core import Term from qat.fermion import FermionHamiltonian from qat.fermion.transforms import transform_to_parity_basis hamiltonian = FermionHamiltonian( 2, [Term(0.3, "Cc", [0, 1]), Term(1.4, "CcCc", [0, 1, 1, 0])]) spin_hamiltonian = transform_to_parity_basis(hamiltonian) print(f"H = {hamiltonian} \n") print(f"H(spin) = {spin_hamiltonian}")
H = 0.3 * (Cc|[0, 1]) + 1.4 * (Cc|[0, 0]) + 1.4 * (CCcc|[0, 1, 0, 1]) H(spin) = (0.35+0j) * I^2 + -0.075j * (Y|[0]) + (-0.075+0j) * (XZ|[0, 1]) + (0.075+0j) * (X|[0]) + 0.075j * (YZ|[0, 1]) + (-0.35+0j) * (Z|[1]) + (-0.35+0j) * (Z|[0]) + (0.35+0j) * (ZZ|[0, 1])
Fermionic ansatz circuits
Low-Depth Circuit Ansatz (LDCA)
- qat.fermion.circuits.make_ldca_circ(nb_fermionic_modes: int, ncycles: int, eigstate_ind: Optional[int] = 0, slater: Optional[bool] = False) Circuit
Construct a LDCA circuit (see article by P. Dallaire-Demers et al. (2019)), applying ncycles layers of matchgates routines on nb_fermionic_modes qubits.
- Parameters
nb_fermionic_modes (int) – Number of qubits.
ncycles (int) – Number of LDCA cycles.
eigstate_ind (int, optional) – Eigenstate index. Defaults to 0.
slater (Optional[bool]) – Whether to only include excitation-preserving rotations. Defaults to False.
- Returns
Multi-Reference (MR) ansatz
- qat.fermion.circuits.make_mr_circ() Circuit
Builds a small, one-parameter Multi-Reference (MR) circuit on 4 qubits inspired from Sugisaki et al. article (2019) to prepare states in natural orbitals.
- Returns
Multi-Reference, Excitation-Preserving (MREP) ansatz
- qat.fermion.circuits.make_mrep_circ(n_fsim_cycles: Optional[int] = 4, set_phi_to_0: Optional[bool] = False) Circuit
Constructs the 8-qubit Multi-Reference Excitation Preserving (MREP) ansatz that combines the multi-reference routine of Sugisaki et al. article (2019) with some fSim nearest-neighbour cycles. The second angles of the fSim gates (phi) may be taken to 0.
- Parameters
n_fsim_cycles (int, optional) – Number of fSim cycles, defaults to 4.
set_phi_to_0 (bool, optional) – Whether to set all second angles in the fSim gates to 0 (True) or not (False). Defaults to False.
- Returns
General hardware-efficient ansatz
- qat.fermion.circuits.make_general_hwe_circ(nqbits: int, n_cycles: int = 1, rotation_gates: ~typing.Optional[~typing.List[~qat.lang.AQASM.gates.Gate]] = None, entangling_gate: ~qat.lang.AQASM.gates.Gate = <qat.lang.AQASM.gates.PredefGate object>) Circuit
Constructs an ansatz made of \(n_{\mathrm{cycles}}\) layers of so-called thinly-dressed routines, that is to say entanglers surrounded by four one-qubit rotations are applied on nearest-neighbour qubits in an odd/even alternating pattern.
This circuit is typically of the hardware-efficient class.
- Parameters
nqbits (int) – Number of qubits of the circuit.
n_cycles (int) – Number of layers.
rotation_gates (List[Gate]) – Parametrized rotation gates to include around the entangling gate. Defaults to \(RY\). Must be of arity 1.
entangling_gate (Gate) – The 2-qubit entangler. Must be of arity 2. Defaults to \(CNOT\).
- Returns
The 8-parameter circuit ansatz
- qat.fermion.circuits.make_shallow_circ() Circuit
Builds the 8-parameter circuit proposed in Keen et al. article (2019). This is a 4-qubit circuit.
- Returns
Compressed LDCA ansatz (only for QLM users)
- qat.fermion.circuits.make_compressed_ldca_circ(nb_fermionic_modes: int, ncycles: int, eigstate_ind: Optional[int] = 0, slater: Optional[bool] = False) Circuit
Builds a compressed version of the LDCA ansatz circuit.
The new pattern was obtained using qat.synthopline.
- Parameters
nb_fermionic_modes (int) – Number of qubits.
ncycles (int) – Number of LDCA cycles.
eigstate_ind (Optional[int]) – Eigenstate index. Defaults to 0.
slater (Optional[bool]) – Whether to only include excitation-preserving rotations. Defaults to False.
Return:
Circuit
Quantum phase estimation
- qat.fermion.phase_estimation.perform_phase_estimation(H_el: ElectronicStructureHamiltonian, n_phase_bits: int, n_trotter_steps: int, init_vec: Optional[str] = None, n_adiab_steps: Optional[int] = 0, E_target: Optional[float] = 0, size_interval: Optional[float] = 2.0, basis_transform: Optional[str] = 'jordan-wigner', qpu=None, n_shots: Optional[int] = 0, verbose: Optional[bool] = False) Tuple[float, float]
Perform quantum phase estimation (QPE) on an
ElectronicStructureHamiltonian
. This Hamiltonian is transformed to the computational basis via a Jordan-Wigner transformation and approximated via first order trotterization. Other transformations like parity and Bravyi-Kitaev are also possible.When providing an initial state one can specify it either as a string composed of zeros and ones, or as a
QRoutine
which will produce it. The QPE is meant to start from an eigenstate of the Hamiltonian, however, knowing apriori even one eigenstate of the system may be challenging. Therefore, this function comes with adiabatic state preparation - an optional preliminary step to create an eigenstate of the Hamiltonian \(H\). This step consists in performing QPEn_adiab_steps
number of times, but not to read the phase bits (it is set to only one), but rather to collapse the system to an eigenstate (read from the data bits). The first of the series of QPE executions starts from the lowest energy eigenstate of the Hamiltonian composed of \(h_{pq}\). Then, \(h_{pq}\) is linearly transformed to \(H\) and at each new step we start from the eigenstate of the Hamiltonian of the previous step. This guarantees that when the main QPE routine starts, it will do so from an eigenstate of the full \(H\).Usually, energies lie outside the range \((-\frac{2\pi}{t}, 0)\). However, this range can be adjusted by searching inside the window \((E_{target} - \frac{\Delta}{2}, E_{target} + \frac{\Delta}{2})\) with \(E_{target}\) and \(\Delta\) specified by
E_target
andsize_interval
, respectively. It is suggested to always start from a large size interval and unbiased target energy like \(0\) thus enclosing many of the eigenenergies including the desired one. One can then narrow the window around an already found eigenenergy for a better precision. Working with a window not enclosing an eigenenergy would still evaluate to a result, but it may be misleading.Warning
Regarding the adiabatic state preparation, if the lowest energy eigenstate of the first-step Hamiltonian \(h_{pq}\) is also an eigenstate of the whole \(H\), the system will remain in it until the end of the whole adiabatic stage. Hence, this eigenstate may not be the one of the lowest energy anymore.
As a rule of thumb, if small changes to the interval cause considerable deviations in the energy, that’s a sign that the window is too small or a different target energy may be better.
- Parameters
H_el (ElectronicStructureHamiltonian) – An electronic-structure Hamiltonian.
n_phase_bits (int) – Number of qubits for the phase evaluation. The larger it is, the more accurate is the result.
n_trotter_steps (int) – Number of first order trotterization steps. For good phase estimation it should also increase if n_phase_bits is increased.
init_vec (Optional[str]) – Initial vector specified in the computational basis as a string - ‘01101’ for example. Starting from |0..0> an X will be applied to the respective qubits so as to produce the provided vector. This vector will enter the adiabatic state preparation routine if n_adiab_steps is not 0 or will be given straight to the main QPE routine.
n_adiab_steps (Optional[int]) – Number of steps to pass from the part of the Hamiltonian containing only c_p^dagger * c_p terms (which is diagonal and fast to deal with) to the Hamiltonian of interest.
E_target (Optional[float]) – Expected energy. If unknown, set to 0.
size_interval (Optional[float]) – Size \(\Delta\) of the interval one thinks the value of the energy is in: \(E \in [E_\mathrm{target}-\Delta/2, E_\mathrm{target}+\Delta/2]\) If no idea take \(\Delta =2 E_\mathrm{max}\), with \(E_\mathrm{max}\) an upper bound of the energy.
basis_transform (Optional[str]) – Transformation to go from
qat.fermion.hamiltonians.ElectronicStructureHamiltonian
into aqat.fermion.hamiltonians.SpinHamiltonian
: one can use the “jordan-wigner” (default), “bravyi-kitaev” or “parity” transformations.qpu (Optional[QPU]) – QPU to use for computation. Will use by default the default installed QPU.
- Returns
Energy found,
associated probability.
- Return type
Tuple[float, float]
Note
Usually, energies lie outside the range \((-\frac{2\pi}{t}, 0)\). However, this range can be adjusted by specifying the arguments E_target and size_interval thus searching inside the window \((E_{t} - \frac{\Delta}{2}, E_{target} + \frac{size\_interval}{2})\), where \(E_{t}\) and \(\Delta\) stand for . We suggest to always start from a large size interval and unbiased target energy like 0 thus enclosing many of the eigenenergies including the desired one. One can then narrow the window around an already found eigenenergy for a better precision. Experience shows that working with a window not enclosing an eigenenergy makes the QPE still output a result, but it is misleading.
Quantum subspace expansion
- qat.fermion.chemistry.qse.apply_quantum_subspace_expansion(hamiltonian: SpinHamiltonian, state_prep_circ: Circuit, expansion_operators: List[Observable], qpu: QPUHandler, nbshots: int = 0, threshold: float = 1e-15, return_matrices: bool = False) Tuple[float, Optional[ndarray], Optional[ndarray]]
Apply quantum subspace expansion (QSE) to the given Hamiltonian.
QSE is a method that improves the quality of noisy results at the cost of additional measurements that help write the Hamiltonian in the small subspace where it can be diagonalized classically.
If \(\langle \Psi^\star | \hat{H} | \Psi^\star \rangle\) is the VQE result, the projected Hamiltonian matrix is built from
\[H^{(s)}_{i,j} = \langle \Psi^\star | \hat{O}_i^\dagger \hat{H} \hat{O}_j | \Psi^\star \rangle\]where \(\hat{O}_i\) is an element of expansion_operators.
Then the generalized eigenvalue problem
\[H^{(s)} \vec{x} = E S \vec{x}\]is solved, with \(S\) the overlap matrix:
\[S_{i,j} = \langle \Psi^\star | \hat{O}_i^\dagger \hat{O}_j | \Psi^\star \rangle\]- Parameters
hamiltonian (SpinHamiltonian) – The Hamiltonian in its spin representation.
state_prep_circ (Circuit) – The state preparation circuit.
expansion_operators (list<SpinHamiltonian>) – The set of operators \({O_i}_i\) generating the subspace of interest.
qpu (QPUHandler) – The QPU.
nbshots (int, optional) – The number of shots. Defaults to 0: infinite number of shots.
threshold (float, optional) – The numerical threshold.
return_matrices (bool, optional) – If set to
True
, the function returns the matrices \(H^{(s)}\) and \(S\). Defaults to False.
- Returns
Improved energy provided by the QSE procedure. matrix_h (Optional[np.ndarray]): The subspace Hamiltonian \(H^{(s)}\). Only if
return_matrices
is True. matrix_s (Optional[np.ndarray]): The overlap matrix \(S\). Only ifreturn_matrices
is True.- Return type
e_qse (float)
Example:
import numpy as np from qat.core import Term from qat.fermion import SpinHamiltonian from qat.lang.AQASM import Program, RY, CNOT, RZ from qat.qpus import get_default_qpu from qat.plugins import SeqOptim # We instantiate the Hamiltonian we want to approximate the ground state energy of hamiltonian = SpinHamiltonian(2, [Term(1, op, [0, 1]) for op in ["XX", "YY", "ZZ"]]) # We construct the variational circuit (ansatz) prog = Program() reg = prog.qalloc(2) theta = [prog.new_var(float, '\\theta_%s'%i) for i in range(3)] RY(theta[0])(reg[0]) RY(theta[1])(reg[1]) RZ(theta[2])(reg[1]) CNOT(reg[0], reg[1]) circ = prog.to_circ() # Construct a (variational) job with the variational circuit and the observable job = circ.to_job(observable=hamiltonian, nbshots=0) # We now build a stack that can handle variational jobs qpu = get_default_qpu() optimizer = SeqOptim(ncycles=10, x0=[0, 0.5, 0]) stack = optimizer | qpu # We submit the job and print the optimized variational energy (the exact GS energy is -3) result = stack.submit(job) E_min = -3 print("E(VQE) = %s (err = %s %%)"%(result.value, 100*abs((result.value-E_min)/E_min))) e_vqe = result.value # We use the optimal parameters found by VQE opt_circ = circ.bind_variables(eval(result.meta_data["parameter_map"])) expansion_operators = [SpinHamiltonian(2, [], 1.0), SpinHamiltonian(2, [Term(1., "ZZ", [0, 1])])] from qat.fermion.chemistry.qse import apply_quantum_subspace_expansion e_qse = apply_quantum_subspace_expansion(hamiltonian, opt_circ, expansion_operators, qpu, return_matrices=False) print("E(QSE) = %s (err = %s %%)"%(e_qse, 100*abs((e_qse-E_min)/E_min)))
E(VQE) = -3.0 (err = 0.0 %) E(QSE) = -3.0 (err = 0.0 %)
Unitary Coupled-Cluster (UCC)
- qat.fermion.chemistry.ucc.transform_integrals_to_new_basis(one_body_integrals: ndarray, two_body_integrals: ndarray, u_mat: ndarray) Tuple[ndarray, ndarray]
Change one and two body integrals (indices p, q…) to new basis (indices i, j…) using transformation U such that
\[\hat{c}_{i}=\sum_{q}U_{qi}c_{q}\]i.e
\[\hat{I}_{ij} =\sum_{pq}U_{pi}I_{pq}U_{jq}^{\dagger} \hat{I}_{ijkl}=\sum_{pqrs}U_{pi}U_{qj}I_{pqrs}U_{kr}^{\dagger}U_{ls}^{\dagger}\]- Parameters
one_body_integrals (np.ndarray) – One-body integrals \(I_{pq}\).
two_body_integrals (np.ndarray) – Two-body integrals \(I_{pqrs}\).
u_mat (np.ndarray) – Transformation matrix \(U\).
- Returns
h_hat_ij (np.ndarray): One-body integrals \(\hat{I}_{ij}\).
h_hat_ijkl (np.ndarray): Two-body integrals \(\hat{I}_{ijkl}\).
- Return type
Tuple[np.ndarray, np.ndarray]
- qat.fermion.chemistry.ucc.compute_active_space_integrals(one_body_integrals: ndarray, two_body_integrals: ndarray, active_indices: List[int], occupied_indices: List[int]) Tuple[ndarray, ndarray, float]
Restrict one- and two-body integrals for given list of active indices.
\[ \begin{align}\begin{aligned}\forall u,v\in \mathcal{A},\; I^{(a)}_{uv} = I_{uv} + \sum_{i\in \mathcal{O}} 2 I_{i,u,v,i} - I_{i,u,i,v}\\\forall u,v,w,x \in \mathcal{A}, I^{(a)}_{uvwx} = I_{uvwx}\\c^{(a)} = c + \sum_{i\in\mathcal{O}} I_{ii} + \sum_{ij\in\mathcal{O}} 2I_{ijji} - I_{ijij}\end{aligned}\end{align} \]- Parameters
one_body_integrals (np.ndarray) – Array of one-body integrals \(I_{uv}\). Must be 2D.
two_body_integrals (np.ndarray) – Array of two-body integrals \(I_{uvwx}\). Must be 4D.
active_indices (List[int]) – Active indices.
occupied_indices (List[int]) – Occupied indices.
- Returns
2D array of one-body integrals \(I_{uv}^{(a)}\),
4D array of two-body integrals \(I_{uvwx}^{(a)}\),
core constant \(c^{(a)}\).
- Return type
Tuple[np.ndarray, np.ndarray, float]
- qat.fermion.chemistry.ucc.convert_to_h_integrals(one_body_integrals: ndarray, two_body_integrals: ndarray) Tuple[ndarray, ndarray]
Convert from \(I_{uv},I_{uvwx}\) to \(h_{pq},h_{pqrs}\), with
\[ \begin{align}\begin{aligned}h_{u\sigma, v\sigma'} = I_{u, v} \delta_{\sigma, \sigma'}\\h_{u\sigma_1, v\sigma_2, w\sigma_2', x\sigma_1'} = I_{uvwx} \left((1-\delta_{\sigma,\sigma'}) + \delta_{\sigma,\sigma'} (1-\delta_{u,v})(1-\delta_{w,x}) \right)\end{aligned}\end{align} \]and where the one- and two-body integrals are defined as:
\[I_{uv}\equiv(u|h|v)=\int\mathrm{d}r\phi_{u}^{*}(r)T\phi_{v}(r)\]\[I_{uvwx}\equiv(ux|vw)=\iint\mathrm{d}r_{1}\mathrm{d}r_{2}\phi_{u}^{*}(r_{1})\phi_{x}(r_{1})v(r_{12})\phi_{v}^{*}(r_{2})\phi_{w}(r_{2})\]with \(T\) (resp. \(v\)) the one- (resp. two-) body potentials, and \(\phi_u(r)\) is the molecular orbital wavefunction.
The \(h\) integrals are used to construct hamiltonians of the ElectronicStructureHamiltonian type.
- Parameters
one_body_integrals (np.ndarray) – Array of one-body integrals \(I_{uv}\). Must be 2D.
two_body_integrals (np.ndarray) – Array of two-body integrals \(I_{uvwx}\). Must be 4D.
- Returns
the \(h_{pq}\) integrals,
the \(h_{pqrs}\) integrals.
- Return type
Tuple[np.ndarray, np.ndarray]
- qat.fermion.chemistry.ucc.construct_ucc_ansatz(cluster_ops: List[SpinHamiltonian], ket_hf: int, n_steps: int = 1) Program
Builds the parametric state preparation circuit implementing the provided cluster operator.
The returned function maps \(\vec{\theta}\) to a QRoutine describing \(Q\) such as:
\[Q \vert \vec{0} \rangle = \vert \mathrm{UCC} (\vec{\theta}) \rangle = e^{T(\vec{\theta})} \vert \mathrm{HF}\rangle\]- Parameters
cluster_ops (List[SpinHamiltonian]) – The cluster operators iT (note the i factor).
ket_hf (int) – The Hartree-Fock state in integer representation.
n_steps (int) – Number of trotter steps.
- Returns
The parametric program implementing the UCCSD method.
- Return type
- qat.fermion.chemistry.ucc.select_active_orbitals(noons: List[float], n_electrons: int, threshold_1: Optional[float] = 0.02, threshold_2: Optional[float] = 0.001) Tuple[List[int], List[int]]
Selects the right active space and freezes core electrons according to their NOONs.
This function is an implementation of the Complete Active Space (CAS) approach. It divides orbital space into sets of active and inactive orbitals, the occupation number of the latter remaining unchanged during the computation.
- Parameters
noons (np.ndarray) – The natural orbital occupation numbers in descending order (from high occupations to low occupations)
n_electrons (int) – The number of electrons.
threshold_1 (Optional[float]) – The upper threshold \(\varepsilon_1\) on the NOON of an active orbital. Defaults to 0.02.
threshold_2 (Optional[float]) – The lower threshold \(\varepsilon_2\) on the NOON of an active orbital. Defaults to 0.001.
- Returns
active_so (List[int]): The list of active spatial orbitals.
inactive_occupied_so (List[int]): The list of core spatial orbitals.
- Return type
Tuple[List[int], List[int]]
- qat.fermion.chemistry.ucc.guess_init_params(two_body_integrals: ndarray, n_electrons: int, orbital_energies: List[float], noons: Optional[List[float]] = None) List[float]
Find initial parameters using Møller-Plesset perturbation theory.
The trial parametrization is efficiently improved upon the Hartree-Fock solution (which would set every initial parameter to zero) thanks to the following formula identifying the UCC parameters in the Møller-Plesset (MP2) solution :
\[\theta_a^i = 0\]\[\theta_{a, b}^{i, j} = \frac{h_{a, b, i, j} - h_{a, b, j, i}}{\epsilon_i + \epsilon_j -\epsilon_a - \epsilon_b}\]where \(h_{p, q, r, s}\) is the 2-electron molecular orbital integral, and \(\epsilon_i\) is the orbital energy.
- Parameters
two_body_integrals (np.ndarray) – 4D array of two-body integrals \(I_{uvwx}\).
n_electrons (int) – The number of active electrons of the system.
noons (List[float]) – the natural-orbital occupation numbers \(n_i\), sorted in descending order (from high occupations to low occupations) (doubled due to spin degeneracy).
orbital_energies (List[float]) – The energies of the molecular orbitals \(\epsilon_i\) (doubled due to spin degeneracy).
- Returns
The list of initial coefficients \(\{\theta_{a}^{i}, a \in \mathcal{I}', i \in \mathcal{O}' \} \cup \{\theta_{ab}^{ij}, a>b, i>j, a,b \in \mathcal{I}', i,j \in \mathcal{O}'\}\),
- Return type
theta_list (List[float])
- qat.fermion.chemistry.ucc.get_hf_ket(n_electrons: int, nqbits: int) int
Get Hartree-Fock state stored as a vector with right-to-left orbitals indexing.
- Parameters
n_electrons (int) – The number of active electrons of the system.
nqbits – The number of qubits.
- Returns
Hartree-Fock state.
- Return type
int
- qat.fermion.chemistry.ucc.get_cluster_ops(n_electrons: int, nqbits: Optional[int] = None, noons: Optional[List[float]] = None) List[FermionHamiltonian]
Compute the cluster operators.
- Parameters
n_electrons (int) – The number of active electrons of the system.
nqbits (Optional[int]) – The number of qubits.
noons (Optional[List[float]]) – The natural-orbital occupation numbers \(n_i\), sorted in descending order (from high occupations to low occupations) (doubled due to spin degeneracy).
- Returns
The list of cluster operators \(\{T_{a}^{i}, a \in \mathcal{I}', i \in \mathcal{O}' \} \cup \{T_{ab}^{ij}, a>b, i>j, a,b \in \mathcal{I}', i,j \in \mathcal{O}'\}\)
- Return type
List[FermionHamiltonian]
Note
This function accepts as input the number of qubits or the noons. One of them is needed for the computation of the cluster operators.
n_electrons
andn_qbits
must be pair.
Utility functions
- qat.fermion.trotterisation.make_trotterisation_routine(hamiltonian: Union[SpinHamiltonian, FermionHamiltonian, ElectronicStructureHamiltonian], n_trotter_steps: int, final_time: Optional[float] = 1.0, method: Optional[str] = 'jordan-wigner') QRoutine
This function first trotterizes the evolution operator \(e^{-i H t}\) of a Hamiltonian \(H\) using a first order approximation. If the Hamiltonian is fermionic, it is converted to its spin representation.
- Parameters
hamiltonian (Union[SpinHamiltonian, FermionHamiltonian, ElectronicStructureHamiltonian]) – Hamiltonian to trotterize.
n_trotter_steps (int) – Number \(n\) of Trotter steps.
final_time (Optional[float]) – Time \(t\) in the evolution operator.
method (Optional[str]) – Method to use for the transformation to a spin representation. Other available methods include
"bravyi-kitaev"
and"parity"
. Defaults to"jordan-wigner"
.
- Returns
Gates to apply to perform the time evolution of the chemical Hamiltonian with trotterisation.
- Return type
Notes
In the fermionic case :
\[e^{-i H t} \approx \prod_{k=1}^{n} \left( \prod_{pq} e^{-i \frac{t}{n} h_{pq} c_p^\dagger c_q} \prod_{pqrs} e^{-\frac{i}{2}\frac{t}{n} h_{pqrs} e^{-i c_p^\dagger c_q^\dagger c_r c_s} } \right)\]This operator is then mapped to a product of Pauli operators via a Jordan-Wigner transformation and the resulting QRoutine is returned.
The QRoutine implements a first order Trotter approximation, but higher order approximations are possible.
- qat.fermion.chemistry.pyscf_tools.perform_pyscf_computation(geometry: list, basis: str, spin: int, charge: int, run_fci: bool = False)
Perform various calculations using PySCF. This function is a helper function meant to kickstart molecule studies. Its use is completely optional, and using other methods or packages is entirely possible.
This function will compute:
The reduced density matrix,
The orbital energies,
The nuclear repulsion constant,
The number of electrons,
The one- and two-body integrals,
The groundstate energies obtained through Hartree-Fock and 2nd order Möller-Plesset perturbation approach,
(Optional) The groundstate energy using the full configuration interaction (full CI) approach.
Note
The FCI computation is very expensive for big molecules. Enable it only for small molecules !
- Parameters
geometry (list) –
Defines the molecular structure. The internal format is PySCF format:
atom = [[atom1, (x, y, z)], [atom2, (x, y, z)], ... [atomN, (x, y, z)]]
basis (str) – Defines the basis set.
spin (int) – 2S, number of alpha electrons - number beta electrons to control multiplicity. If spin is None, multiplicity
molecule. (will be guessed based on the neutral) –
charge (int) – Charge of molecule. Affects the electron numbers.
run_fci (bool, optional) – Whether the groundstates energies should also be computed using a full CI approach. Defaults to False.
- Returns
rdm1 (np.ndarray): Reduced density matrix.
orbital_energies (list): List of orbital energies.
nuclear_repulsion (float): Nuclear repulsion constant.
nels (int): Number of electrons.
one_body_integrals (np.ndarray): One-body integral.
two_body_integrals (np.ndarray): Two-body integral.
info (dict): Dictionary containing the Hartree-Fock and 2nd order Möller-Plesset computed ground state energies (and optionally the Full CI energy if run_fci is set to True).
- Return type
Tuple[np.ndarray, list, float, int, np.ndarray, np.ndarray, dict]