Skip to content

feat!: Change the return type of measurement functions to a new Measurement type and remove opaque bools from the compiler#1707

Open
tatiana-s wants to merge 21 commits into
mainfrom
ts/future-measure
Open

feat!: Change the return type of measurement functions to a new Measurement type and remove opaque bools from the compiler#1707
tatiana-s wants to merge 21 commits into
mainfrom
ts/future-measure

Conversation

@tatiana-s
Copy link
Copy Markdown
Contributor

@tatiana-s tatiana-s commented Apr 30, 2026

Closes #1485

Requires a breaking tket release with the extension changes in #1558 before this can be merged

BREAKING CHANGE: (guppylang.std.quantum): measure (and measure_array by extension) now return Measurement instead of bool
BREAKING CHANGE: (guppylang.std.qsystem/qsystem.functional): measure and measure_reset (and by extension the array versions) now return Measurement instead of bool (this matches the behaviour of lazy_measure/lazy_measure_and_reset)
BREAKING CHANGE: (guppylang_internals): bool is now lowered to ht.Bool again instead of tket.bool

The deferred_measurement.ipynb notebook has been adjusted to explain the motivation for the lazy behaviour instead of contrasting measure and lazy_measure

@tatiana-s tatiana-s requested a review from a team as a code owner April 30, 2026 10:36
@tatiana-s tatiana-s requested a review from mark-koch April 30, 2026 10:36
@hugrbot
Copy link
Copy Markdown
Collaborator

hugrbot commented May 5, 2026

This PR contains breaking changes to the public Python API.

Breaking changes summary
guppylang/src/guppylang/std/qsystem/__init__.py:0: collect_measurements:
Public object was removed

guppylang-internals/src/guppylang_internals/definition/custom.py:0: BoolOpCompiler:
Public object was removed

guppylang-internals/src/guppylang_internals/compiler/expr_compiler.py:0: ARRAY_READ_BOOL:
Public object was removed

guppylang-internals/src/guppylang_internals/compiler/expr_compiler.py:0: ARRAY_MAKE_OPAQUE_BOOL:
Public object was removed

guppylang-internals/src/guppylang_internals/compiler/expr_compiler.py:0: array_read_bool:
Public object was removed

guppylang-internals/src/guppylang_internals/compiler/expr_compiler.py:0: array_make_opaque_bool:
Public object was removed

guppylang-internals/src/guppylang_internals/compiler/expr_compiler.py:0: apply_array_op_with_conversions:
Public object was removed

guppylang-internals/src/guppylang_internals/tys/builtin.py:214: bool_type_def:
Attribute value was changed:
Old: OpaqueTypeDef(id=(DefId.fresh()), name='bool', defined_at=None, params=[], never_copyable=False, never_droppable=False, to_hugr=(lambda args, ctx: OpaqueBool))
New: OpaqueTypeDef(id=(DefId.fresh()), name='bool', defined_at=None, params=[], never_copyable=False, never_droppable=False, to_hugr=(lambda args, ctx: ht.Bool))


@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 5, 2026

🐰 Bencher Report

Branchts/future-measure
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
158.29 x 1e3
(-0.30%)Baseline: 158.77 x 1e3
160.36 x 1e3
(98.71%)
📈 view plot
🚷 view threshold
6,630.00
(-0.17%)Baseline: 6,641.00
6,707.41
(98.85%)
tests/benchmarks/test_ctrl_flow.py::test_many_ctrl_flow_compile📈 view plot
🚷 view threshold
26.98 x 1e3
(-2.00%)Baseline: 27.53 x 1e3
27.81 x 1e3
(97.03%)
📈 view plot
🚷 view threshold
1,051.00
(-2.14%)Baseline: 1,074.00
1,084.74
(96.89%)
tests/benchmarks/test_queue_push_pop.py::test_queue_push_benchmark_compile📈 view plot
🚷 view threshold
10.08 x 1e3
(-7.61%)Baseline: 10.91 x 1e3
11.02 x 1e3
(91.48%)
📈 view plot
🚷 view threshold
300.00
(-2.60%)Baseline: 308.00
311.08
(96.44%)
tests/benchmarks/test_queue_push_pop.py::test_queue_push_pop_benchmark_compile📈 view plot
🚷 view threshold
13.88 x 1e3
(-6.44%)Baseline: 14.84 x 1e3
14.99 x 1e3
(92.64%)
📈 view plot
🚷 view threshold
423.00
(-2.76%)Baseline: 435.00
439.35
(96.28%)
🐰 View full continuous benchmarking report in Bencher

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented May 5, 2026

