Skip to content

Bernoulli Expansion based Unitary Coupled-Cluster - #581

Draft
ajay-mk wants to merge 7 commits into
masterfrom
ajay/feat/bernoulli-v2
Draft

Bernoulli Expansion based Unitary Coupled-Cluster#581
ajay-mk wants to merge 7 commits into
masterfrom
ajay/feat/bernoulli-v2

Conversation

@ajay-mk

@ajay-mk ajay-mk commented Jul 27, 2026

Copy link
Copy Markdown
Member

Adds the Bernoulli expansion of the UCC similarity-transformed Hamiltonian $\bar{H} = e^{-\sigma} H e^{\sigma}$, $\sigma = T - T^\dagger$, as an alternative to the BCH expansion in mbpt::CC. Ranks $\bar H^0$$\bar H^4$, Eqs. (45)–(50) of Ref. 1.

Ground state energies are validated, excited states pending.

More details to be added.

References

  1. J. Liu, A. Asthana, L. Cheng, D. Mukherjee, Unitary coupled-cluster based
    self-consistent polarization propagator theory: A third-order formulation and
    pilot applications
    , J. Chem. Phys. 148, 244110 (2018).
    doi:10.1063/1.5030344 — Sec. III B, the
    reference this module implements.

ajay-mk added 7 commits July 26, 2026 01:00
Adds the bottom layer of the Bernoulli expansion of the unitary-CC
similarity-transformed Hamiltonian: a Wick reduction that retains partial
contractions, so a product of normal-ordered operators reduces to a sum of
normal-ordered operators rather than collapsing to a scalar vacuum average,
and the normal-ordered commutator built on it.

WickTheorem::use_topology is disabled explicitly rather than left alone: it
defaults to ON (wick.hpp), and its one-representative-times-multiplicity
bookkeeping is only exercised by the fully-contracted path. On this
partial-contraction path it rescales terms whose amplitude pairs are
symmetric, which leaves vacuum averages correct while corrupting projections
onto excited manifolds.

wick_commutator reindexes B's summed indices to fresh temporaries before
forming A*B, since A and B are independently constructed and may otherwise
share labels, which would fuse two independent summations.
Adds the second layer: the split of an operator O into O_N, "the non-diagonal
part containing all the excitation and de-excitation operators" (defined above
Eq. (43) of 10.1063/1.5030344), and the rank-preserving remainder O_R = O - O_N.
The Bernoulli expansion's inner commutators carry N/R subscripts, so every
nesting level needs this classification.

Classification needs definite index spaces, so expand_to_blocks first rewrites
each general index of the residual NormalOperator as a sum over the base spaces
it spans. Only the hole and particle spaces are expanded over: in the
single-reference setting the remaining base spaces are empty, so restricting to
those keeps the expansion 2-way per index instead of compounding across the
nested commutators. That makes the routine single-reference only, which the
header warns about.

The rank cutoff mirrors pdaggerq (nt_bra > bernoulli_excitation_level -> R)
rather than the paper's uncapped O_N, since that is the convention defining
qUCCSD and the one the numbers are validated against; terms above the cutoff
fall to R rather than being dropped.
Adds the top layer: hbar(N, rank, skip1) sums H̄⁰..H̄^rank of 10.1063/1.5030344
Eq. (45), each order transcribed from its equation with the published
coefficients and per-level N/R subscripts. Bernoulli numbers B₁=-1/2, B₂=1/12,
B₃=0, B₄=-1/720 (Eq. 40) enter as those coefficients; a subscript R/N on a
commutator means "form the commutator, then keep only its R/N part before the
next nesting", which is what the split from the previous commit provides.

Two cancellations from the paper are relied on and noted in place: F enters H̄
only at first order (stated just below Eq. (50)), and the higher orders carry
only R-subscripted inner commutators.

Every term is a nested commutator whose prefix is shared with other terms,
within a rank and across ranks, so nest() memoizes each prefix (keyed by the
base operator plus the tags applied so far). The nine rank-4 terms have only 3
distinct level-1 and 6 distinct level-2 nodes. Reusing a memoized ExprPtr is
safe because expression composition deep-copies its operands.

Contributions accumulate through Sum::append rather than chained operator+,
which deep-copies the whole accumulated Sum on every call and is quadratic in
the term count at high rank.
Adds CC::Options::hbar_expansion (BCH by default, Bernoulli opt-in) and
dispatches CC::hbar() to bernoulli::hbar() when it is selected. Two constructor
assertions guard the combination: the Bernoulli expansion is defined for the
unitary ansatz only, and it requires an explicit hbar_comm_rank, since CC::hbar()
otherwise falls back to rank 4 and would silently select the most expensive and
least exercised order.

CC::energy() takes the plain reference expectation value under this expansion:
the tensor-level H̄ is already fully expanded, so no operator connectivity
remains to constrain. Its comm_rank argument defaults to the amplitude rank and
is passed explicitly for the qUCCSD [2|3] split, where the energy is taken at H̄³
while the amplitudes stop at H̄².
Pins the derived equations at Bernoulli ranks 1-3 for the unitary
ansatz: term
counts for the energy and for the singles/doubles residuals, plus the
guards on
invalid configurations (Bernoulli with a non-unitary ansatz, and
Bernoulli
without an explicit hbar_comm_rank).

The rank-3 numbers (46 energy, 32 singles, 38 doubles terms) are the
ones
cross-checked term-by-term against pdaggerq, so a change here means the
derivation changed.
Corrections:
- Eq. (45) is the assembly H̄ = Σ_k H̄^k; (46)-(50) are the rank-by-rank
  operators. The file header attributed (45)-(50) to the latter.
- expand_to_blocks: the SR "o"/"g" base spaces are not empty, so the old
  justification for dropping them was wrong. They are droppable because
the
  single-reference projection annihilates those terms. The header
@warning
  said the same wrong thing.
- R_part's result is not block-resolved; it stays in compact
general-index
  form. The header claimed the opposite.
- wick_reduce leaves at most one residual NormalOperator, not exactly
one --
  fully-contracted terms carry none, which find_nop already handled.
- The memo shares level-1 nodes across ranks; it is not a prefix
relation.
- The use_topology rescaling set is {2, 1/2, 1/3, 8/3, 2/3}; the comment
said
  3 where it should have said 1/3.
@ajay-mk
ajay-mk force-pushed the ajay/feat/bernoulli-v2 branch from 2b73c55 to e78e554 Compare July 27, 2026 12:08
@ajay-mk ajay-mk added the feature New feature label Jul 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant