Skip to content

Conversation

@johnzl-777
Copy link
Contributor

@johnzl-777 johnzl-777 commented Nov 4, 2025

Implement's squin.is_one, squin.is_zero, and squin.is_lost for use with MeasurementResults.

The type lattice has some additional complexity now because I need the knowledge of what predicate was applied to which measurement result to determine if translation to stim makes sense.

I know you can technically "invert" the measurement result but my understanding is you have to do it at the time of measurement:

M !5 # invert result of measuring qubit 5

CX rec[-1] 0 # if 5 collapses to 0 above, then this CX gets applied because rec[-1] = 1

I don't see this as impossible to do but I don't want to jump the gun on implementing something like this as a follow-up unless there's a clear enough demand for it.

@johnzl-777 johnzl-777 linked an issue Nov 4, 2025 that may be closed by this pull request
@codecov
Copy link

codecov bot commented Nov 4, 2025

@github-actions
Copy link
Contributor

github-actions bot commented Nov 4, 2025

☂️ Python Coverage

current status: ✅

Overall Coverage

Lines Covered Coverage Threshold Status
10213 8957 88% 0% 🟢

New Files

No new covered files...

Modified Files

File Coverage Status
src/bloqade/analysis/measure_id/analysis.py 100% 🟢
src/bloqade/analysis/measure_id/impls.py 94% 🟢
src/bloqade/analysis/measure_id/lattice.py 95% 🟢
src/bloqade/qubit/_init_.py 100% 🟢
src/bloqade/qubit/_interface.py 100% 🟢
src/bloqade/qubit/stdlib/broadcast.py 74% 🟢
src/bloqade/qubit/stdlib/simple.py 58% 🟢
src/bloqade/qubit/stmts.py 98% 🟢
src/bloqade/squin/_init_.py 100% 🟢
src/bloqade/squin/stdlib/broadcast/_init_.py 100% 🟢
src/bloqade/squin/stdlib/broadcast/_qubit.py 100% 🟢
src/bloqade/stim/rewrite/get_record_util.py 100% 🟢
src/bloqade/stim/rewrite/ifs_to_stim.py 95% 🟢
TOTAL 93% 🟢

updated for commit: a14dba9 by action🐍

@johnzl-777 johnzl-777 changed the title predicates for MeasuremenetResult predicates for MeasurementResult Nov 4, 2025
@johnzl-777 johnzl-777 marked this pull request as ready for review November 10, 2025 14:21
Copy link
Collaborator

@david-pl david-pl left a comment

Choose a reason for hiding this comment

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

Looks good, just some minor things to consider.

# readability
@final
@dataclass
class MeasureIdBool(MeasureId):
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is MeasureIdBool used anywhere else in the pipeline? If so, this might be breaking.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think so, I did a ripgrep on our workspace and the only things that depend on it are the original physical dialect (which won't depend on it anymore once my simplification PR gets accepted) and bloqade-circuit (which is why this PR exists haha)

Copy link
Collaborator

Choose a reason for hiding this comment

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

Wait, is this PR a backport candidate anyway? I guess so, right? Please add the label :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think this should be backported ):

Now that I think about this would definitely be something of a breaking change because on the SquinToStim side I've now gone ahead and enforced the following syntax to be necessary:

qs = squin.qalloc(5)
ms = squin.broadcast.measure(qs)
one_meas_result = squin.is_one(ms[0])

if one_meas_result:
	squin.x(qs[1])
	
# This can become:
# CX rec[-1] 1

Whereas historically you didn't need is_one at all and you could just chuck in your measurement result as the condition for the scf.IfElse.

@david-pl david-pl added the breaking breaking changes or proposed changes that would break existing APIs label Nov 12, 2025

expected_is_zero_bools = MeasureIdTuple(
data=tuple(
[MeasureIdBool(idx=i, predicate=Predicate.IS_ZERO) for i in range(1, 4)]
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm just confused: why is idx 1-indexed? Why not stick to Python's 0-indexing everywhere, in which case this would become range(3)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't recall the exact reason, I would be willing to change things if it proves a nuisance but from what I remember it's most likely just a carry-over from initial measurement id analysis.

I think the additional benefit is it makes debugging a bit easier when I look at the raw output.

Copy link
Contributor

@rafaelha rafaelha left a comment

Choose a reason for hiding this comment

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

Looks great to me!

@johnzl-777 johnzl-777 added the squin squin related issues label Nov 13, 2025
@johnzl-777 johnzl-777 added the stim Issues regarding the stim dialect label Nov 13, 2025
@johnzl-777 johnzl-777 merged commit db85cf0 into main Nov 13, 2025
10 of 11 checks passed
@johnzl-777 johnzl-777 deleted the john/measurement-result-predicate branch November 13, 2025 03:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking breaking changes or proposed changes that would break existing APIs squin squin related issues stim Issues regarding the stim dialect

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MeasurementResult Predicates

5 participants