Skip to content

Reorganize qldpc.codes.distance into subpackages by method - #845

Merged
perlinm merged 7 commits into
mainfrom
refactor/distance-layout
Nov 12, 2026
Merged

perlinm merged 7 commits into
mainfrom
refactor/distance-layout

Conversation

@perlinm

@perlinm perlinm commented Nov 12, 2026 •

Copy link
Copy Markdown
Collaborator

Motivation

The review of qldpc.codes.distance that led to #841 also looked at how the package is organized. The package had one _search/ subpackage that mixed the drivers of three methods, the information-set machinery that they share, and compiled kernels. Its order was a convention that no test checked. Two hub modules each held several concepts: information_sets.py (1,199 lines) held basis families, certificates, step planning, and the support stepping of every scan, and coset_leader_search.py (2,210 lines) held the coset-leader query, the Brouwer–Zimmermann coset searches, their tables and tails, the connected-support coset searches, and the helpers they share. Modules outside the package imported the coset-leader search from that deep private path. This PR changes no behavior. It moves code so that each concept that a user or a change request names has one obvious module, and the layers of the package are checked by its layering test.

Changes

  • Layout. The top level of distance/ holds the entry modules (core.py, logical_counts.py, and the private _coset_leader_search.py, which circuits/certification and the experimental residual-weight estimator import), _brute_force.py, _cosets.py, _tuning.py, and _binary.py. The machinery goes into private subpackages:

    • _brouwer_zimmermann/: the distance search (distance.py), the coset searches (coset.py) with their tables and tails (coset_tables.py) and routes (coset_routes.py), and the packed instances and compiled scans that both share;
    • _connected_support/: the search (search.py) and its coset searches (coset.py);
    • _information_sets/: information_sets.py split into basis_families.py, certificates.py, and support_stepping.py, beside the existing automorphism-family, completion-bound, and matroid-partition modules;
    • _counting/: unchanged.

    The README of the package gains a short account of the layout, and its map and dependency levels follow it.

  • Layers. The layering test of the package, now _layering_test.py, orders _binary, _tuning, (_brute_force, _information_sets, _cosets), (_brouwer_zimmermann, _connected_support, _counting), (_coset_leader_search, core), and logical_counts. A unit may import only from itself and lower layers, so the test also records that the methods are independent of each other, and the two entry modules too.

  • Commits 1 and 2 are moves. Moved objects keep their names and bodies, so git diff -M --color-moved=dimmed-zebra shows them as moves. Imports, string patch targets, and test helpers follow the code.

  • Commit 3 adds tests so that each new module is fully covered by its own test file, as the coverage gate requires. Commit 4 updates the guides, docstrings, and module.name references.

  • Commit 5 renames. The code standard asks private modules to use plain names for what other modules use, so the 23 underscore names that now cross module boundaries lose their underscore, such as get_stopping_step and WORK_CAP. Three get clearer names: the Brouwer–Zimmermann coset search becomes BrouwerZimmermannCosetSearch, beside ConnectedSupportCosetSearch; _get_inverse becomes get_unit_syndrome_words, since its rows are the transpose of a right inverse; and _packed_row_int becomes words_to_int, the inverse of int_to_words. The test helpers that several test files now share get plain names too.

  • Commit 6 holds the revisions after review: references that the splits left pointing into other modules now give their paths, a few test helpers and private attributes get names that say what they do, the README and guides are tidied, and new cases test the order in which the tables of single errors keep their words.

  • Commit 7 renames the layering tests of qldpc.circuits, qldpc.decoders, and qldpc.codes.distance to _layering_test.py, like _code_style_test.py, since they test no module of their own.

Validation

  • Each move commit was checked for pure moves by listing every added line that matches no removed line of the same commit, after normalizing module qualifiers. What remains is imports, module docstrings, rewrapped lines, and the manual edits named above. Undoing the renames of commit 5 on its tree leaves only the move of one function, lines rewrapped for longer names, and the docstrings of the renamed functions.
  • Each commit passes on its own the tests of distance/, circuits/certification, the residual-weight estimator, and the style and compilation tests.
  • The object graph of the package, recomputed on the new layout, has the same 357 objects and 760 references. The largest module shrinks from 2,210 lines to about 1,100, and no module outside the package imports anything but core.py or _coset_leader_search.py.

Notes

  • Left as they are, on purpose: _connected_support/search.py keeps its distance driver, which is about 110 lines over the shared search; the basis-family transport stays in _counting/scan.py; CosetRoutes keeps its generic parameters, which let its tests use light stand-ins for the tables and tails; and _coset_leader_search.py still builds the cache keys of the Brouwer–Zimmermann coset searches itself, which factories in _brouwer_zimmermann/coset.py could hide in a later change.
  • Four connected-support coset tests move to _connected_support/coset_test.py, whose module defines no compiled functions, so the --compiled-module-tests run no longer collects them. They still run compiled in the --compile-search-setup run of the distance tests, which compiles all compiled code.

