Double Factorization¶
English · 简体中文
Category C2 · Module
oracq.algorithms.input_model.lowrank· Stage V1
Overview¶
The double factorization (DF) of the quantum chemistry electronic Hamiltonian compresses the two-body integral tensor into a low-rank form
each rank term being a Hermitian matrix whose diagonal spectrum \(g_r\) is conjugated by the rotation \(U_r\). The implementation follows the “low-rank tensor → LCU → BE” pipeline of Berry et al. 2019 and von Burg et al. 2021 (literature citations in the module docstring): the integral tensor is given as classical input data, this module performs no real chemistry integral computation, and the resulting block encoding can enter qubitization directly.
Interface and input model¶
DoubleFactorization(scalar, rotations, spectra)
DoubleFactorization.from_symmetric(scalar, rotations, factors)
diagonalize_symmetric(matrix, *, tolerance=1e-12, max_sweeps=100)
double_factorized_encoding(df, *, name=None)
API entry points: DoubleFactorization, diagonalize_symmetric, double_factorized_encoding
DoubleFactorization: the DF input model (input model CP — the tensor data is given directly as classical parameters, i.e. the “low-rank tensor (HAM) → BE” pipeline in algorithm-coverage).rotationsare explicit small unitary matrices (dimensions powers of two within 2..32, unitarity checked by column orthogonality, tolerance 1e-9), andspectraare the corresponding real spectra; the dataclass attributeswidthgives the number of target qubits andrankthe number of rank terms.from_symmetric: the classical preprocessing entry point of physical DF — takes explicit unitaries \(U_r\) and real symmetric \(G_r\), and folds the eigenvector matrix of \(G_r = V_r\,\mathrm{diag}(g_r)\,V_r^{\mathsf T}\) into the rotation (\(U_r V_r\)).diagonalize_symmetric: Jacobi eigendecomposition of a real symmetric matrix, returning(eigenvalues, eigenvector matrix); non-symmetric input raisesValidationErrorat generation time.double_factorized_encoding: assembles the LCU block encoding (thenameparameter is retained but currently takes no part in naming).
Returns a BlockEncoding with module attributes:
Attribute |
Meaning |
|---|---|
|
\(\lvert\mathrm{scalar}\rvert + \sum_r \lVert g_r\rVert_1\) (sum of the spectra’s 1-norms) |
|
|
|
number of rank terms / number of nonzero terms of the outer LCU |
|
a λ report under the same accounting, equal in value to |
Implementation notes¶
The outer LCU’s PREPARE runs over the rank index \(r\) with weights \(\propto \lVert g_r\rVert_1\); a nonzero scalar joins the same LCU as (scalar, identity), and all-zero coefficients (including all-zero spectra) raise ValidationError. Each rank term’s term block encoding is \(U_r^\dagger\cdot\mathrm{diag}\cdot U_r\): the diagonal part applies a controlled \(R_y(\theta_t)\) on a single-bit signal for every basis state \(\lvert t\rangle\), with \(\cos(\theta_t/2) = g_t/\alpha_r\) and \(\alpha_r = \sum_p\lvert g_p\rvert\) taken as the spectral 1-norm, so the (0,0) block is exactly \(\mathrm{diag}(g_r)/\alpha_r\); the synthesized \(U_r\) is applied on the two sides to complete the conjugation.
\(U_r\) is synthesized by two-level decomposition: columns are eliminated into diagonal phases and replayed in reverse order; each two-level unitary is realized by a ZYZ decomposition (\(e^{i\varphi}R_z(\alpha)R_y(\beta)R_z(\gamma)\)) plus multi-controlled X transpositions along a Gray path. Register layout: the term block encoding is target(n) | signal(1), and the outer LCU’s signal is the selector (as many bits as the term count requires) concatenated with work(1).
Applicability boundary: the explicit-matrix path supports only validation-sized instances of dimension 2..32 (at most 5 qubits); at larger scales the spectra and rotation angle tables of \(U_r\)/\(G_r\) should switch to QRAM data binding (see the three-layer paradigm of prepare_select). In terms of normalization, the DF α of a single-bit positive definite \(g\) equals \(\mathrm{tr}(g)\) and introduces no off-diagonal redundancy from the Pauli expansion (tightness witness in the validation section).
Validation approach¶
Category C2 (approximately continuous semantics; the acceptance criteria are in ../development/validation-plan.md §2): the block encoding’s zero-signal block must agree with the target Hamiltonian within tolerance. Three layers of evidence:
Structure:
tests/core/test_lowrank.py:DiagonalizeSymmetricTests.test_reconstructs_factor(\(V\,\mathrm{diag}(\lambda)\,V^{\mathsf T}\) reconstruction and eigenvector orthogonality, places = 10) andtest_rejects_non_symmetric; the construction attribute assertions ofDoubleFactorizationTests(be_form,df.rank == 1/df.width == 1);ThcTests.test_invalid_inputs_fail_at_generationcovers the DF negative cases (empty rank terms, mismatched spectrum lengths, non-unitary rotations, non-numericscalar, inconsistent counts infrom_symmetric).Numerical:
DoubleFactorizationTests.test_single_rank_block_equals_hamiltonian— single-rank DF cross-checked column by column against \(G\) viaassert_block_equals(places = 9);test_scalar_and_rotated_ranks— a scalar and a Hadamard-rotated second rank, with the expected matrix assembled independently inside the test before cross-checking, and α cross-checked against \(\lvert\mathrm{scalar}\rvert + \sum_r\lVert g_r\rVert_1\) (places = 10);test_feeds_qubitization_walk— after the product enterstransforms.qubitization_walkthere are no unbound slots and the registers are["target", "signal"].Binding:
DoubleFactorizationTests.test_matches_pauli_encoding_block— the DF encoding and the Pauli LCU encoding of the same Hamiltonian are cross-checked column by column across BEs via theblock_columnhelper (places = 9), covering the consistency of two independent encoding paths.
α tightness witnesses (added in V1): test_alpha_matches_closed_form_eigenvalues independently computes \(\sum\lvert\lambda\rvert\) from the 2×2 closed-form eigenvalues \(\lambda_\pm = (t \pm \sqrt{t^2-4d})/2\) (\(t\) the trace, \(d\) the determinant) and cross-checks it against be.alpha (places = 10, measured 2.0); test_df_alpha_tighter_than_pauli takes an off-diagonal-dominant positive definite \(g\) and measures DF α = 1.4 ≤ Pauli LCU α = 1.5 (theoretical condition: on single-bit PSD matrices Pauli α − DF α = \(\lvert g_{01}\rvert + \lvert\Delta/2\rvert - \mathrm{tr}/2\), positive in the off-diagonal-dominant case).
Known gaps and planned stages¶
No known gaps; the stage V1 witnesses are complete (block cross-checks + α tightness against the closed-form eigenvalues and the Pauli comparison + cross-encoding binding consistency + the qubitization hookup).
Numerical validation¶
Paper-grade numerical validation script: tests/verification/verify_blockencoding.py (real-backend execution, no mock substitutes, no skips; all 73 cases passed on 2026-09-16), artifact out/verification/blockencoding.json. This page corresponds to diagonalize-symmetric-*, df-encoding-*, and diagonal-be-*, 11 cases in total (the diagonal block encoding _diagonal_encoding is exactly the kernel of a DF rank term).
Experiment design:
Diagonal BE across scales (
_diagonal_encoding, the diagonal BE named in the paper): three spectrum groups (mixed signs, containing zeros, generated from trigonometric functions) with dim ∈ {2, 4, 8} go through OriginIR-ext + UniQCto_matrixfull-unitary extraction (the (0,0) block compared against \(\mathrm{diag}(g)/\alpha\), with leakage into the failure branch reported), and dim ∈ {16, 32, 64} go through reference + rir-pysparq column by column; there is also a public assembly-consistency case — the same diagonal spectrum yields element-wise identical blocks viadouble_factorized_encoding(identity rotations, two ranks with the same spectrum) and via the direct diagonal BE.Jacobi eigendecomposition: random real symmetric matrices with dim ∈ {2, 4, 8, 16, 32}, eigenvalues compared against
numpy.linalg.eigh, plus checks of the reconstruction \(V\mathrm{diag}(\lambda)V^{\mathsf T}\) and orthogonality.DF block encoding across ranks and scales: 2×2 double rank + scalar (
from_symmetricpreprocessing, full-unitary extraction), 4×4 three ranks with random orthogonal rotations (full-unitary extraction), 8×8 double rank (reference + rir); the expected matrices are assembled independently with numpy, and α is compared against the closed form \(|\mathrm{scalar}|+\sum_r\lVert g_r\rVert_1\).
Case |
Scale |
Paths |
Metric |
Value |
|---|---|---|---|---|
|
dim 2/4/8, α=2.0/3.25/4.0 |
originir-ext + to_matrix, three-backend cross |
max_error |
5.6e-17 / 5.6e-17 / 1.1e-16 |
|
dim 16/32/64 |
reference + rir |
max_error |
1.1e-16 / 1.0e-16 / 1.1e-16 |
|
dim 4 (two paths) |
reference |
max_error |
5.6e-17 |
|
5 groups |
independent classical cross-check |
reconstruction / eigenvalue / orthogonality error |
≤6.2e-13 / ≤5.7e-14 / ≤7.3e-15 |
|
rank 2 + scalar, α=5.05 |
to_matrix + three paths |
max_error / α − closed form |
4.4e-16 / −8.9e-16 |
|
rank 3, α=8.24 |
to_matrix + reference |
max_error |
1.6e-15 |
|
rank 2 + scalar 0.7 |
reference + rir |
max_error |
1.2e-15 |
Reproduction command:
PYTHONPATH=src /path/to/backend/python tests/verification/verify_blockencoding.py
Artifacts: out/verification/blockencoding.json.