Skip to content

feat(quantum): add abstract qubit protocol - #2206

Draft
ss2165 wants to merge 2 commits into
mainfrom
codex/abstract-qubit-protocol
Draft

ss2165 wants to merge 2 commits into
mainfrom
codex/abstract-qubit-protocol

Conversation

@ss2165

@ss2165 ss2165 commented Aug 14, 2026

Copy link
Copy Markdown
Member

Summary

  • add the public AbstractQubit protocol with descriptive (more verbose than stdlib functions), Self-typed quantum operations
  • make the built-in qubit implement the protocol and retain the existing short-form std.quantum API as generic delegates
  • generalize functional and array quantum operations, with integration coverage for a distinct protocol implementation
  • ideally should follow: [Maintenance]: ruff still checking against python 3.10 #2119

Follow-up

Derived quantum operations such as Toffoli are currently required protocol members. Providing defaults for these operations is tracked by #2205; the protocol contains a matching TODO.

@hugrbot

hugrbot commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

This PR contains breaking changes to the public Python API.
Please deprecate the old API instead (if possible), or mark the PR with a ! to indicate a breaking change.

Breaking changes summary
guppylang/src/guppylang/std/quantum/__init__.py:719: rz(angle):
Parameter was removed

guppylang/src/guppylang/std/quantum/__init__.py:719: rz(theta):
Parameter was added as required

guppylang/src/guppylang/std/quantum/__init__.py:726: rx(angle):
Parameter was removed

guppylang/src/guppylang/std/quantum/__init__.py:726: rx(theta):
Parameter was added as required

guppylang/src/guppylang/std/quantum/__init__.py:733: ry(angle):
Parameter was removed

guppylang/src/guppylang/std/quantum/__init__.py:733: ry(theta):
Parameter was added as required

guppylang/src/guppylang/std/quantum/__init__.py:740: crz(angle):
Parameter was removed

guppylang/src/guppylang/std/quantum/__init__.py:740: crz(theta):
Parameter was added as required


@github-actions

Copy link
Copy Markdown
Contributor

🐰 Bencher Report

Projectguppylang
Branchcodex/abstract-qubit-protocol
TestbedLinux
Click to view all benchmark results
Benchmarkhugr_bytesBenchmark Result
bytes x 1e3
(Result Δ%)
Upper Boundary
bytes x 1e3
(Limit %)
hugr_nodesBenchmark Result
nodes
(Result Δ%)
Upper Boundary
nodes
(Limit %)
tests/benchmarks/test_big_array.py::test_big_array_compile📈 view plot
🚷 view threshold
61.81 x 1e3
(-0.47%)Baseline: 62.10 x 1e3
62.72 x 1e3
(98.55%)
📈 view plot
🚷 view threshold
4,585.00
(0.00%)Baseline: 4,585.00
4,630.85
(99.01%)
tests/benchmarks/test_ctrl_flow.py::test_many_ctrl_flow_compile📈 view plot
🚷 view threshold
27.86 x 1e3
(+0.13%)Baseline: 27.83 x 1e3
28.11 x 1e3
(99.13%)
📈 view plot
🚷 view threshold
1,301.00
(0.00%)Baseline: 1,301.00
1,314.01
(99.01%)
tests/benchmarks/test_queue_push_pop.py::test_queue_push_benchmark_compile📈 view plot
🚷 view threshold
7.24 x 1e3
(0.00%)Baseline: 7.24 x 1e3
7.32 x 1e3
(99.01%)
📈 view plot
🚷 view threshold
310.00
(0.00%)Baseline: 310.00
313.10
(99.01%)
tests/benchmarks/test_queue_push_pop.py::test_queue_push_pop_benchmark_compile📈 view plot
🚷 view threshold
9.91 x 1e3
(0.00%)Baseline: 9.91 x 1e3
10.01 x 1e3
(99.01%)
📈 view plot
🚷 view threshold
411.00
(0.00%)Baseline: 411.00
415.11
(99.01%)
🐰 View full continuous benchmarking report in Bencher

@codspeed

codspeed Bot commented Aug 14, 2026

Copy link
Copy Markdown

Merging this PR will degrade performance by 51.16%

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

❌ 6 regressed benchmarks
✅ 5 untouched benchmarks

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Benchmark BASE HEAD Efficiency
test_circuit_comptime_check 1.4 s 7.1 s -79.76%
test_many_ctrl_flow_check 1.3 s 3.1 s -58.23%
test_big_array_check 11.9 s 26.2 s -54.4%
test_circuit_comptime_compile 10 s 16.1 s -37.74%
test_big_array_compile 35.4 s 50.7 s -30.2%
test_many_ctrl_flow_compile 8.2 s 10.2 s -18.99%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing codex/abstract-qubit-protocol (741b46c) with main (ec1e2e4)

Open in CodSpeed

Comment thread ruff.toml
@@ -1,5 +1,5 @@
# See https://docs.astral.sh/ruff/rules/
target-version = "py310"
target-version = "py312"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is outside the scope of the PR, you can make an exception for your test files at the bottom of ruff.toml

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes sorry pushed local change accidentally

q.crz(self.inner, target.inner, theta)

@guppy(unitary=True)
def toffoli(self, control2: Self, target: Self) -> None:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

toffoli would make more sense as a method that takes something implementing AbstractProtocol.

Generally, we need to think about what the minimal api surface for a qubit should be if we're going to add it to std. Something that's way too broad like seems like a big pain for abstracting logical qubits

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah - hence why I'm unsure about this without defaults

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

going extreme we could take tket1's approach: implement CX and an arbitrary single qubit gate and that's it (I guess also alloc/measure/discard)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer that approach, it just makes things useless for codes that have a different set of native gates (e.g. if CX is costly but CZ is cheap). Maybe we shouldn't spend too much time worry about these cases, since writing around the stdlib for high performance code is the norm

q.toffoli(self.inner, control2.inner, target.inner)

@guppy(unitary=True)
def controlled_hadamard(self, target: Self) -> None:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we have unitary hadamard, we don't need this, we can write

with control(...):
    q.hadamard()

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.

3 participants