MethodLayer 1
Generalized singles and doubles ansatz
Drop the rule that an excitation has to move an electron from an occupied orbital into an empty one. Every pair of orbitals may be coupled, so the circuit stops depending on which reference determinant it was built around — a wider variational manifold, paid for in parameters.
The Hamiltonian whose ground state is wanted, together with whatever structure is to be respected — particle number, spin, point-group symmetry, a reference determinant — and the connectivity and native gate set of the device the family has to run on.
A circuit family with a fixed structure and free real parameters, together with the number of those parameters — which is the size of the classical search problem handed to the next layer.
Same contract as the slot it fills.
This one, drawn
From Hamiltonian whose eigenvalues are wanted to Parameterised circuit family
A circle is an object you are holding. This method is drawn heavier, opened into its own steps; the other lines between the same two ends are the alternatives recorded for the same slot. Circles are named on hover, and each one is a link.
Nothing drawn here has a recorded way through it that this figure leaves shut. See it on the map
What it fills
- Choose a parameterised trial state
Fix the gate structure of a circuit family and leave its rotation angles open. What comes back is not a circuit but the set of states the later optimisation is allowed to search — which is why this is a slot of its own and not a paragraph in one method's write-up.
When it applies
Lee et al. define the ansatz by the distinction it removes: "Here the single and double 'excitation' terms do not distinguish between occupied and unoccupied orbitals and they are therefore called 'generalized' singles and doubles (GSD)", and name the result in the same section — "We shall term this ansatz UCCGSD". Its cost is stated beside its sibling's rather than alone: the paper's Table 1 puts UCCGSD at gates and depth against k-UpCCGSD's and . The two are separate ansätze in this paper, compared against each other and against UCCSD, which is why `k-upccgsd-ansatz` and this node are separate rather than one node drawn twice.
Requires
Every step this method names moves its route along, so there is nothing it needs alongside them.
Example
Lee et al. report a classical numerical simulation comparing UCCGSD against UCCSD (and against k-UpCCGSD) on the double dissociation of water in symmetry: at a fixed bond angle both O-H bonds are stretched together, using the STO-3G basis with spin-orbitals and active electrons. Along the resulting potential energy curve, the cluster amplitudes were optimized variationally by minimizing the ansatz's own energy expectation value, the paper's Eq. 9, whose analytic gradient was passed to SciPy's BFGS and rerun between thirty and two hundred times from random starting points to approximate the global minimum; a Psi4 full configuration interaction calculation, run separately via OpenFermion's Psi4 interface, supplied the reference energy used only afterward to score the resulting error. For the ground state, UCCSD and 1-UpCCGSD "perform much worse than the other UCC methods", while UCCGSD is among the methods the paper calls "more or less numerically exact on the scale of the plot". For the first excited state, reached through the orthogonally constrained VQE (OC-VQE) penalty, the paper's own non-parallelity-error table gives 0.00 mEh for UCCGSD against 17.57 mEh for UCCSD, with 1-UpCCGSD worse still at 30.22 mEh. The paper is explicit that this whole benchmark is a wavefunction calculation rather than a circuit one: "a practical implementation of UCC relies on approximating by a small number of Trotter steps, which leads to ansätze that are not exactly equivalent to the ones considered in our numerical calculations", so no Trotterized circuit and no qubit mapping were ever built for this run. The optimizer itself is flagged as non-transferable to real hardware, since the BFGS routine used here "is unsuitable for use on a quantum device due to the stochastic error associated with the measurement of observables in the VQE framework".
Classical simulation · Section "Double Dissociation of H2O (C2v)", Figure 2 and Table 5 of arXiv:1810.02327
given Hamiltonian H on N spin-orbitals, eta electrons
reference state |phi_0> (an eta-electron Slater determinant, e.g. RHF;
a multi-determinantal reference is also usable)
requires a fermion-to-qubit encoding fixed ahead of time, one qubit per spin-orbital
# qubit count is linear in N by construction of the mapping (Sec. Quantum
# Resource Requirements)
# --- cluster operator, over ALL spin-orbital pairs, not just occ-to-virt -------------
T1 = (1/2) sum_pq t^q_p a_q^dag a_p
T2 = (1/4) sum_pqrs t^rs_pq a_r^dag a_s^dag a_q a_p (Eq. 11-12)
# p,q,r,s each range over all N spin-orbitals -- occupied and unoccupied are
# NOT distinguished, unlike UCCSD's T1 = sum(i occ, a virt) t^a_i a_a^dag a_i
# (Eq. 3-5): "the single and double 'excitation' terms do not distinguish
# between occupied and unoccupied orbitals" -- hence 'generalized' (GSD)
T = T1 + T2
# the free amplitudes {t^q_p, t^rs_pq} number as many as the parameters of the
# 2nd-quantized Hamiltonian itself (Sec. Generalized CC, same T as Eq. 11)
# --- anti-Hermitize and exponentiate --------------------------------------------------
generator = T - T^dag
# the anti-Hermitian combination is what makes exp(generator) unitary
U(theta) = exp(T - T^dag) (Eq. 13 -- the paper names this UCCGSD)
|psi(theta)> = U(theta) |phi_0>
# theta is the amplitude vector {t^q_p, t^rs_pq}
# --- what a device actually runs -------------------------------------------------------
U(theta) implemented as Trotter_m[ exp(T - T^dag) ], m a small FIXED step count
# "a practical implementation of UCC relies on approximating e^(T-T^dag) by a
# small number of Trotter steps" -- the circuit prepared is not exactly the
# |psi(theta)> above; it differs from the state the amplitudes were fit to
# (Sec. Quantum Resource Requirements)
# this paper does not derive how large m must be for UCCGSD; it reports that
# even m=1 has been shown elsewhere to reach high accuracy for UCC ansatze
# in general (cited to Ref. 64) -- an external result, not proved here
# --- how the resulting family is scored ------------------------------------------------
E(theta) = <phi_0| U(theta)^dag H U(theta) |phi_0> / <phi_0| U(theta)^dag U(theta) |phi_0>
# evaluated variationally (Eq. 9's form, carried over unchanged from the general
# UCC ansatz Eq. 8 to the UCCGSD ansatz Eq. 13, which only redefines T),
# NOT by the projective coupled-cluster equations (Eq. 6-7)
return the parameterized circuit U(theta) |phi_0>, theta ranging over {t^q_p, t^rs_pq}
# a circuit FAMILY, not yet a converged state -- theta is fit by an outer classical
# loop elsewhere in the pipelineCost, as the source states it
Lee, Huggins, Head-Gordon and Whaley cost UCCGSD in Table 1: gates and circuit depth in spin-orbitals, with no dependence on the electron number — against UCCSD's and . Conditions: state preparation only; a fixed number of Trotter steps of rather than the exact exponential; gate count taken as the two-qubit count; and a depth assuming maximum parallelization, no Jordan-Wigner overhead, and a linearly connected qubit array, the last resting on their Refs. 59 and 63, the latter unpublished. Qubits are linear in . Table 9 reports amplitudes per benchmark case, not as a formula: 27 at , 135 at , 434 at for both and ; their classical code stops near 16 spin-orbitals. Nothing bounds the optimization — each one was rerun thirty to two hundred times from random starting points — and the paper gives no absolute shot or measurement count, deferring measurement to McClean et al.
Implementations
3
Generalized excitations behind a flag in Qiskit Nature's UCC
Qiskit Nature carries this ansatz as a keyword rather than under its name. The UCC class takes generalized: bool = False, documented as “Boolean flag whether or not to use generalized excitations, which ignore the occupation of the spin orbitals. As such, the set of generalized excitations is only determined from the number of spin orbitals and independent from the number of particles.” The string UCCGSD does not occur anywhere in the repository, and neither does this method's paper: grep over a checkout of the main branch taken 2026-09-03 returns no match for GSD and no match for the identifier 1810.02327. The UCC class docstring's only reference is arXiv:1805.04340, Barkoutsos et al., a different paper about particle/hole Hamiltonians and optimized wavefunction expansions. A reader looking for Lee, Huggins, Head-Gordon and Whaley's ansatz by name will not find it here; it is reached as UCC(..., generalized=True), or as UCCSD(..., generalized=True), the subclass forwarding the flag unchanged.
The flag is interpreted in the excitation list, not in the circuit builder. In qiskit_nature/second_q/circuit/library/ansatzes/utils/fermionic_excitation_generator.py, get_alpha_excitations returns list(itertools.combinations(range(num_spatial_orbitals), 2)) when generalized is set, in place of list(itertools.product(alpha_occ, alpha_unocc)); get_beta_excitations makes the same substitution over the beta block. Those two substitutions are the whole of the occupied/unoccupied distinction being dropped. The module's own doctest states the difference exactly: generate_fermionic_excitations(num_excitations=1, num_spatial_orbitals=3, num_particles=(1,1)) returns [((0,), (1,)), ((0,), (2,)), ((3,), (4,)), ((3,), (5,))], while generate_fermionic_excitations(1, 3, (1, 1), generalized=True) returns [((0,), (1,)), ((0,), (2,)), ((1,), (2,)), ((3,), (4,)), ((3,), (5,)), ((4,), (5,))]. Because preserve_spin defaults to True, the generalized excitations still stay inside one spin species; clearing it as well takes a separate and wider branch in the same file, whose comment reads “Combining generalized=True with preserve_spin=False results in all possible excitations, regardless of both, orbital occupancy and orbital spin species.” The flag also switches off two of the class's own input checks: in _check_ucc_configuration, the guard rejecting fully occupied alpha and beta orbitals and the guard rejecting more particles than spatial orbitals both sit inside if not self._generalized.
No molecule is attached to the flag anywhere in the test suite and no energy is computed with it; what the repository checks is excitation lists and the operators built from them. test/second_q/circuit/library/ansatzes/utils/test_fermionic_excitation_generator.py carries test_generalized_excitations, “Test generalized excitations.”, which compares generate_fermionic_excitations(..., generalized=True) against hard-coded expected lists, and test_generalized_preserve_spin_excitations, described in the file as a regression test against Qiskit Nature issue 788.
The keyword is on the UCC class in qiskit_nature/second_q/circuit/library/ansatzes/ucc.py and is passed straight through by the UCCSD subclass in ansatzes/uccsd.py, in the Python package qiskit-nature, https://github.com/qiskit-community/qiskit-nature, under the Apache License 2.0, with VERSION.txt on the main branch reading 0.9.0. UCC subclasses EvolvedOperatorAnsatz; the excitation generator sits beside it at ansatzes/utils/fermionic_excitation_generator.py, and the flag reaches that generator through the extra_kwargs dictionary built in _get_excitation_generators, as "generalized": bool(self._generalized), bound into partial over each generator.
The library reports no energy for a generalized run; the flag is exercised over operators and circuit structure only. test_uccsd_ansatz_generalized in test/second_q/circuit/library/ansatzes/test_uccsd.py builds UCCSD(..., generalized=True) at three spatial orbitals with one alpha and one beta electron, compares the fifteen FermionicOp excitation operators it produces — six generalized singles and nine doubles — against a hard-coded list, and through the shared helper assert_ucc_like_ansatz calls ansatz._build() and asserts that the built circuit carries six qubits; no molecule enters and no simulator is called. test_puccd.py and test_succd.py set the flag the same way for the PUCCD and SUCCD variants.
Quket's uccgsd ansatz option
Quket exposes the ansatz under its own name: uccgsd is one of the strings the ansatz input keyword accepts, listed in the README beside uccsd, uccgd, uccgsdt, uccgsdtq, sauccgsd and k-upccgsd. The package describes itself as “This suite of programs simulates quantum computing for electronic Hamiltonian.”, so what runs is a simulator, not a device; it is built over Qulacs and OpenFermion, which the README puts as “Quket overrides QuantumState of Qulacs and QubitOperator and FermionOperator of OpenFermion as quket.QuantumState, etc.” The same string is accepted in two roles — quket/config.py holds both a vqe_ansatz_list and a qite_ansatz_list, and uccgsd appears in each — so the operator set is reused as a QITE pool as well as a VQE ansatz.
get_pauli_list_uccgsd(norbs, DS=0, singles=True, ...) in quket/pauli/pauli.py, docstring “Create Pauli list for UCCGSD.”, assembles the ansatz from two generalized blocks. create_pauli_list_gs loops p over all spatial orbitals and q over range(p), taking every pair rather than an occupied-to-virtual pair, and emits the alpha term (pA, qA) and the beta term (pB, qB) separately, so its generalized singles stay within a spin species; create_pauli_list_gd takes its doubles from Gdoubles_list(norbs). Each term is anti-Hermitized as fermi - hermitian_conjugated(fermi) before mapping, and the mapping is Jordan-Wigner or Bravyi-Kitaev by argument. The circuit-level form of the singles is ucc_Gsingles in quket/ansatze/ucclib.py, documented as “Construct circuit for generalized singles prod_pq exp[theta (p!q - q!p)]”. The parameter count is written down rather than derived: quket/utils/ndims.py sets ndim1 = norbs*(norbs-1) for uccgsd, against ndim1 = 0 for the doubles-only uccgd in the same branch. Block ordering is a switch and not a fixed choice — the DS flag selects ['singles','doubles'] or ['doubles','singles'] — and singles=False reduces the same routine to uccgd.
The only worked example of it in the distribution is a four-electron, four-orbital H4 case in docs/Tutorial_6_qite_multistate.ipynb: four hydrogens at (0, 0, 0), (0, 0, 1.2), (1, 0, 0) and (1, 0, 1.2), basis sto-6G, multiplicity 1, charge 0, taper_off = True, with the initial state given as a two-determinant combination. No input file under samples/ uses uccgsd — grep over that directory returns nothing — although samples/k-UpCCGSD/ exists for the paired variant.
The package is Quket, https://github.com/quket/quket, under the Apache License 2.0, with __version__ = "0.9.4" in quket/_version.py. The entry points are the input keyword ansatz = uccgsd, or QuketData.set(ansatz='uccgsd') from Python, dispatched in quket/quket_data/quket_data.py to get_pauli_list_uccgsd in quket/pauli/pauli.py, with the circuit helper ucc_Gsingles in quket/ansatze/ucclib.py. Of the other generalized strings in quket/config.py only uccgsdt and uccgsdtq reach past the singles and doubles that this method is: sauccgsd is the same excitation rank in spin-free form, dispatched instead to get_pauli_list_uccgsd_sf in the same file, “Create Pauli list for Spin-Free UCCGSD.”, while uccgd and sauccgd are those same two routines called with singles=False.
The notebook's UCCGSD section is a QITE run and not a variational optimisation of the amplitudes: the cell reads QITE.set(ansatz = 'uccgsd', det="0.9391 * |00001111> - 0.2518 * |00110011>") and the printed output is “Final: E[uccgsd] = -2.033812414801 <S**2> = +0.000000000000001”. The markdown above it says what the keyword does there — “Setting ansatz to a pre-defined ansatz in qite_ansatz_list, config.py, prepares an operator pool.” So that figure is a QITE energy reached with the UCCGSD operator set on the Qulacs simulator, not a UCCGSD VQE energy, and the distribution ships no UCCGSD VQE benchmark: uccgsd matches only this one notebook under docs/ and nothing in test.py.
The GSD operator pool in QForte
QForte carries the generalized excitations as an operator pool named GSD rather than as an ansatz named UCCGSD. Its UCCVQE base class — the parent of both UCCNVQE and ADAPTVQE — documents the string among the allowed _pool_type values as “GSD: At most two excitations, from any orbital to any orbital.”, beside SD through SDTQPH and the spin-adapted SA_SD. The package paper introduces that pool in its section 3.2, Adaptive VQE — “In QForte it is possible to construct P in a variety of ways, including the generalized single and double excitation/de-excitation operators described in the original publication.” — where the publication cited is Grimsley et al.'s ADAPT-VQE paper, not this method's. Lee, Huggins, Head-Gordon and Whaley's paper is in the same reference list, but it is cited in the outlook, among the references for which the authors write “we plan to extend the type of ansätze supported in QForte”. So in the 2021 paper the fixed generalized ansatz is future work; what makes the present code an implementation of it is a different route through the same pool.
That route is UCCNVQE, where the entire pool becomes the ansatz instead of being searched: initialize_ansatz in src/qforte/ucc/uccnvqe.py is documented as “Adds all operators in the pool to the list of operators in the circuit, with amplitude 0.” and its body is self._tops = list(range(len(self._pool_obj))) with self._tamps = [0.0] * len(self._pool_obj), so UCCNVQE(mol).run(pool_type="GSD") fixes every generalized single and double as a variational amplitude. The pool is built in C++: src/qforte/sq_op_pool.cc opens the branch with if (pool_type == "GSD"), takes singles over every pair of spatial orbitals within a spin, and takes doubles with i over all orbitals, j from i, a from 0 and b from a — the a and b indices running over all spatial orbitals rather than over virtuals only. Repeated terms and their adjoints are filtered against the uniqe_2bdy and adjnt_2bdy lists before a term is added, and a point-group test, find_irrep(orb_irreps_to_int_, ...), can drop symmetry-forbidden terms. The pool is not owned by ADAPT-VQE in the code: fill_pool, which routes GSD — with sa_SD, SD, SDT, SDTQ, SDTQP and SDTQPH — to SQOpPool.fill_pool, is defined on the shared Algorithm base class in src/qforte/abc/algorithm.py, and GSD is separately an accepted _expansion_type for QITE in src/qforte/ite/qite.py.
The string is accepted by UCCNVQE.run(..., pool_type="GSD", ...) in src/qforte/ucc/uccnvqe.py, exported from src/qforte/ucc/__init__.py, in https://github.com/evangelistalab/qforte under the GNU Lesser General Public License version 3, with setup.py declaring name="qforte", version="0.1". The pool constructor is the GSD branch of fill_pool in src/qforte/sq_op_pool.cc, a C++ class exposed to Python, and the sentence listing the allowed pool types is the _pool_type docstring on the UCCVQE base class in src/qforte/abc/uccvqeabc.py.
The repository never exercises the fixed generalized ansatz. Every pool_type="GSD" call in tests/ is on ADAPTVQE and none is on UCCNVQE: tests/test_adapt_vqe.py runs jacobi.run(optimizer="jacobi", pool_type="GSD", avqe_thresh=0.001) and a BFGS counterpart, tests/test_computer_init.py runs it at avqe_thresh=1e-5, and tests/test_open_shells.py runs alg.run(pool_type="GSD", avqe_thresh=0.1, adapt_maxiter=100) inside a test named test_H5_adaptvqe and marked in its own comment as a regression test — a doublet linear chain of five hydrogens at spacing Rhh = 1.5, basis sto-6g, symmetry d2h — asserting alg._Egs == approx(-2.4982780593834577, abs=1.0e-12). Listing every pool_type in the suite shows UCCNVQE driven only by the strings SD, sa_SD and SDTQ, and once, in tests/test_custom_pool.py, by a hand-built one-operator SQOpPool. So the evidence that the GSD pool works is an ADAPT-VQE run on QForte's own state-vector simulator, not a UCCGSD one.
What it needs
Nobody has taken this apart yet. That is a gap in this graph, not a claim that the method has no parts.
Other ways to fill the same slot
12
Different approaches
- Unitary coupled-cluster singles and doubles
Build the trial state from single and double excitations out of a reference determinant, exponentiated as a unitary. The family is chosen for chemistry rather than for the machine: the state you want is in it by construction, and the circuit that reaches it is deep.
- Hardware-efficient ansatz
Build the trial state out of the gates and couplings the machine already has, and accept whatever states that reaches. The circuit is shallow because nothing in it was chosen for the chemistry; there is correspondingly no argument that the state you want is inside the family.
- ADAPT-VQE adaptive ansatz
Refuse to fix the structure in advance. Start from nothing and add one operator at a time, choosing each from a pool according to what the molecule itself indicates, until the energy stops improving. The circuit ends up short because nothing was included that the problem did not ask for.
- qubit-ADAPT-VQE ansatz a narrower version of ADAPT-VQE adaptive ansatz
The same grow-it-one-operator-at-a-time construction, with the pool rebuilt out of qubit operators rather than fermionic excitations so that the circuits it produces are shallow enough for near-term hardware.
- k-UpCCGSD ansatz
Take k repetitions of paired double excitations together with generalized singles, instead of the full set of doubles. The point of the restriction is that the depth then grows linearly in the number of orbitals rather than polynomially, and k is the dial that buys accuracy back.
- Qubit coupled-cluster ansatz
Skip the fermionic layer and build the ansatz directly in qubit space, ranking candidate entangling operators by how much each would move the energy and keeping the ones that earn their place.
- Particle-hole coupled-cluster circuits
Rewrite the Hamiltonian around the reference determinant so that what the circuit has to describe is excitations out of it, then build the family from gates that move an electron without creating or destroying one. Staying inside the right particle-number sector is a property of the gates, not something the optimiser has to discover.
- Orbital-optimized coupled-cluster circuits
Let the orbitals move too. The usual family fixes a basis and varies the amplitudes; this one varies the molecular orbital coefficients alongside them, so the same accuracy is reachable from a smaller active space and a shallower circuit — and the energy becomes fully variational, which is what makes forces available.
- Symmetry-preserving state-preparation circuits
Build the circuit so that it cannot leave the symmetry sector the chemistry lives in. Particle number, total spin, spin projection and time reversal are respected by the gate structure itself, so the search never spends parameters on states the answer cannot be in.
- TETRIS-ADAPT-VQE ansatz a narrower version of ADAPT-VQE adaptive ansatz
Keep ADAPT's habit of growing the ansatz from measured gradients, and stop adding one operator per round. Several operators acting on disjoint qubits can go in together, filling the same layer instead of stacking — the same circuit, packed rather than piled.
- Iterative qubit coupled cluster a narrower version of Qubit coupled-cluster ansatz
Stop growing the circuit and grow the Hamiltonian instead. Each round folds the entanglers found so far into the operator by a canonical transformation, so every round runs a circuit of the same size — the cost moves off the device and into the number of terms that have to be measured.
- Batched ADAPT-VQE ansatz a narrower version of ADAPT-VQE adaptive ansatz
Keep ADAPT's habit of growing the ansatz from measured gradients, and stop adding exactly one operator per round. Every operator whose gradient is close to the largest goes in together, so the ansatz reaches the same size in far fewer rounds — and it is the rounds, not the operators, that cost measurements.
In the Atlas
1
- Generalized excitation VQE
Generalized singles and doubles relax occupied-to-virtual restrictions to enlarge the variational manifold.