Skip to content

Result

Result dataclass

Result(
    *,
    storage: StorageBackend,
    shot_filter: ShotFilter = _default_shot_filter()
)

Result view over stored shots.

Merge-oriented methods assume each selected task ID has the same subtask structure.

Attributes:

Name Type Description
storage StorageBackend

Storage backend that holds shots and task metadata.

shot_filter ShotFilter

Filter used when reading shots and deriving subtask scope. Defaults to the DETECTED frame type.

storage_filter property

storage_filter: StorageFilter

Return the subtask-level portion of shot_filter.

Returns:

Name Type Description
StorageFilter StorageFilter

Filter containing task IDs, subtask indices, and task-subtask pairs from shot_filter.

arguments

arguments(verify: bool = True) -> list[dict | None]

Return subtask arguments after merging selected task IDs.

Parameters:

Name Type Description Default
verify bool

Whether to validate that selected task IDs can be merged before reading arguments. Defaults to True.

True

Returns:

Type Description
list[dict | None]

list[dict | None]: One arguments entry per merged subtask, ordered by subtask index.

Raises:

Type Description
ValueError

If verify is True and selected task IDs cannot be merged.

Source code in src/bloqade/core/device/result.py
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
def arguments(self, verify: bool = True) -> list[dict | None]:
    """Return subtask arguments after merging selected task IDs.

    Args:
        verify (bool): Whether to validate that selected task IDs can be
            merged before reading arguments. Defaults to True.

    Returns:
        list[dict | None]: One arguments entry per merged subtask, ordered
            by subtask index.

    Raises:
        ValueError: If `verify` is True and selected task IDs cannot be
            merged.
    """
    subtasks = self.subtasks(verify=verify)
    return [subtask["arguments"] for subtask in subtasks]

full_arguments

full_arguments() -> list[dict | None]

Return all stored subtask arguments without merging task IDs.

Returns:

Type Description
list[dict | None]

list[dict | None]: Arguments for every selected stored subtask row, including None for rows without arguments.

Source code in src/bloqade/core/device/result.py
209
210
211
212
213
214
215
216
def full_arguments(self) -> list[dict | None]:
    """Return all stored subtask arguments without merging task IDs.

    Returns:
        list[dict | None]: Arguments for every selected stored subtask row,
            including `None` for rows without arguments.
    """
    return self.storage.get_arguments(storage_filter=self.storage_filter)

full_subtasks

full_subtasks() -> list[dict]

Return selected stored subtasks without merging task IDs.

If selected task IDs share the same subtask structure, this view contains one row per task and subtask.

Returns:

Type Description
list[dict]

list[dict]: Full subtask dictionaries selected by storage_filter.

Source code in src/bloqade/core/device/result.py
252
253
254
255
256
257
258
259
260
261
def full_subtasks(self) -> list[dict]:
    """Return selected stored subtasks without merging task IDs.

    If selected task IDs share the same subtask structure, this view
    contains one row per task and subtask.

    Returns:
        list[dict]: Full subtask dictionaries selected by `storage_filter`.
    """
    return self.storage.get_subtasks(storage_filter=self.storage_filter)

group_shots_by_metadata

group_shots_by_metadata(
    shots: Sequence[Sequence[ShotValue]],
    metadata_keys: Sequence[str],
) -> dict[tuple[Hashable, ...], list[ShotValue]]

Aggregate per-subtask shots by selected user-metadata values.

shots must contain one sequence per entry of :meth:subtasks, in that same order. For a result merged from multiple task IDs, every full subtask contributing to one merged subtask must agree on the requested metadata values.

Parameters:

Name Type Description Default
shots Sequence[Sequence[ShotValue]]

Per-subtask shot sequences to aggregate.

required
metadata_keys Sequence[str]

User-metadata keys whose values form each group key.

required

Returns:

Type Description
dict[tuple[Hashable, ...], list[ShotValue]]

A dictionary mapping metadata-value tuples to flattened shot lists.

dict[tuple[Hashable, ...], list[ShotValue]]

The order within each list follows subtasks() order, then the

dict[tuple[Hashable, ...], list[ShotValue]]

order supplied within each corresponding shot sequence.

Raises:

Type Description
ValueError

If shots does not align with the selected merged subtasks, a full subtask has invalid/missing user metadata, a requested key is missing, metadata disagrees across merged task IDs, or a key value is unhashable.

Source code in src/bloqade/core/device/result.py
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
def group_shots_by_metadata(
    self,
    shots: Sequence[Sequence[ShotValue]],
    metadata_keys: Sequence[str],
) -> dict[tuple[Hashable, ...], list[ShotValue]]:
    """Aggregate per-subtask shots by selected user-metadata values.

    ``shots`` must contain one sequence per entry of :meth:`subtasks`, in
    that same order. For a result merged from multiple task IDs, every full
    subtask contributing to one merged subtask must agree on the requested
    metadata values.

    Args:
        shots: Per-subtask shot sequences to aggregate.
        metadata_keys: User-metadata keys whose values form each group key.

    Returns:
        A dictionary mapping metadata-value tuples to flattened shot lists.
        The order within each list follows ``subtasks()`` order, then the
        order supplied within each corresponding shot sequence.

    Raises:
        ValueError: If ``shots`` does not align with the selected merged
            subtasks, a full subtask has invalid/missing user metadata, a
            requested key is missing, metadata disagrees across merged
            task IDs, or a key value is unhashable.
    """
    subtasks = self.subtasks()
    if len(shots) != len(subtasks):
        raise ValueError(
            "shots must contain one sequence per selected merged subtask: "
            f"got {len(shots)} sequences for {len(subtasks)} subtasks."
        )

    metadata_keys_by_subtask_index: dict[int, tuple[Hashable, ...]] = {}
    for subtask in self.full_subtasks():
        subtask_ref = f"{subtask['task_id']!r}/{subtask['subtask_index']}"
        metadata = subtask["metadata"]
        user_metadata_text = (
            None if metadata is None else metadata.get("user_metadata")
        )
        if user_metadata_text is None:
            raise ValueError(f"Subtask {subtask_ref} has no user metadata.")

        try:
            user_metadata = json.loads(user_metadata_text)
        except (TypeError, json.JSONDecodeError) as exc:
            raise ValueError(
                f"Subtask {subtask_ref} has invalid JSON user metadata."
            ) from exc

        if not isinstance(user_metadata, dict):
            raise TypeError(
                f"Subtask {subtask_ref} user metadata must be a JSON object."
            )

        missing_keys = [key for key in metadata_keys if key not in user_metadata]
        if missing_keys:
            raise ValueError(
                f"Subtask {subtask_ref} is missing metadata keys: {missing_keys!r}."
            )

        key = tuple(user_metadata[name] for name in metadata_keys)
        try:
            hash(key)
        except TypeError as exc:
            raise ValueError(
                f"Subtask {subtask_ref} metadata values for {metadata_keys!r} "
                "must be hashable."
            ) from exc

        subtask_index = subtask["subtask_index"]
        existing_key = metadata_keys_by_subtask_index.setdefault(subtask_index, key)
        if existing_key != key:
            raise ValueError(
                "Selected task IDs disagree on metadata values for "
                f"subtask_index={subtask_index}: {existing_key!r} != {key!r}."
            )

    grouped: dict[tuple[Hashable, ...], list[ShotValue]] = {}
    for subtask, subtask_shots in zip(subtasks, shots, strict=True):
        key = metadata_keys_by_subtask_index[subtask["subtask_index"]]
        grouped.setdefault(key, []).extend(subtask_shots)

    return grouped

raw_shot_results

raw_shot_results(
    verify: bool = True,
) -> list[list[ShotResult]]

Return raw :class:ShotResult objects grouped by merged subtask.

Unlike :meth:shot_results, this preserves each row's task ID, shot indexes, frame type, and bitstring. A group contains all selected task IDs that contribute to its merged subtask_index. Rows within each group are sorted by (task_id, shot_index, frame_type).

Parameters:

Name Type Description Default
verify bool

Whether to validate that selected task IDs can be merged before reading shots. Defaults to True.

True

Returns:

Type Description
list[list[ShotResult]]

One list of raw shot rows per merged subtask, ordered by subtask

list[list[ShotResult]]

index. Rows within each list are ordered by

list[list[ShotResult]]

(task_id, shot_index, frame_type).

Raises:

Type Description
ValueError

If verify is True and selected task IDs cannot be merged.

Source code in src/bloqade/core/device/result.py
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
def raw_shot_results(self, verify: bool = True) -> list[list[ShotResult]]:
    """Return raw :class:`ShotResult` objects grouped by merged subtask.

    Unlike :meth:`shot_results`, this preserves each row's task ID, shot
    indexes, frame type, and bitstring. A group contains all selected task
    IDs that contribute to its merged ``subtask_index``. Rows within each
    group are sorted by ``(task_id, shot_index, frame_type)``.

    Args:
        verify: Whether to validate that selected task IDs can be merged
            before reading shots. Defaults to True.

    Returns:
        One list of raw shot rows per merged subtask, ordered by subtask
        index. Rows within each list are ordered by
        ``(task_id, shot_index, frame_type)``.

    Raises:
        ValueError: If ``verify`` is True and selected task IDs cannot be
            merged.
    """
    subtasks = self.subtasks(verify=verify)
    return self._raw_shot_results_for_subtasks(subtasks)

shot_results

shot_results(verify: bool = True) -> list[np.ndarray]

Return physical shot bitstrings grouped by merged subtask.

Parameters:

Name Type Description Default
verify bool

Whether to validate that selected task IDs can be merged before reading shots. Defaults to True.

True

Returns:

Type Description
list[ndarray]

list[np.ndarray]: One two-dimensional boolean array per merged subtask, ordered by subtask index.

Raises:

Type Description
ValueError

If verify is True and selected task IDs cannot be merged.

Source code in src/bloqade/core/device/result.py
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
def shot_results(self, verify: bool = True) -> list[np.ndarray]:
    """Return physical shot bitstrings grouped by merged subtask.

    Args:
        verify (bool): Whether to validate that selected task IDs can be
            merged before reading shots. Defaults to True.

    Returns:
        list[np.ndarray]: One two-dimensional boolean array per merged
            subtask, ordered by subtask index.

    Raises:
        ValueError: If `verify` is True and selected task IDs cannot be
            merged.
    """
    subtasks = self.subtasks(verify=verify)
    return self._shot_results_for_subtasks(subtasks)

subtasks

subtasks(verify: bool = True) -> list[dict]

Return subtasks merged across selected task IDs.

The merged view is ordered by subtask_index, removes ambiguous per-task fields (task_id and metadata), and aggregates num_shots. Use full_subtasks when task IDs or metadata must be preserved.

Parameters:

Name Type Description Default
verify bool

Whether to validate that selected task IDs can be merged before returning subtasks. Defaults to True.

True

Returns:

Type Description
list[dict]

list[dict]: Merged subtask dictionaries ordered by subtask index.

Raises:

Type Description
ValueError

If verify is True and selected task IDs cannot be merged.

Source code in src/bloqade/core/device/result.py
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
def subtasks(self, verify: bool = True) -> list[dict]:
    """Return subtasks merged across selected task IDs.

    The merged view is ordered by `subtask_index`, removes ambiguous
    per-task fields (`task_id` and `metadata`), and aggregates `num_shots`.
    Use `full_subtasks` when task IDs or metadata must be preserved.

    Args:
        verify (bool): Whether to validate that selected task IDs can be
            merged before returning subtasks. Defaults to True.

    Returns:
        list[dict]: Merged subtask dictionaries ordered by subtask index.

    Raises:
        ValueError: If `verify` is True and selected task IDs cannot be
            merged.
    """
    if verify:
        self.validate()

    subtasks = self.storage.get_subtasks(storage_filter=self.storage_filter)
    subtasks_by_index: dict[int, dict] = {}
    for subtask in subtasks:
        # NOTE: remove task_id and metadata since we're merging multiple ones
        subtask.pop("task_id")
        subtask.pop("metadata")
        idx = subtask["subtask_index"]
        if idx in subtasks_by_index:
            subtasks_by_index[idx]["num_shots"] += subtask["num_shots"]
        else:
            subtasks_by_index[idx] = subtask
    return [subtasks_by_index[i] for i in sorted(subtasks_by_index)]

task_ids

task_ids() -> set[str]

Return task IDs selected by this result view.

Returns:

Type Description
set[str]

set[str]: Task IDs from shot_filter.task_ids when set; otherwise all task IDs known to storage.

Source code in src/bloqade/core/device/result.py
349
350
351
352
353
354
355
356
357
358
359
def task_ids(self) -> set[str]:
    """Return task IDs selected by this result view.

    Returns:
        set[str]: Task IDs from `shot_filter.task_ids` when set; otherwise
            all task IDs known to storage.
    """
    if self.shot_filter.task_ids is not None:
        return set(self.shot_filter.task_ids)

    return self.storage.task_ids()

validate

validate() -> None

Validate that selected task IDs can be merged by subtask index.

Compatible task IDs have the same program_index and equal arguments for each shared subtask_index. Different shot counts are allowed, and None and empty dictionaries are treated as equivalent arguments.

Raises:

Type Description
ValueError

If selected task IDs disagree on program_index or arguments for the same subtask_index.

Source code in src/bloqade/core/device/result.py
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
def validate(self) -> None:
    """Validate that selected task IDs can be merged by subtask index.

    Compatible task IDs have the same `program_index` and equal arguments
    for each shared `subtask_index`. Different shot counts are allowed, and
    None and empty dictionaries are treated as equivalent arguments.

    Raises:
        ValueError: If selected task IDs disagree on `program_index` or
            arguments for the same `subtask_index`.
    """

    if self._is_valid:
        return

    if self.shot_filter.task_ids is None:
        task_ids = self.storage.task_ids()
    else:
        task_ids = self.shot_filter.task_ids

    if len(task_ids) == 1:
        # Just a single task, we're safe
        self._is_valid = True
        return

    full_subtasks = self.full_subtasks()

    subtask_index_groups: dict[int, list[dict]] = {}
    for subtask in full_subtasks:
        subtask_index_groups.setdefault(subtask["subtask_index"], []).append(
            subtask
        )

    _VERIFY_HINT = "Pass verify=False to skip this check."

    for idx, group in subtask_index_groups.items():
        if len(group) <= 1:
            continue
        ref_subtask = group[0]
        for other_subtask in group[1:]:
            if other_subtask["program_index"] != ref_subtask["program_index"]:
                raise ValueError(
                    f"task_ids disagree on program_index for subtask_index={idx}: "
                    f"{ref_subtask['task_id']!r} -> {ref_subtask['program_index']}, "
                    f"{other_subtask['task_id']!r} -> {other_subtask['program_index']}. "
                    + _VERIFY_HINT
                )
            ref_arguments = ref_subtask["arguments"]
            other_arguments = other_subtask["arguments"]
            if not ref_arguments and not other_arguments:
                # NOTE: treat empty dict and None as equal
                continue
            if other_subtask["arguments"] != ref_subtask["arguments"]:
                raise ValueError(
                    f"task_ids disagree on arguments for subtask_index={idx}: "
                    f"{ref_subtask['task_id']!r} -> {ref_subtask['arguments']!r}, "
                    f"{other_subtask['task_id']!r} -> {other_subtask['arguments']!r}. "
                    + _VERIFY_HINT
                )

    self._is_valid = True

where_arguments

where_arguments(
    predicate: Callable[[dict | None], bool],
) -> Self

Return a result narrowed by subtask arguments.

The predicate sees only subtasks in the scope of self.shot_filter; the returned result inherits that scope intersected with the matches.

NOTE: the Subtask model coerces bool values in arguments to float (True -> 1.0, False -> 0.0). Predicates that rely on identity (is True) or strict types will silently match nothing for bool-valued arguments. Use == 1 or > 0 instead, or store non-bool discriminators.

Parameters:

Name Type Description Default
predicate Callable[[dict | None], bool]

Predicate applied to each selected subtask's arguments.

required

Returns:

Name Type Description
Self Self

A narrowed result view.

Source code in src/bloqade/core/device/result.py
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
def where_arguments(
    self,
    predicate: Callable[[dict | None], bool],
) -> Self:
    """Return a result narrowed by subtask arguments.

    The predicate sees only subtasks in the scope of `self.shot_filter`; the
    returned result inherits that scope intersected with the matches.

    NOTE: the Subtask model coerces bool values in `arguments` to float
    (True -> 1.0, False -> 0.0). Predicates that rely on identity
    (`is True`) or strict types will silently match nothing for bool-valued
    arguments. Use `== 1` or `> 0` instead, or store non-bool
    discriminators.

    Args:
        predicate (Callable[[dict | None], bool]): Predicate applied to each
            selected subtask's arguments.

    Returns:
        Self: A narrowed result view.
    """
    where_filter = self.storage.filter_by_arguments(
        predicate=predicate, storage_filter=self.storage_filter
    )
    return self._from_where_filters(
        where_filter=where_filter,
    )

where_metadata

where_metadata(
    predicate: Callable[[dict | None], bool],
) -> Self

Return a result narrowed by JSON-decoded user metadata.

Expects user_metadata to be a JSON-serialized dict; non-JSON values raise. To filter on raw strings instead, use where_subtasks and parse manually. The predicate sees only subtasks in the scope of self.shot_filter; the returned result inherits that scope intersected with the matches.

Parameters:

Name Type Description Default
predicate Callable[[dict | None], bool]

Predicate applied to each selected subtask's decoded user_metadata.

required

Returns:

Name Type Description
Self Self

A narrowed result view.

Source code in src/bloqade/core/device/result.py
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
def where_metadata(
    self,
    predicate: Callable[[dict | None], bool],
) -> Self:
    """Return a result narrowed by JSON-decoded user metadata.

    Expects user_metadata to be a JSON-serialized dict; non-JSON values raise. To
    filter on raw strings instead, use `where_subtasks` and parse manually. The
    predicate sees only subtasks in the scope of `self.shot_filter`; the returned
    result inherits that scope intersected with the matches.

    Args:
        predicate (Callable[[dict | None], bool]): Predicate applied to each
            selected subtask's decoded `user_metadata`.

    Returns:
        Self: A narrowed result view.
    """
    where_filter = self.storage.filter_by_metadata(
        predicate=predicate, storage_filter=self.storage_filter
    )
    return self._from_where_filters(
        where_filter=where_filter,
    )

where_shots

where_shots(
    predicate: Callable[[ShotResult], bool],
    predicate_filter: ShotFilter | None = None,
) -> Self

Return a result narrowed by shot-level predicate.

predicate_filter selects the shots the predicate evaluates against; defaults to self.shot_filter (predicate sees the same shots the current result fetches). The returned result inherits self.shot_filter's scope (notably frame_type) intersected with the matching shot pairs.

To precondition on one frame and return another, such as SORTED-was-all-1 -> DETECTED, pass predicate_filter=replace(self.shot_filter, frame_type='SORTED').

Parameters:

Name Type Description Default
predicate Callable[[ShotResult], bool]

Predicate applied to each shot selected by predicate_filter.

required
predicate_filter ShotFilter | None

Filter used only for predicate evaluation. When None, self.shot_filter is used. Defaults to None.

None

Returns:

Name Type Description
Self Self

A narrowed result view.

Source code in src/bloqade/core/device/result.py
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
def where_shots(
    self,
    predicate: Callable[[ShotResult], bool],
    predicate_filter: ShotFilter | None = None,
) -> Self:
    """Return a result narrowed by shot-level predicate.

    `predicate_filter` selects the shots the predicate evaluates against;
    defaults to `self.shot_filter` (predicate sees the same shots the
    current result fetches). The returned result inherits
    `self.shot_filter`'s scope (notably `frame_type`) intersected with the
    matching shot pairs.

    To precondition on one frame and return another, such as
    SORTED-was-all-1 -> DETECTED, pass
    `predicate_filter=replace(self.shot_filter, frame_type='SORTED')`.

    Args:
        predicate (Callable[[ShotResult], bool]): Predicate applied to each
            shot selected by `predicate_filter`.
        predicate_filter (ShotFilter | None): Filter used only for predicate
            evaluation. When None, `self.shot_filter` is used. Defaults to
            None.

    Returns:
        Self: A narrowed result view.
    """
    if predicate_filter is None:
        predicate_filter = self.shot_filter

    where_filter = self.storage.filter_by_shots(
        predicate, shot_filter=predicate_filter
    )
    shot_filter = replace(
        self.shot_filter,
        task_shot_pairs=where_filter.task_shot_pairs,
    )
    return type(self)(
        storage=self.storage,
        shot_filter=shot_filter,
    )

where_subtasks

where_subtasks(predicate: Callable[[dict], bool]) -> Self

Return a result narrowed to subtasks matching a predicate.

The predicate sees only subtasks in the scope of self.shot_filter; the returned result inherits that scope intersected with the matches.

Parameters:

Name Type Description Default
predicate Callable[[dict], bool]

Predicate applied to each selected subtask dictionary.

required

Returns:

Name Type Description
Self Self

A narrowed result view.

Source code in src/bloqade/core/device/result.py
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
def where_subtasks(
    self,
    predicate: Callable[[dict], bool],
) -> Self:
    """Return a result narrowed to subtasks matching a predicate.

    The predicate sees only subtasks in the scope of `self.shot_filter`; the
    returned result inherits that scope intersected with the matches.

    Args:
        predicate (Callable[[dict], bool]): Predicate applied to each
            selected subtask dictionary.

    Returns:
        Self: A narrowed result view.
    """
    where_filter = self.storage.filter_by_subtasks(
        predicate, storage_filter=self.storage_filter
    )
    return self._from_where_filters(
        where_filter=where_filter,
    )