Skip to content

results: register defaults, YieldHandling key formats, and root exports - #76

Open
qci-amos wants to merge 5 commits into
mainfrom
results/api-defaults-and-key-handling
Open

results: register defaults, YieldHandling key formats, and root exports#76
qci-amos wants to merge 5 commits into
mainfrom
results/api-defaults-and-key-handling

Conversation

@qci-amos

Copy link
Copy Markdown
Collaborator

Part of splitting #71 into reviewable pieces. This is the non-QCDL half —
dwave.gate.results — and is independent of the other four PRs.

Three independent fixes, one commit each.

1. get_memory / get_counts default to the measured register

Both fell back to get_default_register, which lists every qubit in the
circuit whether or not it was measured. An unmeasured qubit was therefore
padded into the bitstring with unmeasured_value and read as an outcome:
a three-qubit circuit measuring only q1 and q2 returned {"01_": 3}.

They now default to get_measurements_register, falling back to every qubit
only when nothing was measured at all. get_default_register is unchanged and
still available — pass it explicitly to get the padded register back — and its
docstring now says which methods use it and when.

Compatibility: this changes the default output shape for any circuit with
unmeasured qubits. Callers passing an explicit register are unaffected.

2. YieldHandling.apply handles every counts key format

apply tested keys with "*" not in k. count_measurements(..., key_format=None)
produces integer keys, so composing the two — which is the obvious thing to
do — raised TypeError: argument of type 'int' is not iterable. The
all-erasures fallback had the same assumption, building its zeros key with
str.replace.

Only the string key formats can hold a splat, so the erasure test now checks
for that, and the fallback key falls back to 0 for a non-string key.

An empty distribution raised StopIteration out of that fallback, which is not
a useful error for a counts dict that post-selection emptied; it now raises
ValueError.

apply also picked up the docstring it never had.

3. Export Result and YieldHandling from the package root

The user guide refers to these as dwave.gate.Result and
dwave.gate.YieldHandling, which did not resolve. They are re-exported from
the package root and remain importable from dwave.gate.results, which is
still where they are defined — a test asserts __module__ does not move, since
Sphinx and pickle both key off it.

Testing

pytest tests/ passes. tests/test_results.py covers the register default
(including the explicit-register and nothing-measured paths), apply against
every key format count_measurements produces, and the import paths.

🤖 Generated with Claude Code

qci-amos and others added 3 commits August 19, 2026 12:51
Both fell back to get_default_register, which lists every qubit in the
circuit whether or not it was measured, so an unmeasured qubit was padded
into the bitstring and read as an outcome. They now default to
get_measurements_register and fall back to every qubit only when nothing
was measured at all. Passing get_default_register explicitly still gets
the padded register.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
apply() tested keys with `"*" not in k`, which raises TypeError on the
integer keys count_measurements produces for key_format=None, and built
its all-erasures fallback key with str.replace. Only string keys can hold
a splat, so the erasure test now checks for that and the fallback key
falls back to 0 for a non-string key.

An empty distribution raised StopIteration from the fallback, which is
not a useful error for a counts dict that post selection emptied; it now
raises ValueError.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The user guide refers to these as dwave.gate.Result and
dwave.gate.YieldHandling, which did not resolve. They are re-exported
from the package root and remain importable from dwave.gate.results,
which is still where they are defined, so __module__ does not move.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Aug 19, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.71%. Comparing base (2b82b20) to head (82076a9).

Additional details and impacted files
@@            Coverage Diff             @@
##             main      #76      +/-   ##
==========================================
+ Coverage   90.18%   90.71%   +0.53%     
==========================================
  Files          31       31              
  Lines        5317     5377      +60     
==========================================
+ Hits         4795     4878      +83     
+ Misses        522      499      -23     

☔ View full report in Codecov by Harness.
📢 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.

Comment thread dwave/gate/results.py

Only the string key formats can hold a splat: the
:func:`.count_measurements` function produces integer keys only for
memory that is entirely 0s and 1s.

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.

wouldn't splay be held as -1? Maybe not here.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

What's at stake here are the data types that count_measurements can return. The key_format there may be bin, hex, and None. Maybe we should remove hex and None, I don't know of any current use of those (count_measurements was written before erasures).

But regardless, hex and "integer" for keys don't support splats. We only have -1 outside of a bitstring context or * for a bitstring context.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

That said, I can imagine that at scale we'll want some representation more compact than strings... but we're not at the point where that matters yet and Qiskit requires strings afaik.

Comment thread dwave/gate/results.py
:exception:`ValueError`: If the distribution is empty, or if the
yield is too low for
:attr:`.renormalize_distribution_or_raise`.
:exception:`ZeroDivisionError`: If nothing survives post selection

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.

Is this the best error type for this case?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

It's raised here:

raise ZeroDivisionError("yield is zero, can't renormalize distribution")

I generally try to use the built-in types where it makes sense and it seems like this qualifies: there really is a "divide by zero" that would occur here. We could do a custom error if that's what you mean?

Comment thread dwave/gate/results.py
Comment thread dwave/gate/results.py
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.

2 participants