Refactor + Optimize Fermion-to-Qubit Infrastructure with MajoranaMapping#475
Draft
wavefunction91 wants to merge 118 commits into
Draft
Refactor + Optimize Fermion-to-Qubit Infrastructure with MajoranaMapping#475wavefunction91 wants to merge 118 commits into
wavefunction91 wants to merge 118 commits into
Conversation
… commuting pauli strings" This reverts commit b55ca4a.
…w energy_estimator
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…n' into feature/agamshayit/time_evolution
Generalize MajoranaMapping from "table of per-Majorana Pauli images" to
"fermion-to-qubit encoding," exposing the bilinear i*gamma_j*gamma_k as
the unified primitive that works in every encoding (including future
redundant encodings such as Bravyi-Kitaev superfast, Verstraete-Cirac,
and Derby-Klassen, where individual Majoranas have no Pauli image).
C++ (data/majorana_mapping.{hpp,cpp}):
- New bilinear(j, k) -> (complex, SparsePauliWord), computed via
PauliTermAccumulator::multiply_uncached with the
i * phase_j * phase_k prefactor. Throws out_of_range /
invalid_argument.
- New majorana(k) alias for operator()(k).
- New introspection hooks reserved for redundant encodings:
is_majorana_atomic() (true), stabilizers() (empty),
parity_sector() (0).
- Expanded Doxygen with references (Chen-Xu-Boettcher 2023;
Jiang-Kalev-Mruczkiewicz-Neven 2020).
Pybind11 + Python wrapper:
- Bind bilinear, majorana, is_majorana_atomic, stabilizers,
parity_sector. Map invalid_argument -> ValueError,
out_of_range -> IndexError.
- Document that for tapered encodings (e.g. SCBK) returned Pauli
strings are in the pre-taper basis (len(table[0])), with tapering
applied downstream by the qubit mapper.
Docs:
- New "Bilinears as the unified primitive" section in the
MajoranaMapping user doc; BdG / MZM clarifications; references.
Tests (TestBilinear, TestEncodingMetadata):
- Parametrized over JW / BK / parity x n_modes in {2,3,4,6}; verify
bilinear(j,k) == i*gamma_j*gamma_k, antisymmetry,
(i*gamma_j*gamma_k)^2 = I, commutation / anticommutation by
shared-index count, Hermitian (real +/-1 coefficient).
- Hand-computed JW(n=2) values, error cases, and SCBK pre-taper
length check.
All additions are backward-compatible; no public API was removed.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This was
linked to
issues
May 20, 2026
…t-operators Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
📊 Coverage Summary
Detailed Coverage ReportsC++ Coverage DetailsPython Coverage DetailsPybind11 Coverage Details |
- Add BK-tree factory (MajoranaMapping.bravyi_kitaev_tree) and fix SCBK to use BK-tree as base encoding (works for non-power-of-2 modes) - Fix parity encoding to match standard convention (Qiskit-compatible) - Fix UHF BBAA ERI index ordering (eri_aabb[r,s,p,q] not [p,q,r,s]) - Fix HDF5 round-trip for phases and tapering metadata - Propagate tapering through QubitHamiltonian arithmetic and interleave - Handle tapering in QubitMapper.run() base class for all backends - Document F2Q dispatch contract: table-driven (QDK) vs name-dispatched (OpenFermion, Qiskit) backends, with inline comments and RST docs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- M2: Use 1e-12 threshold (not eps) for near-zero filtering in taper_qubits - M6: Return zero-coefficient identity on full cancellation instead of ValueError - M1: taper_to_scbk sets TaperingSpecification on output QubitHamiltonian - M5: Transpose h2_ba for Qiskit UHF — (aa|bb) → (bb|aa) per Qiskit convention - L2: MajoranaMapping repr shows tapered=N when tapering is present - Add tests for zero-operator return and taper_to_scbk tapering metadata Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…/microsoft/qdk-chemistry into session/majorana-qubit-operators
These fields were always empty for the Majorana-atomic encodings the class produces and were never read by the mapping engine, validation, or any consumer. Codespace metadata, if ever needed for redundant encodings, is derivable from the encoding and belongs to the consuming algorithm. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… from C++ Remove phases (dead code — no factory produced negative phases), Clifford validation, and dense-string handling from the C++ and pybind layers. C++/pybind boundary now uses SparsePauliWord exclusively; Python owns dense little-endian string conversion via _dense_le_to_sparse / _sparse_to_dense_le helpers. Public Python API unchanged (still returns strings). Consolidate majorana_map_engine.hpp into majorana_mapping.hpp. Rename is_restricted → is_spin_free in the engine (documents the actual semantic). Note the spin-free-only limitation on majorana_map_hamiltonian. Minimize docs: strip speculative encoding references and validation language from docstrings and RST. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Engine: - Replace anonymous namespaces with namespace detail - Snake-case constants (excitation_coeff, inline 0.25/0.0625) - Portable C++20: std::popcount, std::countr_zero (no __builtin_) - Use utils::hash_combine instead of ad-hoc hash - Dispatch table covers NW 1..16 (up to 1024 qubits); error beyond - Merge αβ/βα cross-spin loops via Coulomb symmetry (pq|rs)=(rs|pq) Terminology: - Rename is_spin_free → spin_symmetric throughout (C++, pybind, Python) - Spin-free = Hamiltonian has no spin operators (always true for standard electronic H). Restricted/unrestricted = orbital basis choice. The flag controls the spin-summed fast path, which requires spin-symmetric integrals — a consequence of restricted orbitals. MajoranaMapping: - Add from_bilinears() factory for bilinear-only encodings (C++, pybind, Python). Supports encodings where individual Majoranas have no Pauli image; only bilinear(j,k) is available. - Minor doc updates for the two construction forms. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace the public MajoranaMapping constructor with from_table() for symmetry with from_bilinears(). Both are named static factories; the actual constructors are private. Add unit tests for from_bilinears: basic construction, bilinear lookup matches table-derived values, antisymmetry, and majorana() raises for bilinear-only mappings. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Extract JW/BK/BK-tree/parity factory methods and BK index-set helpers into majorana_mapping_factories.cpp (313 lines). Core class stays in majorana_mapping.cpp (150 lines, down from 492). Also rename OP_X/OP_Y/OP_Z to op_x/op_y/op_z (snake_case) in the factories file. Fix all docs examples to use hamiltonian.get_orbitals(). get_num_molecular_orbitals() instead of the fragile hamiltonian.get_one_body_integrals()[0].shape[0] pattern. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
from qdk_chemistry.data import MajoranaMapping (not the private module path). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove 'tapering is applied downstream', 'passed to Algorithm.run', 'used by QubitMapper' boilerplate from method/property docstrings. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Build pair product caches from mapping.bilinear() instead of mapping(k) + manual packed multiply. This makes the engine work with both Majorana-atomic and bilinear-only mappings. Pair products store complex coefficients (γ_j·γ_k = -i·bilinear(j,k)) rather than integer phase indices. accumulate_epq now uses the same pair caches as the two-body loops. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
from_table() precomputes all M*(M-1)/2 bilinears from the Majorana table at construction. bilinear() is now always an O(1) lookup regardless of construction form — no dispatch, no on-demand Pauli multiply. Unified to a single private constructor; majorana_atomic_ derived from whether the table is populated. bilinear() returns a const reference to the cached word. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
from_bilinears: add num_qubits, wrong count, missing entry, out-of-range, equal-indices error tests (5 new). Sparse/dense conversion helpers: roundtrip identity, single Pauli, JW table, invalid character, case insensitivity (5 new). Serialization backward compat: JSON and HDF5 files with old 'phases' key/dataset deserialize without error (2 new). Bilinear caching: verify cached bilinear(j,k) matches manual Pauli multiply of table entries for all factory encodings (1 new, parametrized across 3 encodings). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
wavefunction91
commented
May 30, 2026
|
|
||
|
|
||
|
|
||
| class MajoranaMapping(DataClass): |
Collaborator
Author
There was a problem hiding this comment.
This should just be the C++ class exposed to python.
|
|
||
| __all__: list[str] = [] | ||
|
|
||
| # Sparse op_type codes used by the C++ layer: 1=X, 2=Y, 3=Z (0/identity omitted). |
Collaborator
Author
There was a problem hiding this comment.
Don't we handle this elsewhere in the code? e.g. in the pauli arithmetic library?
| @@ -0,0 +1,236 @@ | |||
| """Internal qubit tapering utilities for symmetry-conserving encodings. | |||
Collaborator
Author
There was a problem hiding this comment.
All of these functions should live in the data tapering module.
| EncodingMismatchError, | ||
| MajoranaMapping, | ||
| QubitHamiltonian, | ||
| validate_encoding_compatibility, |
Collaborator
Author
There was a problem hiding this comment.
I want validate_encoding_compatibility completely removed from the code base
- Remove validate_encoding_compatibility and EncodingMismatchError entirely - Move taper_qubits from utils/tapering.py to data/tapering.py - Trim MajoranaMapping class docstring Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Tests (90 → 43): - Drop trivial getter/metadata/immutability/display/cross-encoding tests - Drop redundant serialization, bilinear antisymmetry/hermitian/caching tests - Drop stale test_majorana_consistent_with_call and sparse conversion micro-tests - Fix stale test_scbk_factory_creates_bk_table → compares against bk_tree - Add test_without_tapering Docs: - Fix pybind class docstring (was missing bilinear-only form) - Fix RST 'stabilizers' reference (removed feature term) - Trim C++ class doxygen, pybind table property docstring - Trim verbose factory docstrings (BK-tree, parity, SCBK) - Trim num_qubits docstring - Drop BK superfast reference from test class docstring Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This pull request introduces a new, encoding-agnostic Majorana mapping engine for fermion-to-qubit transformations in the chemistry package, along with a new
MajoranaMappingdata class. The API for the QubitMapper is updated to require an explicitMajoranaMappingargument, and the documentation and examples are revised to reflect these changes. Additional minor improvements and documentation updates are included.Majorana Mapping Engine and Data Class:
majorana_map_engine.hppandmajorana_mapping.hpp, defining a newMajoranaMappingclass for representing fermion-to-qubit encodings and a mapping engine (majorana_map_hamiltonian) that transforms fermionic Hamiltonians to Pauli strings using arbitrary encodings. Factory methods for standard encodings (Jordan-Wigner, Bravyi-Kitaev, Parity) are provided. [1] [2]API and Example Updates:
MajoranaMappingargument, removing the previous string-based"encoding"configuration. Examples now explicitly construct the mapping and pass it to the mapper. [1] [2] [3]MajoranaMappingargument and its usage, including how to construct standard or custom encodings. [1] [2]New and Improved Usage Examples:
Minor Documentation and Import Fixes: