Skip to content

Commit

Permalink
Add some instruction utility methods (#833)
Browse files Browse the repository at this point in the history
- `stim.CircuitInstruction.__init__` now parses a single instruction
line from a circuit file, if given one argument
- `stim.DemInstruction.__init__` now parses a single instruction line
from a dem file, if given one argument
- Add `stim.CircuitRepeatBlock.num_measurements`
- Fix `stim.CircuitInstruction.__init__` not validating its arguments
form a valid instruction, until attempting to append it to a circuit
- Add documentation examples to `CircuitErrorLocationStackFrame` methods

Fixes #797

Fixes #800

Fixes #801
  • Loading branch information
Strilanc authored Sep 21, 2024
1 parent 3ee5bf8 commit 42b07a1
Show file tree
Hide file tree
Showing 18 changed files with 630 additions and 77 deletions.
130 changes: 123 additions & 7 deletions doc/python_api_reference_vDev.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ API references for stable versions are kept on the [stim github wiki](https://gi
- [`stim.CircuitRepeatBlock.__repr__`](#stim.CircuitRepeatBlock.__repr__)
- [`stim.CircuitRepeatBlock.body_copy`](#stim.CircuitRepeatBlock.body_copy)
- [`stim.CircuitRepeatBlock.name`](#stim.CircuitRepeatBlock.name)
- [`stim.CircuitRepeatBlock.num_measurements`](#stim.CircuitRepeatBlock.num_measurements)
- [`stim.CircuitRepeatBlock.repeat_count`](#stim.CircuitRepeatBlock.repeat_count)
- [`stim.CircuitTargetsInsideInstruction`](#stim.CircuitTargetsInsideInstruction)
- [`stim.CircuitTargetsInsideInstruction.__init__`](#stim.CircuitTargetsInsideInstruction.__init__)
Expand Down Expand Up @@ -3762,6 +3763,30 @@ class CircuitErrorLocationStackFrame:
The full location of an instruction is a list of these frames,
drilling down from the top level circuit to the inner-most loop
that the instruction is within.
Examples:
>>> import stim
>>> err = stim.Circuit('''
... REPEAT 5 {
... R 0
... Y_ERROR(0.125) 0
... M 0
... }
... OBSERVABLE_INCLUDE(0) rec[-1]
... ''').shortest_graphlike_error()
>>> err[0].circuit_error_locations[0].stack_frames[0]
stim.CircuitErrorLocationStackFrame(
instruction_offset=0,
iteration_index=0,
instruction_repetitions_arg=5,
)
>>> err[0].circuit_error_locations[0].stack_frames[1]
stim.CircuitErrorLocationStackFrame(
instruction_offset=1,
iteration_index=4,
instruction_repetitions_arg=0,
)
"""
```

Expand All @@ -3778,6 +3803,14 @@ def __init__(
instruction_repetitions_arg: int,
) -> None:
"""Creates a stim.CircuitErrorLocationStackFrame.
Examples:
>>> import stim
>>> frame = stim.CircuitErrorLocationStackFrame(
... instruction_offset=1,
... iteration_index=2,
... instruction_repetitions_arg=3,
... )
"""
```

Expand All @@ -3795,6 +3828,18 @@ def instruction_offset(
from the line number, because blank lines and commented lines
don't count and also because the offset of the first instruction
is 0 instead of 1.
Examples:
>>> import stim
>>> err = stim.Circuit('''
... R 0
... TICK
... Y_ERROR(0.125) 0
... M 0
... OBSERVABLE_INCLUDE(0) rec[-1]
... ''').shortest_graphlike_error()
>>> err[0].circuit_error_locations[0].stack_frames[0].instruction_offset
2
"""
```

Expand All @@ -3810,6 +3855,23 @@ def instruction_repetitions_arg(
"""If the instruction being referred to is a REPEAT block,
this is the repetition count of that REPEAT block. Otherwise
this field defaults to 0.
Examples:
>>> import stim
>>> err = stim.Circuit('''
... REPEAT 5 {
... R 0
... Y_ERROR(0.125) 0
... M 0
... }
... OBSERVABLE_INCLUDE(0) rec[-1]
... ''').shortest_graphlike_error()
>>> full = err[0].circuit_error_locations[0].stack_frames[0]
>>> loop = err[0].circuit_error_locations[0].stack_frames[1]
>>> full.instruction_repetitions_arg
5
>>> loop.instruction_repetitions_arg
0
"""
```

Expand All @@ -3825,6 +3887,23 @@ def iteration_index(
"""Disambiguates which iteration of the loop containing this instruction
is being referred to. If the instruction isn't in a REPEAT block, this
field defaults to 0.
Examples:
>>> import stim
>>> err = stim.Circuit('''
... REPEAT 5 {
... R 0
... Y_ERROR(0.125) 0
... M 0
... }
... OBSERVABLE_INCLUDE(0) rec[-1]
... ''').shortest_graphlike_error()
>>> full = err[0].circuit_error_locations[0].stack_frames[0]
>>> loop = err[0].circuit_error_locations[0].stack_frames[1]
>>> full.iteration_index
0
>>> loop.iteration_index
4
"""
```

Expand Down Expand Up @@ -3873,19 +3952,30 @@ def __eq__(
def __init__(
self,
name: str,
targets: List[object],
gate_args: List[float] = (),
targets: Optional[Iterable[Union[int, stim.GateTarget]]] = None,
gate_args: Optional[Iterable[float]] = None,
) -> None:
"""Initializes a `stim.CircuitInstruction`.
"""Creates or parses a `stim.CircuitInstruction`.
Args:
name: The name of the instruction being applied.
If `targets` and `gate_args` aren't specified, this can be a full
instruction line from a stim Circuit file, like "CX 0 1".
targets: The targets the instruction is being applied to. These can be raw
values like `0` and `stim.target_rec(-1)`, or instances of
`stim.GateTarget`.
gate_args: The sequence of numeric arguments parameterizing a gate. For
noise gates this is their probabilities. For `OBSERVABLE_INCLUDE`
instructions it's the index of the logical observable to affect.
Examples:
>>> import stim
>>> print(stim.CircuitInstruction('DEPOLARIZE1', [5], [0.25]))
DEPOLARIZE1(0.25) 5
>>> stim.CircuitInstruction('CX rec[-1] 5 # comment')
stim.CircuitInstruction('CX', [stim.target_rec(-1), stim.GateTarget(5)], [])
"""
```

Expand Down Expand Up @@ -3989,7 +4079,7 @@ def num_measurements(
3
>>> stim.Circuit('MPP X0*X1 X0*Z1*Y2')[0].num_measurements
2
>>> stim.CircuitInstruction('HERALDED_ERASE', [0]).num_measurements
>>> stim.CircuitInstruction('HERALDED_ERASE', [0], [0.25]).num_measurements
1
"""
```
Expand Down Expand Up @@ -4207,6 +4297,27 @@ def name(
"""
```

<a name="stim.CircuitRepeatBlock.num_measurements"></a>
```python
# stim.CircuitRepeatBlock.num_measurements

# (in class stim.CircuitRepeatBlock)
@property
def num_measurements(
self,
) -> int:
"""Returns the number of bits produced when running this loop.
Examples:
>>> import stim
>>> stim.CircuitRepeatBlock(
... body=stim.Circuit("M 0 1"),
... repeat_count=25,
... ).num_measurements
50
"""
```

<a name="stim.CircuitRepeatBlock.repeat_count"></a>
```python
# stim.CircuitRepeatBlock.repeat_count
Expand Down Expand Up @@ -5336,13 +5447,15 @@ def __eq__(
def __init__(
self,
type: str,
args: List[float],
targets: List[object],
args: Optional[Iterable[float]] = None,
targets: Optional[Iterable[stim.DemTarget]] = None,
) -> None:
"""Creates a stim.DemInstruction.
"""Creates or parses a stim.DemInstruction.
Args:
type: The name of the instruction type (e.g. "error" or "shift_detectors").
If `args` and `targets` aren't specified, this can also be set to a
full line of text from a dem file, like "error(0.25) D0".
args: Numeric values parameterizing the instruction (e.g. the 0.1 in
"error(0.1)").
targets: The objects the instruction involves (e.g. the "D0" and "L1" in
Expand All @@ -5356,6 +5469,9 @@ def __init__(
... [stim.target_relative_detector_id(5)])
>>> print(instruction)
error(0.125) D5
>>> print(stim.DemInstruction('error(0.125) D5 L6 ^ D4 # comment'))
error(0.125) D5 L6 ^ D4
"""
```

Expand Down
Loading

0 comments on commit 42b07a1

Please sign in to comment.