Merging this PR will not alter performance

✅ 9 untouched benchmarks


Comparing ts/future-measure (9405b97) with main (17282cd)

Open in CodSpeed

@ss2165 ss2165 requested review from maximilianruesch and removed request for mark-koch May 18, 2026 09:07
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented May 20, 2026

Codecov Report

❌ Patch coverage is 86.15385% with 9 lines in your changes missing coverage. Please review.
✅ Project coverage is 92.89%. Comparing base (dcc1ed1) to head (9405b97).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
guppylang/src/guppylang/std/qsystem/__init__.py 65.00% 7 Missing ⚠️
guppylang/src/guppylang/std/quantum/__init__.py 88.23% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1707      +/-   ##
==========================================
- Coverage   93.49%   92.89%   -0.61%     
==========================================
  Files         133      134       +1     
  Lines       12793    12935     +142     
==========================================
+ Hits        11961    12016      +55     
- Misses        832      919      +87     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Collaborator

@maximilianruesch maximilianruesch left a comment

Choose a reason for hiding this comment

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

Big PR, lots of little changes. Great work! I massively trust the tests on this one.

A few comments here and there. Also I think the title (which will end up as the commit title) should mention that we drop the opaque guppy bools / that we change the return type of measurement functions, not just add some type.

Comment thread tests/error/modifier_errors/bad_custom_call.err
# TODO this should be a compile-time error
# Fails with "pyo3_runtime.PanicException: Cannot convert negative integer -2 to
# unsigned."
@pytest.mark.xfail(reason="Rust PanicException cannot be caught from Python")
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.

You can catch "Exception", and PanicException should be a subtype of that

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I did try that and it didn't work?

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.

What do you mean by "it did not work"? The panic went through? You can also catch BaseException even more generally...

Comment thread guppylang-internals/src/guppylang_internals/compiler/expr_compiler.py Outdated
Comment thread guppylang-internals/src/guppylang_internals/std/_internal/compiler/quantum.py Outdated
Comment thread examples/deferred_measurement.ipynb Outdated
"metadata": {},
"source": [
"Simply replacing the method results in an error because `lazy_measure` returns a value of type `Measurement`. In order to obtain a `bool`, we have to explicitaly use `read()` on the value. "
"Simply replacing the method results in an error because `result` expects a `bool`. In order to obtain it, we have to explicitly use `read()` on the value of type `Measurement`. This will block until the physical measurement is completed:"
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.

We are not "replacing" the method anymore, since we are breakingly forcing an upgrade. This needs a reword, potentially to just "This results in an error because ...".

Comment thread tests/integration/test_qsystem.py
Comment thread examples/deferred_measurement.ipynb Outdated
Comment thread examples/deferred_measurement.ipynb Outdated
Comment thread examples/t_factory.ipynb
@tatiana-s tatiana-s changed the title feat!: Add a Measurement type as the return type for measurement functions feat!: Change the return type of measurement functions to a new Measurement type and remove opaque bools from the compiler May 22, 2026
Copy link
Copy Markdown
Collaborator

@maximilianruesch maximilianruesch left a comment

Choose a reason for hiding this comment

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

LGTM for now. When merging / handling the latest tket release, please rerequest a review, and then I can approve.

Comment thread examples/t_factory.ipynb
" qs = array(some(qubit()) for _ in range(3))\n",
" mask = array(True, False, True)\n",
" measure_mask(qs, mask)\n",
" # We need to consume the array of measurement options as they are linear.\n",
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 comment and the next one have the same underlying reason (linear -> cannot be leaked), but both only display the truth partially.

@tatiana-s tatiana-s added the S-wait-to-merge Status: Ready to merge but waiting on external factor label May 26, 2026

@guppy
@no_type_check
def collect_measurements(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I guess it's been called collect_measurements for awhile but it feels like it ought to have read in the name at least, given the measurements are already in a collection (so no collecting is done) and there's nothing in the name to say that it's reading!!

Copy link
Copy Markdown
Contributor

@acl-cqc acl-cqc left a comment

Choose a reason for hiding this comment

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

Thanks @tatiana-s! A big PR already I admit but is this the time to add overrides to result that accept Measurement directly? (Or a followup?)

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

Labels

S-wait-to-merge Status: Ready to merge but waiting on external factor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Change measure() to return a future bool

6 participants