perlinm and others added 5 commits November 12, 2026 10:15
Split `_search/` by role.  Each method gets one home: `_brute_force.py`,
`_brouwer_zimmermann/` (the distance search, its packed instances, the
compiled scans of layers, and the coset routes), and
`_connected_support/search.py`.  The information-set machinery that the
searches and counts share moves to `_information_sets/`, where
`information_sets.py` splits into `basis_families.py`, `certificates.py`,
and `support_stepping.py`.  `coset_leader_search.py` moves up to
`_coset_leader_search.py`, the private entry module of the coset-leader
search.

The moves change no behavior.  Imports, test helpers, the layers that
`layering_test.py` enforces, and the paths that the guides cite follow the
new layout.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
`_coset_leader_search.py` keeps `CosetLeaderSearch` and the queries that
split a syndrome class into coset searches.  The coset searches move to
their methods: the Brouwer-Zimmermann ones to `_brouwer_zimmermann/coset.py`,
with the tables of their steps and tails in
`_brouwer_zimmermann/coset_tables.py`, and the connected-support ones to
`_connected_support/coset.py`.  What both methods share, including
`MinWeightBound`, moves to `_cosets.py`, a layer below the methods.
External modules still import from `_coset_leader_search.py`.

The tests follow their code, and helpers that several test files use move
to `conftest.py`.  The moves change no behavior.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Each module must be fully covered by its own test file, and the splits
left code that only other modules' tests reached.  Add direct tests of the
shared coset parts in `_cosets.py`, of the search tables and first steps
in `coset_tables.py`, of BZ coset searches by CSS weight, of the
certificate checks and work estimates for arrays in `certificates.py`, and
of batches of connected-support searches by CSS weight.  Two tests of
`CosetLeaderSearch` itself move back to its test file.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The README gains a short account of the layout, and its map of where to
look and its levels of dependency follow the subpackages, with the order
of the modules within each.  The code maps of both guides, the module
docstrings that described the old modules, and the references of the form
`module.name` name the modules where the code now lives.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The splits made 22 underscore names of the new private modules cross
module boundaries, and `_WORK_CAP` already did.  The code standard asks
private modules to use plain names for what other modules use, so these
lose their underscore.  Two get clearer names: `_CosetSearch` becomes
`BrouwerZimmermannCosetSearch`, beside `ConnectedSupportCosetSearch`, and
`_get_inverse` becomes `get_unit_syndrome_words`, since its rows are the
transpose of a right inverse.  `_packed_row_int` becomes `words_to_int`,
the inverse of `int_to_words`.  `_get_planning` moves after the plain
names of `coset_tables.py`.

The helpers that several test files share also get plain names, as the
other helpers of `distance/conftest.py` have, in a section of their own.
No behavior changes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@perlinm
perlinm force-pushed the refactor/distance-layout branch from 9caa2a8 to f50c87e Compare November 12, 2026 15:31
perlinm and others added 2 commits November 12, 2026 10:40
Docstrings and comments that cite code in another module now give its
path, and paragraphs that the edits left ragged are filled.  The README
describes `_binary.py` and `_counting/` precisely, says that the method
name "information_sets" is an alias of "brouwer_zimmermann", and its
levels of dependency name the modules without repeating the layout.  The
code map of the coset searches moves to the end of Section 4.1 of
`brouwer_zimmermann.md`, after the terms that it uses, and the tests that
the guide cites without a file name their files.  Text that called the
words with unit syndromes the rows of a right inverse now says what they
are.

Three test helpers get names that say what they do: `get_product_state`
merges into `get_stabilizer_matrix`, which now takes strings too, and
`get_css_minima`, which also gives physical weights, becomes
`get_exhaustive_minima`, whose callers now pass the weight.  The private
attributes of `CosetLeaderSearch` that hold its coset searches are named
for their methods: `_brouwer_zimmermann_searches` and
`_connected_support_searches`.

`tabulate_singles` keeps the first word of each syndrome, with X before Z
before Y on each qubit.  New cases check that order where words on one
qubit, or Z errors on two qubits, share a syndrome.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The tests of the import layers of `qldpc.circuits`, `qldpc.decoders`,
and `qldpc.codes.distance` test no module of their own, so they get a
leading underscore, as `_code_style_test.py` has.  The package docstrings,
the README of the distance package, the code and decoder standards, and
the message that `check_import_layering` prints cite the new names.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@perlinm
perlinm force-pushed the refactor/distance-layout branch from f50c87e to 3d6922b Compare November 12, 2026 15:43
@perlinm
perlinm merged commit eba1dd2 into main Nov 12, 2026
9 checks passed
@perlinm
perlinm deleted the refactor/distance-layout branch November 12, 2026 15:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant