Skip to content

refactor(circuit)!: build UCJ from an ffsim UCJ operator - #322

Open
mrossinek wants to merge 1 commit into
clarify-ffsim-boundaryfrom
ucj-from-ffsim-op
Open

refactor(circuit)!: build UCJ from an ffsim UCJ operator#322
mrossinek wants to merge 1 commit into
clarify-ffsim-boundaryfrom
ucj-from-ffsim-op

Conversation

@mrossinek

Copy link
Copy Markdown
Member

The UCJ gate reimplemented how the ansatz tensors are obtained (double factorization of the t2 amplitudes, interaction-pair masking, and the parameter-vector packing) alongside the part that is actually this package's concern: turning those tensors into a mapper-agnostic fermionic circuit. The first half duplicated ffsim, which is where the ansatz math belongs, so this narrows the gate to the second half and takes the ffsim operator directly.

The duplication was verified, not assumed. Against ffsim 0.0.84, the removed num_parameters/from_parameters/to_parameters agreed elementwise with n_params/from_parameters/to_parameters for all three spin variants and both with_final_orbital_rotation settings, and the tensor layouts and dtypes were already identical, so passing the operator through changes no numerics. What it gains is what ffsim has and this package never implemented: the compressed (optimize=True) double factorization and from_cisd_vec.

What remains is the part with no ffsim equivalent: the OrbitalRotation and Evolution decomposition, and in particular the closed-form circle-method edge coloring that hands Evolution a pre-grouped FermionOperator so each group synthesizes as one parallel layer. That is what makes the gate lowerable through any fermion-to-qubit encoding, which ffsim's JW-hardcoded UCJOpSpinBalancedJW cannot do, and it is unchanged: a 2-repetition balanced ansatz still expands to 10 OrbitalRotation plus 2 Evolution gates.

Two consequences worth naming. ffsim is now the gate's input type rather than an accelerator with a fallback, so UCJ is constructible only where ffsim installs, which excludes Windows; that is documented with a WSL pointer rather than worked around. And UCJOpSpinless is read as a single norb-mode register, since a gate fixes its width at construction while ffsim resolves spin at apply time from nelec; the two-register reading remains expressible as a UCJOpSpinBalanced with a zeroed alpha-beta block, which is the same operator.

UCJAnglesOpSpinBalanced is deliberately not accepted: it stores gate rotation angles rather than tensors, so it is already a Jordan-Wigner decomposition of the ansatz and sits below the encoding-agnostic layer this gate occupies.

The LUCJ guide's transpiled phase-gate count moves from 16 to 14. ffsim's factorization returns orbital rotations differing from the previous ones by a per-column phase gauge; the operators are physically identical (same state vector to machine precision) but the gauge phases surface as PhaseGates during Givens synthesis. The VQE outer-loop guide is removed here rather than ported, since it was built entirely on the parameter API that is now ffsim's.

Refs #318

@coveralls

coveralls commented Sep 4, 2026

Copy link
Copy Markdown

Coverage Status

Coverage is 98.203%ucj-from-ffsim-op into clarify-ffsim-boundary. No base build found for clarify-ffsim-boundary.

The UCJ gate reimplemented how the ansatz tensors are *obtained* (double
factorization of the t2 amplitudes, interaction-pair masking, and the
parameter-vector packing) alongside the part that is actually this package's
concern: turning those tensors into a mapper-agnostic fermionic circuit. The
first half duplicated ffsim, which is where the ansatz math belongs, so this
narrows the gate to the second half and takes the ffsim operator directly.

The duplication was verified, not assumed. Against ffsim 0.0.84, the removed
`num_parameters`/`from_parameters`/`to_parameters` agreed elementwise with
`n_params`/`from_parameters`/`to_parameters` for all three spin variants and
both `with_final_orbital_rotation` settings, and the tensor layouts and dtypes
were already identical, so passing the operator through changes no numerics.
What it gains is what ffsim has and this package never implemented: the
compressed (`optimize=True`) double factorization and `from_cisd_vec`.

What remains is the part with no ffsim equivalent: the OrbitalRotation and
Evolution decomposition, and in particular the closed-form circle-method edge
coloring that hands Evolution a pre-grouped FermionOperator so each group
synthesizes as one parallel layer. That is what makes the gate lowerable
through any fermion-to-qubit encoding, which ffsim's JW-hardcoded
`UCJOpSpinBalancedJW` cannot do, and it is unchanged: a 2-repetition balanced
ansatz still expands to 10 OrbitalRotation plus 2 Evolution gates.

Two consequences worth naming. ffsim is now the gate's input type rather than
an accelerator with a fallback, so UCJ is constructible only where ffsim
installs, which excludes Windows; that is documented with a WSL pointer rather
than worked around. Since the class docstring's example now needs ffsim, it is
gated with `.. skip: start if(not HAS_FFSIM)`, which required registering Sybil's
`SkipParser` in python/conftest.py; docs/conftest.py already had it, so this is
the same pattern the guides use, and the example stays executed and verified
wherever ffsim is installed. And `UCJOpSpinless` is read as a single norb-mode register,
since a gate fixes its width at construction while ffsim resolves spin at apply
time from `nelec`; the two-register reading remains expressible as a
`UCJOpSpinBalanced` with a zeroed alpha-beta block, which is the same operator.

`UCJAnglesOpSpinBalanced` is deliberately not accepted: it stores gate rotation
angles rather than tensors, so it is already a Jordan-Wigner decomposition of
the ansatz and sits below the encoding-agnostic layer this gate occupies.

The LUCJ guide's transpiled phase-gate count moves from 16 to 14. ffsim's
factorization returns orbital rotations differing from the previous ones by a
per-column phase gauge; the operators are physically identical (same state
vector to machine precision) but the gauge phases surface as PhaseGates during
Givens synthesis. The VQE outer-loop guide is removed here rather than ported,
since it was built entirely on the parameter API that is now ffsim's.

Refs #318

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants