Skip to content

Implement Y basis initialization/measurement block#719

Open
inmzhang wants to merge 45 commits into
mainfrom
feat/y-basis-block
Open

Implement Y basis initialization/measurement block#719
inmzhang wants to merge 45 commits into
mainfrom
feat/y-basis-block

Conversation

@inmzhang
Copy link
Copy Markdown
Contributor

@inmzhang inmzhang commented Oct 3, 2025

This PR implements the inplace Y-basis initialization and measurement block. Closes #548.

Circuit Construction

Craig’s original circuit is designed under the fixed-bulk convention with an X-top boundary. The memory round uses S-shaped CX ordering for X stabilizers and N-shaped ordering for Z stabilizers. At first, I thought we could simply rotate and reflect the circuit to obtain versions for all conventions and boundary orientations. However, it turns out that the CX ordering in the memory round before/after the Y-basis block matters: the interaction ordering within the Y-basis block must be adjusted accordingly to avoid tricky space/time/spacetime-like errors that would reduce the circuit distance.

The challenging part of the circuit is the transition round, which transforms the code patch between a normal surface code patch and a degenerate patch with no encoded qubit. Careful design of the diagonal twist line, the domain wall orientation, and the interaction ordering is needed to achieve good logical performance. I do not yet have a systematic method for designing such circuits, but by following the pattern of the original circuit, I have worked out correct versions for all conventions and boundary orientations (three variants in total, since two conventions share the same circuit with a Z-top boundary). Key points include:

  1. Use reverse ordering of the memory round during the transition round.
  2. Ensure the circuit realizes the walk-then-merge operation by adjusting certain interactions in the transition round. This creates the expected domain wall and twist line topologically.
  3. If circuit distance decreases, try using the other diagonal for the twist line, and choose different corners for the single MY operation to avoid near-twist spacetime-like errors.

Here are the final Crumble circuits for a Y-basis initialize-then-measure experiment:

Implementation

Initially, I tried to use the existing RawCircuitLayer to implement the Y-basis block within the current architecture. However, I found it difficult to align and merge layers with symbolic linear expressions of k. For example, the Y-basis block has 1 + k + 1 layers, while regular cubes have 1 + (2k - 1) + 1 layers. To handle this, we would need to unroll the repetition layers depending on the value of k, then align the layers at either the head or the tail for merging. On top of that, significant changes would be required to support detector annotations in RawCircuitLayer, since the current approach is based on template and plaquette concepts. While it still seems possible to implement the Y-basis block with this layered approach, it would require too much work.

The current implementation of Y-basis blocks is spacetime-oriented. In this design, a YHalfCube can only connect temporally to other cubes and is spatially distinct from surrounding cubes. This makes it natural to construct the circuits for the main computation and the “temporally injected” Y-basis blocks separately, then align and merge them at the circuit level. The bulk of detectors is built independently for each circuit; we only need to add the missing detectors at the injection interface during merging. With this in mind, I introduced a new block type called InjectedBlock, which includes a factory callable that generates both the Y-basis block circuit and its detector-flow interface. The injected blocks are attached to the LayerTree. After building the main circuit from the LayerTree, I iterate through the injected blocks, aligning and merging their circuits layer by layer. The missing detectors are then computed from the flow interface and added.

Circuit alignment and merging is the most challenging part. We need to carefully track flows and measurement records to correctly update existing detector and observable definitions. I relied heavily on the gen package, which I used to convert stim circuits into gen.Layers (with layer type information) and to merge two gen.LayerCircuits using a simple merging strategy. The current implementation has only minimal checks on circuit structure and may not work reliably for more generic injected circuits. However, it works for the specific Y-basis block circuits tested so far.

Since I used gen extensively during both construction and merging, I also ran into a few small issues with the package that required modifying its source code. For this reason, I created a local copy of the repository, clarifying the license and documenting my modifications in the README. In the long run, it would be preferable to re-implement the most useful functionality from gen directly in TQEC, but this was the fastest way to get things working.

So far, I have only tested compilation with Y-basis blocks in a simple Y-memory experiment and in an S-gate teleportation experiment. A working example of the S-gate has been added to the gallery in the docs. There may still be bugs for more complex computational structures that I haven’t tested yet. We will also need more meaningful test cases involving Y-basis blocks. Additionally, the implementation is not optimized for performance, and there is plenty of room for speed improvements. For example, all the circuits are flattened (unloop) during circuit merging for simplicity while for a larger computation most layers require no flatten operation at all. That said, the feature is already usable under this feature branch.

References

…ation to the layer tree with metadata stored in `SequencedLayer`
@inmzhang inmzhang self-assigned this Oct 3, 2025
@inmzhang inmzhang added enhancement New feature or request, may not be in the task flow backend Issue pertaining to the Python backend (tqec package) labels Oct 3, 2025
@inmzhang
Copy link
Copy Markdown
Contributor Author

@KabirDubey When checking the test coverage for y_basis.py, I noticed that the “ANTI” diagonal type is never used, and the same goes for get_new_boundary_for_basis and get_old_boundary_for_basis. While a Y-basis circuit with an “ANTI” diagonal twist line can be constructed for certain interaction orderings, it’s not needed for any of the TQEC variants. Moreover, the circuit-building logic would definitely need changes to support the ANTI diagonal case. I also found that the abstractions for twist lines, boundary regions, and geometry aren’t particularly helpful — they mainly serve as data containers and seem a bit overengineered. Therefore, I’m inclined to safely revert your changes made to y_basis.py, which would significantly reduce the code size. Are you okay with that?

@KabirDubey
Copy link
Copy Markdown
Contributor

@KabirDubey When checking the test coverage for y_basis.py, I noticed that the “ANTI” diagonal type is never used, and the same goes for get_new_boundary_for_basis and get_old_boundary_for_basis. While a Y-basis circuit with an “ANTI” diagonal twist line can be constructed for certain interaction orderings, it’s not needed for any of the TQEC variants. Moreover, the circuit-building logic would definitely need changes to support the ANTI diagonal case. I also found that the abstractions for twist lines, boundary regions, and geometry aren’t particularly helpful — they mainly serve as data containers and seem a bit overengineered. Therefore, I’m inclined to safely revert your changes made to y_basis.py, which would significantly reduce the code size. Are you okay with that?

Yes! Sorry, I tried to come up with something that can systematically generate layers but I couldn't figure out how to specify the geometric constraints. What remained was a lot of dead code. You might be able to replace with simple helper functions taking distance, top_boundary_basis, convention as parameters but also a total reversion makes complete sense as well.

@inmzhang
Copy link
Copy Markdown
Contributor Author

inmzhang commented Oct 17, 2025

After adding more tests involving Y-basis blocks, I found additional issues. For example, the following structure compiles into a circuit whose logical observable anti-commutes with the reset, which clearly indicates a problem in circuit construction or merging.

图片

And this structure
图片

produces the following distances:

Convention       k          Distance       Expected
--------------------------------------------------------
Fixed-bulk       1            3                3
Fixed-bulk       2            5                5
Fixed-bulk       3            6                7
Fixed-boundary   1            2                2
Fixed-boundary   2            3                4
Fixed-boundary   3            4                5

I need more time to identify the root cause of the issue and find a fix.

@KabirDubey
Copy link
Copy Markdown
Contributor

The last layers of the Crumble example distance 5 Y basis initialization circuit are a particular pattern of MPPs. Gidney says "the measurement process is finished by destroying the patch by measuring all of its data qubits. To maximize code distance, each data qubit is measured in the basis of its closest boundary." I haven't figured out how that implies the exact pattern we see in the circuit but I see that your Crumble circuit does not do the same, right? Do we pay the price in code distance?

@inmzhang
Copy link
Copy Markdown
Contributor Author

The last layers of the Crumble example distance 5 Y basis initialization circuit are a particular pattern of MPPs. Gidney says "the measurement process is finished by destroying the patch by measuring all of its data qubits. To maximize code distance, each data qubit is measured in the basis of its closest boundary." I haven't figured out how that implies the exact pattern we see in the circuit but I see that your Crumble circuit does not do the same, right? Do we pay the price in code distance?

No, it’s not that issue. The data qubit measurements you mentioned correspond to the final twist line, which is orthogonal to the one constructed by the stabilizer walking operation. My circuit already accounts for that by design.

I haven’t started investigating the problem yet, but I’ll update once I have a more precise idea of its root cause.

@KabirDubey
Copy link
Copy Markdown
Contributor

The last layers of the Crumble example distance 5 Y basis initialization circuit are a particular pattern of MPPs. Gidney says "the measurement process is finished by destroying the patch by measuring all of its data qubits. To maximize code distance, each data qubit is measured in the basis of its closest boundary." I haven't figured out how that implies the exact pattern we see in the circuit but I see that your Crumble circuit does not do the same, right? Do we pay the price in code distance?

No, it’s not that issue. The data qubit measurements you mentioned correspond to the final twist line, which is orthogonal to the one constructed by the stabilizer walking operation. My circuit already accounts for that by design.

I haven’t started investigating the problem yet, but I’ll update once I have a more precise idea of its root cause.

I'm asking generally, not as an explanation for the bug (I haven't looked into that yet either). Are you saying that your circuit implements an equivalent data qubit measurement?

@inmzhang
Copy link
Copy Markdown
Contributor Author

The last layers of the Crumble example distance 5 Y basis initialization circuit are a particular pattern of MPPs.

MPPs are used for terminating the out flows from the initialization circuit for demonstration purpose. MPP is not a real physical operation available in superconducting qubits. In a Y-basis memory experiment, there are no MPPs. The out flows from Y basis initialization are terminated by Y basis measurement circuit instead.

Gidney says "the measurement process is finished by destroying the patch by measuring all of its data qubits. To maximize code distance, each data qubit is measured in the basis of its closest boundary."

This is under the context of Y-basis measurement (the reverse of initialization). At the final layer of Y-basis measurement, we measure (near) half of data qubits in X basis and others in Z basis to form a twist line and preserve distance as well. You can see from the Crumble links in this PR that all the circuits have implemented the data qubit reset/measurements in a similar pattern at the first/last layer.

@github-actions
Copy link
Copy Markdown

Code Coverage

Package Line Rate Complexity Health
src.tqec 100% 0
src.tqec.circuit 96% 0
src.tqec.circuit.schedule 99% 0
src.tqec.compile 92% 0
src.tqec.compile.blocks 97% 0
src.tqec.compile.blocks.layers 95% 0
src.tqec.compile.blocks.layers.atomic 97% 0
src.tqec.compile.blocks.layers.composed 99% 0
src.tqec.compile.detectors 89% 0
src.tqec.compile.observables 99% 0
src.tqec.compile.specs 97% 0
src.tqec.compile.specs.library 97% 0
src.tqec.compile.specs.library.generators 98% 0
src.tqec.compile.tree 67% 0
src.tqec.compile.tree.annotators 84% 0
src.tqec.computation 96% 0
src.tqec.gallery 100% 0
src.tqec.interop 90% 0
src.tqec.interop.collada 94% 0
src.tqec.interop.pyzx 85% 0
src.tqec.interop.pyzx.synthesis 91% 0
src.tqec.plaquette 90% 0
src.tqec.plaquette.compilation 100% 0
src.tqec.plaquette.compilation.passes 95% 0
src.tqec.plaquette.compilation.passes.transformer 99% 0
src.tqec.plaquette.rpng 95% 0
src.tqec.plaquette.rpng.translators 97% 0
src.tqec.post_processing 82% 0
src.tqec.post_processing.utils 96% 0
src.tqec.templates 94% 0
src.tqec.utils 96% 0
Summary 93% (8117 / 8748) 0

@github-actions
Copy link
Copy Markdown

A preview of bcad2d8 is uploaded and can be seen here:

https://tqec.github.io/tqec/pull/719/

Changes may take a few minutes to propagate.

@inmzhang
Copy link
Copy Markdown
Contributor Author

I used this block graph for debugging and noticed that some detectors include unnecessary measurements during the split step. As a result, they form hyperedges in the decoding graph, which reduces the circuit distance when searching for graphlike logical errors. You can see these hyper-detectors at the right boundary of the left logical patch in the detslice diagram.

图片 图片

This issue arises from calling gen.ChunkSemiAuto.solve() when we attempt to automatically solve the flows from the split round to the Y-basis measurement rounds. Internally, it calls stim.Circuit.solve_flow_measurements(), which does not guarantee that the chosen solution measurements are minimal.

In the latest commits, I applied a temporary workaround: first compute all flows from the split fragment using tqecd, then perform a one-to-one match to the expected end stabilizers—i.e., the start stabilizers required by the Y-basis transition round. After that, we call gen.ChunkSemiAuto.solve() only on the remaining unsolved flows. With this approach, the circuit distances for all the cases mentioned above now match the expected values.

However, this fix is fragile and far from elegant. Ideally, we should move toward using flow annotations for more efficient detector computation. If possible, I expect this PR to remain open for a while so we can revisit and rework it once the improved architecture is available.

@KabirDubey
Copy link
Copy Markdown
Contributor

KabirDubey commented Feb 22, 2026

Thanks Yiming, I will look into this tomorrow and this week.

