diff --git a/dev/util_gen_stub_file.py b/dev/util_gen_stub_file.py index bcc6193a7..6e66646a1 100644 --- a/dev/util_gen_stub_file.py +++ b/dev/util_gen_stub_file.py @@ -36,6 +36,8 @@ "__next__", } skip = { + "__annotate_func__", + "__annotations_cache__", "__firstlineno__", "__static_attributes__", "__replace__", diff --git a/doc/gates.md b/doc/gates.md index 3978e320a..4f21ce09e 100644 --- a/doc/gates.md +++ b/doc/gates.md @@ -4879,13 +4879,19 @@ detection event simulations and affect whether the observable is included in err makes it easier to benchmark all observables of a code, without having to introduce noiseless qubits entangled with the logical qubit to avoid the testing of the X observable anticommuting with the testing of the Z observable. +Unlike a `DETECTOR` instruction which provides a complete description of a detector by listing all its constituent +measurement records, an individual `OBSERVABLE_INCLUDE` instruction is not required to (and generally does not) fully +describe a logical observable. Instead, measurement records or Pauli targets are added to it incrementally. A logical +observable can be given both types of description: as a collection of Pauli targets and as a collection of measurement +record targets. + Parens Arguments: A non-negative integer specifying the index of the logical observable to add the measurement records to. Targets: - The measurement records to add to the specified observable. + The measurement records or Pauli terms to add to the specified observable. Example: @@ -4921,6 +4927,12 @@ Example: OBSERVABLE_INCLUDE(0) X0 X1 OBSERVABLE_INCLUDE(1) Z0 Z2 + # Stim circuit may include a description of an observable in terms of Pauli targets + # alongside a description in terms of measurement records. + OBSERVABLE_INCLUDE(0) Z0 Z1 + M 0 1 + OBSERVABLE_INCLUDE(0) rec[-2] rec[-1] + ### The 'QUBIT_COORDS' Instruction diff --git a/doc/sinter_api.md b/doc/sinter_api.md index 5cb64f821..b8eb87d8a 100644 --- a/doc/sinter_api.md +++ b/doc/sinter_api.md @@ -161,11 +161,11 @@ class CollectionOptions: biggest batch size that can finish in under the given number of seconds. Limits each batch to be no larger than that. """ - max_shots: Optional[int] = None - max_errors: Optional[int] = None - start_batch_size: Optional[int] = None - max_batch_size: Optional[int] = None - max_batch_seconds: Optional[float] = None + max_shots: Union = None + max_errors: Union = None + start_batch_size: Union = None + max_batch_size: Union = None + max_batch_seconds: Union = None ``` @@ -461,9 +461,9 @@ class Fit: of the best fit's square error, or whose likelihood was within some maximum Bayes factor of the max likelihood hypothesis. """ - low: Optional[float] - best: Optional[float] - high: Optional[float] + low: Union + best: Union + high: Union ``` @@ -586,16 +586,16 @@ class Task: def __init__( self, *, - circuit: Optional[stim.Circuit] = None, - decoder: Optional[str] = None, - detector_error_model: Optional[stim.DetectorErrorModel] = None, - postselection_mask: Optional[np.ndarray] = None, - postselected_observables_mask: Optional[np.ndarray] = None, + circuit: stim.Circuit | None = None, + decoder: str | None = None, + detector_error_model: stim.DetectorErrorModel | None = None, + postselection_mask: np.ndarray | None = None, + postselected_observables_mask: np.ndarray | None = None, json_metadata: Any = None, collection_options: sinter.CollectionOptions = sinter.CollectionOptions(), skip_validation: bool = False, - circuit_path: Union[str, pathlib.Path, NoneType] = None, - _unvalidated_strong_id: Optional[str] = None, + circuit_path: str | pathlib.Path | None = None, + _unvalidated_strong_id: str | None = None, ) -> None: """ Args: @@ -864,14 +864,14 @@ def to_csv_line( def with_edits( self, *, - strong_id: Optional[str] = None, - decoder: Optional[str] = None, - json_metadata: Optional[Any] = None, - shots: Optional[int] = None, - errors: Optional[int] = None, - discards: Optional[int] = None, - seconds: Optional[float] = None, - custom_counts: Optional[Counter[str]] = None, + strong_id: str | None = None, + decoder: str | None = None, + json_metadata: Any | None = None, + shots: int | None = None, + errors: int | None = None, + discards: int | None = None, + seconds: float | None = None, + custom_counts: Counter[str] | None = None, ) -> sinter.TaskStats: ``` @@ -925,23 +925,23 @@ def better_sorted_str_terms( def collect( *, num_workers: int, - tasks: Union[Iterator[sinter.Task], Iterable[sinter.Task]], - existing_data_filepaths: Iterable[Union[str, pathlib.Path]] = (), - save_resume_filepath: Union[NoneType, str, pathlib.Path] = None, - progress_callback: Optional[Callable[[sinter.Progress], NoneType]] = None, - max_shots: Optional[int] = None, - max_errors: Optional[int] = None, + tasks: Iterator[sinter.Task] | Iterable[sinter.Task], + existing_data_filepaths: Iterable[str | pathlib.Path] = (), + save_resume_filepath: None | str | pathlib.Path = None, + progress_callback: Callable[[sinter.Progress], NoneType] | None = None, + max_shots: int | None = None, + max_errors: int | None = None, count_observable_error_combos: bool = False, count_detection_events: bool = False, - decoders: Optional[Iterable[str]] = None, - max_batch_seconds: Optional[int] = None, - max_batch_size: Optional[int] = None, - start_batch_size: Optional[int] = None, + decoders: Iterable[str] | None = None, + max_batch_seconds: int | None = None, + max_batch_size: int | None = None, + start_batch_size: int | None = None, print_progress: bool = False, - hint_num_tasks: Optional[int] = None, - custom_decoders: Optional[Dict[str, Union[sinter.Decoder, sinter.Sampler]]] = None, - custom_error_count_key: Optional[str] = None, - allowed_cpu_affinity_ids: Optional[Iterable[int]] = None, + hint_num_tasks: int | None = None, + custom_decoders: Dict[str, sinter.Decoder | sinter.Sampler] | None = None, + custom_error_count_key: str | None = None, + allowed_cpu_affinity_ids: Iterable[int] | None = None, ) -> List[sinter.TaskStats]: """Collects statistics from the given tasks, using multiprocessing. @@ -1252,20 +1252,20 @@ def group_by( def iter_collect( *, num_workers: int, - tasks: Union[Iterator[sinter.Task], Iterable[sinter.Task]], - hint_num_tasks: Optional[int] = None, - additional_existing_data: Union[NoneType, Dict[str, sinter.TaskStats], Iterable[sinter.TaskStats]] = None, - max_shots: Optional[int] = None, - max_errors: Optional[int] = None, - decoders: Optional[Iterable[str]] = None, - max_batch_seconds: Optional[int] = None, - max_batch_size: Optional[int] = None, - start_batch_size: Optional[int] = None, + tasks: Iterator[sinter.Task] | Iterable[sinter.Task], + hint_num_tasks: int | None = None, + additional_existing_data: None | Dict[str, sinter.TaskStats] | Iterable[sinter.TaskStats] = None, + max_shots: int | None = None, + max_errors: int | None = None, + decoders: Iterable[str] | None = None, + max_batch_seconds: int | None = None, + max_batch_size: int | None = None, + start_batch_size: int | None = None, count_observable_error_combos: bool = False, count_detection_events: bool = False, - custom_decoders: Optional[Dict[str, Union[sinter.Decoder, sinter.Sampler]]] = None, - custom_error_count_key: Optional[str] = None, - allowed_cpu_affinity_ids: Optional[Iterable[int]] = None, + custom_decoders: Dict[str, sinter.Decoder | sinter.Sampler] | None = None, + custom_error_count_key: str | None = None, + allowed_cpu_affinity_ids: Iterable[int] | None = None, ) -> Iterator[sinter.Progress]: """Iterates error correction statistics collected from worker processes. @@ -1377,7 +1377,7 @@ def iter_collect( # (at top-level in the sinter module) def log_binomial( *, - p: Union[float, np.ndarray], + p: float | np.ndarray, n: int, hits: int, ) -> np.ndarray: @@ -1466,7 +1466,7 @@ def plot_discard_rate( group_func: Callable[[sinter.TaskStats], ~TCurveId] = lambda _: None, filter_func: Callable[[sinter.TaskStats], Any] = lambda _: True, plot_args_func: Callable[[int, ~TCurveId, List[sinter.TaskStats]], Dict[str, Any]] = lambda index, group_key, group_stats: dict(), - highlight_max_likelihood_factor: Optional[float] = 1000.0, + highlight_max_likelihood_factor: float | None = 1000.0, point_label_func: Callable[[sinter.TaskStats], Any] = lambda _: None, ) -> None: """Plots discard rates in curves with uncertainty highlights. @@ -1530,8 +1530,8 @@ def plot_error_rate( group_func: Callable[[sinter.TaskStats], ~TCurveId] = lambda _: None, filter_func: Callable[[sinter.TaskStats], Any] = lambda _: True, plot_args_func: Callable[[int, ~TCurveId, List[sinter.TaskStats]], Dict[str, Any]] = lambda index, group_key, group_stats: dict(), - highlight_max_likelihood_factor: Optional[float] = 1000.0, - line_fits: Optional[Tuple[Literal['linear', 'log', 'sqrt'], Literal['linear', 'log', 'sqrt']]] = None, + highlight_max_likelihood_factor: float | None = 1000.0, + line_fits: Tuple[Literal['linear', 'log', 'sqrt'], Literal['linear', 'log', 'sqrt']] | None = None, point_label_func: Callable[[sinter.TaskStats], Any] = lambda _: None, ) -> None: """Plots error rates in curves with uncertainty highlights. @@ -1593,7 +1593,7 @@ def plot_error_rate( # (at top-level in the sinter module) def post_selection_mask_from_4th_coord( - dem: Union[stim.Circuit, stim.DetectorErrorModel], + dem: stim.Circuit | stim.DetectorErrorModel, ) -> np.ndarray: """Returns a mask that postselects detector's with non-zero 4th coordinate. @@ -1666,7 +1666,7 @@ def predict_observables( dets: np.ndarray, decoder: str, bit_pack_result: bool = False, - custom_decoders: Optional[Dict[str, sinter.Decoder]] = None, + custom_decoders: Dict[str, sinter.Decoder] | None = None, ) -> np.ndarray: """Predicts which observables were flipped based on detection event data. @@ -1729,7 +1729,7 @@ def predict_observables_bit_packed( dem: stim.DetectorErrorModel, dets_bit_packed: np.ndarray, decoder: str, - custom_decoders: Optional[Dict[str, sinter.Decoder]] = None, + custom_decoders: Dict[str, sinter.Decoder] | None = None, ) -> np.ndarray: """Predicts which observables were flipped based on detection event data. @@ -1786,14 +1786,14 @@ def predict_observables_bit_packed( def predict_on_disk( *, decoder: str, - dem_path: Union[str, pathlib.Path], - dets_path: Union[str, pathlib.Path], + dem_path: str | pathlib.Path, + dets_path: str | pathlib.Path, dets_format: str, - obs_out_path: Union[str, pathlib.Path], + obs_out_path: str | pathlib.Path, obs_out_format: str, postselect_detectors_with_non_zero_4th_coord: bool = False, - discards_out_path: Union[str, pathlib.Path, NoneType] = None, - discards_out_format: Optional[str] = None, + discards_out_path: str | pathlib.Path | None = None, + discards_out_format: str | None = None, custom_decoders: Dict[str, sinter.Decoder] = None, ) -> None: """Performs decoding and postselection on disk. @@ -1866,11 +1866,11 @@ def read_stats_from_csv_files( # (at top-level in the sinter module) def shot_error_rate_to_piece_error_rate( - shot_error_rate: Union[float, sinter.Fit], + shot_error_rate: float | sinter.Fit, *, pieces: float, values: float = 1, -) -> Union[float, sinter.Fit]: +) -> float | sinter.Fit: """Convert from total error rate to per-piece error rate. Args: diff --git a/src/stim/gates/gate_data_annotations.cc b/src/stim/gates/gate_data_annotations.cc index ddf18f11a..dbcaa62f6 100644 --- a/src/stim/gates/gate_data_annotations.cc +++ b/src/stim/gates/gate_data_annotations.cc @@ -137,13 +137,19 @@ detection event simulations and affect whether the observable is included in err makes it easier to benchmark all observables of a code, without having to introduce noiseless qubits entangled with the logical qubit to avoid the testing of the X observable anticommuting with the testing of the Z observable. +Unlike a `DETECTOR` instruction which provides a complete description of a detector by listing all its constituent +measurement records, an individual `OBSERVABLE_INCLUDE` instruction is not required to (and generally does not) fully +describe a logical observable. Instead, measurement records or Pauli targets are added to it incrementally. A logical +observable can be given both types of description: as a collection of Pauli targets and as a collection of measurement +record targets. + Parens Arguments: A non-negative integer specifying the index of the logical observable to add the measurement records to. Targets: - The measurement records to add to the specified observable. + The measurement records or Pauli terms to add to the specified observable. Example: @@ -178,6 +184,12 @@ Parens Arguments: DETECTOR rec[-3] rec[-6] OBSERVABLE_INCLUDE(0) X0 X1 OBSERVABLE_INCLUDE(1) Z0 Z2 + + # Stim circuit may include a description of an observable in terms of Pauli targets + # alongside a description in terms of measurement records. + OBSERVABLE_INCLUDE(0) Z0 Z1 + M 0 1 + OBSERVABLE_INCLUDE(0) rec[-2] rec[-1] )MARKDOWN", .unitary_data = {}, .flow_data = {},