The UCC Family

The following unitary coupled cluster (UCC) ansatzes are available in InQuanto:

These are discussed in further detail in the following subsections.

Unitary Coupled Cluster

This ansatz corresponds to a variant of the (non-unitary) coupled cluster method [44], in which the operator acting on a reference state becomes unitary [45]

(86)\[ \begin{align}\begin{aligned}\hat{U}_{\text{UCC}}(\boldsymbol{\theta}) = e^{\hat{T} - \hat{T}^\dagger} = e^{\sum_\lambda \theta_\lambda (\hat{T}_\lambda - \hat{T}^\dagger_\lambda)}\\|\Psi(\boldsymbol{\theta})\rangle = \hat{U}_{\text{UCC}}(\boldsymbol{\theta}) |\text{HF}\rangle .\end{aligned}\end{align} \]

Here, the excitation operator \(\hat{T}\) has the same form as in coupled cluster theory. Under the exponent the excitation operator self-adjoint is subtracted, rendering the exponent anti-Hermitian, and hence the operator \(\hat{U}_{\text{UCC}}\) is unitary. The unitarity of \(\hat{U}_{\text{UCC}}\) makes its implementation on a quantum circuit more natural. By parameterizing the excitations, this ansatz is suitable for variational algorithms in which the parameters \(\boldsymbol{\theta} = \{\theta_1, \theta_2, ..., \theta_\lambda, ...\}\) are to be optimized such that the total energy is minimized according to the variational principle. The reference wavefunction is often the Hartree-Fock ground state, but excited configurations are also possible, as long as \(\hat{U}_{\text{UCC}}\) is applied to a single configuration. Truncating excitations to singles and doubles leads to the (FermionSpaceAnsatzUCCSD) ansatz. Doubles-only (FermionSpaceAnsatzUCCD) ansatz is also available.

Consider the following example for a system of 4 spin orbitals and 2 electrons (applicable to the H2 molecule in minimal basis):

from inquanto.states import FermionState
from inquanto.spaces import FermionSpace
from inquanto.mappings import QubitMappingJordanWigner
from inquanto.ansatzes import FermionSpaceAnsatzUCCD, FermionSpaceAnsatzUCCSD

space = FermionSpace(4)
state = FermionState([1, 1, 0, 0])
jw_map = QubitMappingJordanWigner()

ansatz_uccsd = FermionSpaceAnsatzUCCSD(
    fermion_space=space, fermion_state=state, qubit_mapping=jw_map
)

ansatz_uccd = FermionSpaceAnsatzUCCD(
    fermion_space=space, fermion_state=state, qubit_mapping=jw_map
)

report_uccsd = ansatz_uccsd.generate_report()
uccsd_resources = ansatz_uccsd.circuit_resources()
report_uccd = ansatz_uccd.generate_report()
uccd_resources = ansatz_uccd.circuit_resources()

print("\nNumber of parameters: {} (UCCSD), {} (UCCD)".format(
    report_uccsd['n_parameters'],
    report_uccd['n_parameters'])
)
print("Number of qubits: {} (UCCSD), {} (UCCD)".format(
    report_uccsd['n_qubits'],
    report_uccd['n_qubits'])
)
print("Ansatz circuit depth: {} (UCCSD), {} (UCCD)".format(
    uccsd_resources['depth'],
    uccd_resources['depth'])
)

uccsd_circuit = ansatz_uccsd.get_circuit(
ansatz_uccsd.state_symbols.construct_random()
)
uccd_circuit = ansatz_uccd.get_circuit(
ansatz_uccd.state_symbols.construct_random()
)

Number of parameters: 3 (UCCSD), 1 (UCCD)
Number of qubits: 4 (UCCSD), 4 (UCCD)
Ansatz circuit depth: 83 (UCCSD), 57 (UCCD)

In the above script, we have built UCCSD and UCCD ansatzes objects using the fermionic orbital space (FermionSpace) and occupation state (FermionState) objects, as well as our choice of fermion-to-qubit mapping (QubitMappingJordanWigner). Symbols corresponding to the ansatz parameters can be accessed by the state_symbols attribute, which returns an Python dictionary object that stores the SymPy symbols. For more information on how to access and manipulate symbolic parameters in InQuanto please see the corresponding section. Useful information about the ansatz circuit such as number of qubits, number of parameters, and circuit depth is available from the dict returned by the generate_report() method of each ansatz object. A pytket Circuit object can be generated using the get_circuit() method (which needs numeric values for the parameters, and we provide random values here using the construct_random() method).

Warning

The get_circuit() method will return circuits in an arbitrary gateset, which may include circuit boxes (sets of gates) expressed as singular quantum gates. Care must be taken when analysing these circuits, as resource counts such as circuit depth may be misleading. For an estimate of resource counts, use the circuit_resources() method. Note that while this method reports in a consistent gateset, it is still a crude estimate, and does not capture improvements obtainable through circuit compilation.

For this system, we see three parameters for UCCSD: 2 single (alpha-beta single excitations are not allowed in order to preserve spin symmetry), and 1 double excitation. Exclusion of the singles in the UCCD ansatz leads to only one excitation – the double. This is consistent with minimal basis H2. As we can see, fewer excitations in UCCD leads to equally less parameters and a reduced circuit depth compared to the UCCSD ansatz.

InQuanto generates the excitation operators for UCC using the FermionOperatorList class. To construct a UCC ansatz object, anti-hermitian UCC excitations must be transformed to qubit operators via a provided fermion to qubit mapping method and exponentiated. To facilitate its implementation on a quantum circuit, the UCC ansatz is expressed in a trotterized form (facilitated by the FermionOperatorList internal structure), i.e. approximated as