In the latest commits, I applied a temporary workaround: first compute all flows from the split fragment using tqecd, then perform a one-to-one match to the expected end stabilizers—i.e., the start stabilizers required by the Y-basis transition round. After that, we call gen.ChunkSemiAuto.solve() only on the remaining unsolved flows. With this approach, the circuit distances for all the cases mentioned above now match the expected values.

where can I find your implementation of the "one-to-one match to the expected end stabilizers"? Is it here? It's not clear to me that this is fragile. The function _solve_semi_auto_flows_ensure_single_source looks fragile, I'll need to take some time to figure out how it works and test it.

Ideally, we should move toward using flow annotations for more efficient detector computation.

Wouldn't this call gen.ChunkSemiAuto.solve(), which generates excessive solution measurements for the spatial arm part? I can look into refactoring tqecd to use ChunkCompiler. I suppose this would make it easier for us to integrate other circuits which Gidney designs and sources, like MSC. However, note here he says "It changes from paper to paper and isn't really bullet proofed... so don't expect stability."

@KabirDubey
Copy link
Copy Markdown
Contributor

Looks like even the hybrid annotator is not working perfectly. Here's the LER for the "claw" plot from here.

my screenshots 2026-02-26 at 3 32 55 PM

Still better than puretqecd annotator:

U_tqecd_ler

But not as good as the pure tqecd annotator on the S gate and Y memory experiment block graph results:

my screenshots 2026-02-26 at 3 46 03 PM my screenshots 2026-02-26 at 3 46 56 PM my screenshots 2026-02-26 at 3 44 57 PM

I will next debug by modifying tqecd (starting with Tianyi's tqecd PR 45) and verifying if buggy circuit distances are preserved.

@KabirDubey
Copy link
Copy Markdown
Contributor

Is this block graph expected to fail correlation-surface-finding? Cube in the middle is ZXZ, it's connected to opposite nodes along one spatial axis but like nodes along the other.

my screenshots 2026-02-26 at 4 37 06 PM

my screenshots 2026-02-26 at 4 37 30 PMm

@KabirDubey
Copy link
Copy Markdown
Contributor

Looks like even the hybrid annotator is not working perfectly. Here's the LER for the "claw" plot from here.
my screenshots 2026-02-26 at 3 32 55 PM

Note this depicts k=1 --> 2, k=2 --> 4, k=3 --> 5 whereas pure tqecd is k --> 1 for all k.

@KabirDubey
Copy link
Copy Markdown
Contributor

I will next debug by modifying tqecd (starting with Tianyi's tqecd PR 45) and verifying if buggy circuit distances are preserved.

Still not working. Will update tqecd issue 48, we can work on buffing tqecd up directly to get these circuits working there.

@HaoTy
Copy link
Copy Markdown
Collaborator

HaoTy commented Feb 27, 2026

Is this block graph expected to fail correlation-surface-finding? Cube in the middle is ZXZ, it's connected to opposite nodes along one spatial axis but like nodes along the other.

my screenshots 2026-02-26 at 4 37 06 PM my screenshots 2026-02-26 at 4 37 30 PMm

If it's a valid block graph, the algorithm will find the correlation surfaces successfully.

@KabirDubey
Copy link
Copy Markdown
Contributor

Looks like even the hybrid annotator is not working perfectly. Here's the LER for the "claw" plot from here.
my screenshots 2026-02-26 at 3 32 55 PM

Note what is pictured above is the fixed boundary convention, not the fixed bulk. The fixed bulk convention with the hybrid annotator has the expected circuit distance. See here for more.

@smburdick
Copy link
Copy Markdown
Collaborator

@KabirDubey @inmzhang Do you still plan on finishing this?

@inmzhang
Copy link
Copy Markdown
Contributor Author

@KabirDubey @inmzhang Do you still plan on finishing this?

Hi Sam, I don’t have time to finish this PR at the moment. I’ve provided the necessary circuit here and hope someone can pick it up and explore a better way to integrate it into the TQEC framework.

That said, I’ll try to catch up on the changes in the TQEC repo and get back to reviewing PRs later this week.

@KabirDubey
Copy link
Copy Markdown
Contributor

@KabirDubey @inmzhang Do you still plan on finishing this?

Yes, but I'm too busy at the moment. The starting point is in the tqecd issue I am assigned to, so progress can be tracked there. If someone else that is more available than me wants to take the job up, I'm happy to pass the torch and offload my understanding of the task. Thanks for the organizational work you've been doing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend Issue pertaining to the Python backend (tqec package) enhancement New feature or request, may not be in the task flow

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Y-Basis Initialization and Measurement

7 participants