Trotter Ansatz

The TrotterAnsatz class represents a state built from a product of exponentiated Pauli strings and is at the core of the UCC family of ansatzes.

The mathematical definition of TrotterAnsatz is as follows:

(93)\[|\mathrm{TrotterAnsatz}\rangle = \prod_{k}^{\leftarrow}e^{ip_{k}\sum_{l_{k}}\lambda_{l_{k}}^{(k)}\hat{P}_{l_{k}}^{(k)}}|\mathrm{Ref}\rangle = \prod_{k}^{\leftarrow}\prod_{l_{k}}e^{ip_{k}\lambda_{l_{k}}^{(k)}\hat{P}_{l_{k}}^{(k)}}|\mathrm{Ref}\rangle,\]

where it is assumed that for every \(k\) and \(\{l_{k},l'_{k}\}\), \(\hat{P}_{l_{k}}^{(k)}\) and \(\hat{P}_{l'_{k}}^{(k)}\) are mutually commuting Pauli strings, \(\lambda_{l_{k}}^{(k)}\) is a real numerical value and \(p_{k}\) is a real numeric or symbolic expression. We also use the following notation for the reverse-ordered product of operators here:

(94)\[\prod_{k}^{\leftarrow}\hat{O}_{k}=...\hat{O}_{k+1}\hat{O}_{k}\hat{O}_{k-1}...\hat{O}_{0}.\]

When generating circuits for TrotterAnsatz in InQuanto, we leverage the pytket PauliExpBox class to prepare gates corresponding to the exponentiated Pauli strings. The PauliExpBox constructor takes in a Pauli string object \(\hat{P}\) and an expression object \(t\), and encodes the following exponentiated expression:

(95)\[\mathrm{PauliExpBox}(\hat{P}, t) = e^{-\frac{i\pi}{2}t\hat{P}}.\]

We can thus re-write the definition of TrotterAnsatz in terms of PauliExpBox as follows:

(96)\[|\mathrm{TrotterAnsatz}\rangle=\prod_{k}^{\leftarrow}\prod_{l_{k}}\mathrm{PauliExpBox}(\hat{P}_{l_{k}}^{(k)}, -\frac{2}{\pi}p_{k}\lambda_{l_{k}}^{(k)})|\mathrm{Ref}\rangle.\]

To construct it, one needs a reference QubitState object \(|\mathrm{Ref}\rangle\) and a QubitOperatorList object, which represents the expression to be exponentiated, and is defined as follows:

(97)\[ \begin{align}\begin{aligned}\mathrm{QubitOperatorList}=[...,(p_{k-1},\{...,(i\lambda_{l_{k-1}}^{(k-1)},\hat{P}_{l_{k-1}}^{(k-1)}),...\}),\\(p_{k},\{...,(i\lambda_{l_{k}}^{(k)},\hat{P}_{l_{k}}^{(k)}),...\}),(p_{k+1},\{...,(i\lambda_{l_{k+1}}^{(k+1)},\hat{P}_{l_{k+1}}^{(k+1)}),...\}),...] .\end{aligned}\end{align} \]

One should keep in mind that only the imaginary part of the supplied \(\lambda_{l_{k}}^{(k)}\) (i.e. the coefficients of each of the QubitOperator object terms), will be taken on construction of TrotterAnsatz.

In the InQuanto ansatz class hierarchy, TrotterAnsatz is a base class of FermionSpaceStateExp, which in turn forms the basis of all UCC ansatz classes. However, it can be used all by itself, in order to define a custom ansatz in terms of QubitOperator objects. To do this, one needs to provide bare-bones Pauli string terms, “wrapped” into QubitOperator objects, and then construct a QubitOperatorList object out of them. As described above, one should think of it as of a product of exponents of the provided Pauli strings, with each string multiplied by a symbolic expression. The resulting QubitOperatorList object is then passed to a TrotterAnsatz constructor.

For instance, to recover the FCI energy of a hydrogen molecule in a minimal basis, a single Pauli word is needed:

from inquanto.operators import QubitOperator, QubitOperatorList
from inquanto.states import QubitState
from inquanto.ansatzes import TrotterAnsatz
from sympy import Symbol

q = QubitOperator("Y0 X1 X2 X3", 1j)
qlist = QubitOperatorList([(Symbol("x"), q)])
ansatz = TrotterAnsatz(qlist, QubitState([1, 1, 0, 0]))