Fermionic Exponentiated Ansatz

The FermionSpaceStateExp class is essentially a thin wrapper over TrotterAnsatz (see previous section), and serves as the basis for all the Unitary Coupled Cluster ansatzes. It accepts a FermionOperatorList object as an input, maps it to a corresponding QubitOperatorList object, and provides the latter as an input to TrotterAnsatz.

If one has an idea for a chemically inspired unitary ansatz, which can be written in terms of fermionic operators, and would like to build and handle the corresponding circuit in InQuanto, this can be achieved by first instantiating a list of fermionic operators, and then providing it to a FermionSpaceStateExp constructor.

As an illustrative example, let us generate a reduced UCCD ansatz from scratch for a system of two electrons in six spin-orbitals. We first need to write the double excitations of interest:

from inquanto.spaces import FermionSpace
from inquanto.ansatzes import FermionSpaceAnsatzUCCD
from inquanto.operators import (
     FermionOperatorString,
     FermionOperator,
     FermionOperatorList
)
from sympy import Symbol

# Generate example state and space
space = FermionSpace(n_spin_orb=6)
state = space.generate_occupation_state(n_fermion=2)

# Construct a list of two double excitation operators
d0 = FermionOperatorString.from_string("2^ 0 3^ 1")
d1 = FermionOperatorString.from_string("4^ 0 5^ 1")
term_list = FermionOperatorList(
   [
     (Symbol("d0"), FermionOperator(d0, 1)),
     (Symbol("d1"), FermionOperator(d1, 1))
   ]
)
print(f"Fermion state: {state}")
print(f"Fermion operator list: \n{term_list}")
Fermion state: (1.0, {0: np.int64(1), 1: np.int64(1), 2: np.int64(0), 3: np.int64(0), 4: np.int64(0), 5: np.int64(0)})
Fermion operator list: 
d0        [(1, F2^ F0  F3^ F1 )],
d1        [(1, F4^ F0  F5^ F1 )]

Here, we should think of term_list as a product of exponents of single FermionOperator objects, constructed from a certain string of creation-annihilation fermionic operators, and pre-multiplied by symbolic terms d0 and d1. In order to ensure the ansatz operator is unitary, we make the expressions under the exponents anti-hermitian by taking the difference of each term with its adjoint. The resulting FermionOperatorList is then passed to the FermionSpaceStateExp constructor, together with the FermionState object and the fermion-to-qubit mapping class of choice:

from inquanto.ansatzes import FermionSpaceStateExp
from inquanto.mappings import QubitMappingJordanWigner
anti_hermitian_term_list = FermionOperatorList(
   [(symbol, operator - operator.dagger()) for operator, symbol in term_list.items()]
)
my_ansatz = FermionSpaceStateExp(
   anti_hermitian_term_list,
   state,
   QubitMappingJordanWigner()
)

The ansatz object thus constructed can generate a circuit and be used with any of the algorithms or computable objects of InQuanto.