(87)\[e^{\hat{T} - \hat{T}^\dagger} \approx \prod_\lambda e^{\theta_\lambda (\hat{T}_\lambda - \hat{T}^\dagger_\lambda)}\]

which corresponds to the first order Trotter decomposition. In general this is an approximation, which leads to (usually small) variations of the energy that depend on the order of terms in the product \(\prod_\lambda e^{\theta_\lambda (\hat{T}_\lambda - \hat{T}^\dagger_\lambda)}\). For variational algorithms, it is expected that this error will be absorbed by the variational procedure; however, this must be considered – particularly when using non-variational algorithms. All the UCC-family ansatzes in InQuanto use first-order trotterization. To implement higher-order approximations, one needs to use their base FermionSpaceStateExp class described in the corresponding section.

Generalized Unitary Coupled Cluster

The UCC ansatz discussed in the previous section refers to set of coupled cluster operators with a well defined separation between occupied and unoccupied (virtual) orbital spaces, such that all excitations are transitions between occupied and virtual spin orbitals. Lee et al. [27] proposed variations of UCC in which occupied-to-occupied and virtual-to-virtual excitations are also included. The direct extension of UCC(S)D ansatzes to include these generalized transitions is referred to as UCCG(S)D. Here

(88)\[ \begin{align}\begin{aligned}\hat{T}^{(1\text{G})} = \sum_{p,q}t_{p}^{q}\hat{f}_{q}^{\dagger}\hat{f}_{p}\\\hat{T}^{(2\text{G})} = \sum_{p,q,r,s}t_{p,q}^{r,s}\hat{f}_{r}^{\dagger}\hat{f}_{s}^{\dagger}\hat{f}_{p}\hat{f}_{q}\\\hat{T}_{\text{GSD}} = \hat{T}^{(1\text{G})} +\hat{T}^{(2\text{G})}\\\hat{U}_{\text{UCCGSD}}(\boldsymbol{\theta}) = e^{\hat{T}_{\text{GSD}} - \hat{T}_{\text{GSD}}^\dagger},\end{aligned}\end{align} \]

where \(p,q,r,s\) run over both occupied and virtual spin orbital spaces. Note there is a one-to-one mapping between the set of parameters (labeled by generic indexes for cluster operators) and the set of excitation coefficients for singles and doubles (labeled by orbitals involved in the transition), i.e. \(\boldsymbol{\theta} = \{\theta_1, \theta_2, ..., \theta_\lambda, ...\} \mapsto \{t_{p}^{q}, ..., t_{p,q}^{r,s}, ...\}\). The UCCG(S)D ansatzes are instantiated in the same way as UCC(S)D (see the code snippet in Unitary Coupled Cluster), by simply replacing FermionSpaceAnsatzUCCSD (FermionSpaceAnsatzUCCD) with FermionSpaceAnsatzUCCGSD (FermionSpaceAnsatzUCCGD) for singles+doubles (doubles only).

A more compact form of generalized UCC has also been proposed in which the double excitations are restricted to pair-doubles, i.e. transitions of a pair of electrons between the two spatial orbitals (but spatial orbital indexes still span the general range as above)

(89)\[\hat{T}^{(2\text{pG})} = \sum_{(p\alpha,p\beta), (q\alpha,q\beta)}t_{p\alpha,p\beta}^{q\alpha,q\beta}\hat{f}_{q\alpha}^{\dagger}\hat{f}_{q\beta}^{\dagger}\hat{f}_{p\alpha}\hat{f}_{p\beta}\]

where \({\alpha, \beta}\) label spins, \({p, q}\) labels spatial orbitals, and the singles are as in \(T^{(1\text{G})}\). This ansatz, referred to as \(k\)-UpCCGSD [27] (FermionSpaceAnsatzkUpCCGSD), is expressed as a product of \(k\) factors of cluster operators, each one with an independent set of parameters

(90)\[ \begin{align}\begin{aligned}\hat{T}^{(k)} = \hat{T}^{(1\text{G})} + \hat{T}^{(2\text{pG})}\\\hat{U}_{k\text{UpCCGSD}}(\boldsymbol{\theta}) = \prod_k e^{\hat{T}^{(k)} - \hat{T}^{(k)\dagger}}.\end{aligned}\end{align} \]

The following snippet demonstrates the initialization of the UCCGSD and \(k\)-UpCCGSD ansatzes:

from inquanto.states import FermionState
from inquanto.spaces import FermionSpace
from inquanto.mappings import QubitMappingJordanWigner
from inquanto.ansatzes import FermionSpaceAnsatzkUpCCGSD, FermionSpaceAnsatzUCCGSD

space = FermionSpace(4)
state = FermionState([1, 1, 0, 0])
jw_map = QubitMappingJordanWigner()

ansatz_uccgsd = FermionSpaceAnsatzUCCGSD(
    fermion_space=space, fermion_state=state, qubit_mapping=jw_map
)

ansatz_kupccsd = FermionSpaceAnsatzkUpCCGSD(
    fermion_space=space, fermion_state=state, k_input=2, qubit_mapping=jw_map
)

print("\nNumber of parameters: {} (UCCGSD), {} (k-UpCCGSD)".format(
    ansatz_uccgsd.generate_report()['n_parameters'],
    ansatz_kupccsd.generate_report()['n_parameters'])
)

Number of parameters: 3 (UCCGSD), 6 (k-UpCCGSD)

In this case, there are 2 duplicates for the set of singles and doubles of \(k\)-UpCCGSD, as the input value of \(k\) is set to 2.