Skip to content

Commit 2581b90

Browse files
authored
Add the ability to tag circuit instructions (#848)
- For example, `TICK[100ns]` instead of `TICK` or `I[DYNAMICDECOUPLE] 2 3 5` instead of `I 2 3 5` - Stim ignores tags, except for propagating them through circuit transformations - Users can use tags for debugging or to communicate information from tools generating stim circuits to tools consuming them ```python import stim circuit = stim.Circuit(""" R[mlr] 0 1 TICK[200ns] H 0 TICK[10ns] REPEAT[unroll] 3 { CZ[adiabatic] 0 1 TICK[20ns] } H 0 TICK[20ns] I[DYNAMIC_DECOUPLE_NEW_LATEST_VERSION_5_FINAL_ACTUALLY_FINAL_YXY] 2 3 4 5 M[include_two_state] 0 1 DETECTOR[subgraph_2] rec[-1] rec[-2] """) assert circuit[0].tag == "mlr" assert circuit[1].tag == "200ns" assert circuit[2].tag == "" ``` Fixes #843
1 parent e1de0e6 commit 2581b90

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+1616
-589
lines changed

doc/file_format_stim_circuit.md

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,17 @@ Each line is either blank, an instruction, a block initiator, or a block termina
3434
Also, each line may be indented with spacing characters and may end with a comment indicated by a hash (`#`).
3535
Comments and indentation are purely decorative; they carry no semantic significance.
3636

37+
Here is a formal definition of the above paragraph.
38+
Entries like `/this/` are regular expressions.
39+
Entries like `<this>` are named expressions.
40+
Entries like `'this'` are literal string expressions.
41+
The `::=` operator means "defined as".
42+
The `|` binary operator means "or".
43+
The `?` suffix operator means "zero-or-one".
44+
The `*` suffix operator means "zero-or-many".
45+
Parens are used to group expressions.
46+
Adjacent expressions are combined by concatenation.
47+
3748
```
3849
<CIRCUIT> ::= <LINE>*
3950
<LINE> ::= <INDENT> (<INSTRUCTION> | <BLOCK_START> | <BLOCK_END>)? <COMMENT>? '\n'
@@ -42,13 +53,15 @@ Comments and indentation are purely decorative; they carry no semantic significa
4253
```
4354

4455
An *instruction* is composed of a name,
56+
then (introduced in stim v1.15) an optional tag inside square brackets,
4557
then an optional comma-separated list of arguments inside of parentheses,
4658
then a list of space-separated targets.
4759
For example, the line `X_ERROR(0.1) 5 6` is an instruction with a name (`X_ERROR`),
4860
one argument (`0.1`), and two targets (`5` and `6`).
4961

5062
```
51-
<INSTRUCTION> ::= <NAME> <PARENS_ARGUMENTS>? <TARGETS>
63+
<INSTRUCTION> ::= <NAME> <TAG>? <PARENS_ARGUMENTS>? <TARGETS>
64+
<TAG> ::= '[' /[^\r\]\n]/* ']'
5265
<PARENS_ARGUMENTS> ::= '(' <ARGUMENTS> ')'
5366
<ARGUMENTS> ::= /[ \t]*/ <ARG> /[ \t]*/ (',' <ARGUMENTS>)?
5467
<TARGETS> ::= /[ \t]+/ <TARG> <TARGETS>?
@@ -57,6 +70,14 @@ one argument (`0.1`), and two targets (`5` and `6`).
5770
An instruction *name* starts with a letter and then contains a series of letters, digits, and underscores.
5871
Names are case-insensitive.
5972

73+
An instruction *tag* is an arbitrary string enclosed by square brackets.
74+
Certain characters cannot appear directly in the tag, and must instead be included using escape sequences.
75+
The closing square bracket character `]` cannot appear directly, and is instead encoded using the escape sequence `\C`.
76+
The carriage return character cannot appear directly, and is instead encoded using the escape sequence `\r`.
77+
The line feed character cannot appear directly, and is instead encoded using the escape sequence `\n`.
78+
The backslash character `\` cannot appear directly, and is instead encoded using the escape sequence `\B`.
79+
(This backslash escape sequence differs from the common escape sequence `\\` because that sequence causes exponential explosions when escaping multiple times.)
80+
6081
An *argument* is a double precision floating point number.
6182

6283
A *target* can either be a qubit target (a non-negative integer),
@@ -124,6 +145,17 @@ Currently, control flow is limited to *repetition*.
124145
A circuit can contain `REPEAT K { ... }` blocks,
125146
which indicate that the block's instructions should be iterated over `K` times instead of just once.
126147

148+
### Tags
149+
150+
Instruction tags have no effect on the function of a circuit.
151+
In general, tools should attempt to propagate tags through circuit transformations and otherwise ignore them.
152+
The intent is that users and tools can use tags to specify custom behavior that stim is not aware of.
153+
For example, consider the tagged instruction `TICK[100ns]`.
154+
In most situations, the `100ns` tag does nothing.
155+
But if you are using a tool that adds noise to circuits, and it's programmed to look at tags to get hints about what
156+
noise to add, then the `100ns` tag could be a message to that tool (specifying a duration, which the tool could use when
157+
computing the probability argument of an inserted `DEPOLARIZE1` instruction).
158+
127159
### Target Types
128160

129161
There are four types of targets that can be given to instructions:

doc/python_api_reference_vDev.md

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ API references for stable versions are kept on the [stim github wiki](https://gi
8383
- [`stim.CircuitInstruction.gate_args_copy`](#stim.CircuitInstruction.gate_args_copy)
8484
- [`stim.CircuitInstruction.name`](#stim.CircuitInstruction.name)
8585
- [`stim.CircuitInstruction.num_measurements`](#stim.CircuitInstruction.num_measurements)
86+
- [`stim.CircuitInstruction.tag`](#stim.CircuitInstruction.tag)
8687
- [`stim.CircuitInstruction.target_groups`](#stim.CircuitInstruction.target_groups)
8788
- [`stim.CircuitInstruction.targets_copy`](#stim.CircuitInstruction.targets_copy)
8889
- [`stim.CircuitRepeatBlock`](#stim.CircuitRepeatBlock)
@@ -94,6 +95,7 @@ API references for stable versions are kept on the [stim github wiki](https://gi
9495
- [`stim.CircuitRepeatBlock.name`](#stim.CircuitRepeatBlock.name)
9596
- [`stim.CircuitRepeatBlock.num_measurements`](#stim.CircuitRepeatBlock.num_measurements)
9697
- [`stim.CircuitRepeatBlock.repeat_count`](#stim.CircuitRepeatBlock.repeat_count)
98+
- [`stim.CircuitRepeatBlock.tag`](#stim.CircuitRepeatBlock.tag)
9799
- [`stim.CircuitTargetsInsideInstruction`](#stim.CircuitTargetsInsideInstruction)
98100
- [`stim.CircuitTargetsInsideInstruction.__init__`](#stim.CircuitTargetsInsideInstruction.__init__)
99101
- [`stim.CircuitTargetsInsideInstruction.args`](#stim.CircuitTargetsInsideInstruction.args)
@@ -4017,6 +4019,8 @@ def __init__(
40174019
name: str,
40184020
targets: Optional[Iterable[Union[int, stim.GateTarget]]] = None,
40194021
gate_args: Optional[Iterable[float]] = None,
4022+
*,
4023+
tag: str = "",
40204024
) -> None:
40214025
"""Creates or parses a `stim.CircuitInstruction`.
40224026
@@ -4030,6 +4034,11 @@ def __init__(
40304034
gate_args: The sequence of numeric arguments parameterizing a gate. For
40314035
noise gates this is their probabilities. For `OBSERVABLE_INCLUDE`
40324036
instructions it's the index of the logical observable to affect.
4037+
tag: Defaults to "". A custom string attached to the instruction. For
4038+
example, for a TICK instruction, this could a string specifying an
4039+
amount of time which is used by custom code for adding noise to a
4040+
circuit. In general, stim will attempt to propagate tags across circuit
4041+
transformations but will otherwise completely ignore them.
40334042
40344043
Examples:
40354044
>>> import stim
@@ -4039,6 +4048,9 @@ def __init__(
40394048
40404049
>>> stim.CircuitInstruction('CX rec[-1] 5 # comment')
40414050
stim.CircuitInstruction('CX', [stim.target_rec(-1), stim.GateTarget(5)], [])
4051+
4052+
>>> print(stim.CircuitInstruction('I', [2], tag='100ns'))
4053+
I[100ns] 2
40424054
"""
40434055
```
40444056

@@ -4147,6 +4159,29 @@ def num_measurements(
41474159
"""
41484160
```
41494161

4162+
<a name="stim.CircuitInstruction.tag"></a>
4163+
```python
4164+
# stim.CircuitInstruction.tag
4165+
4166+
# (in class stim.CircuitInstruction)
4167+
@property
4168+
def tag(
4169+
self,
4170+
) -> str:
4171+
"""The custom tag attached to the instruction.
4172+
4173+
The tag is an arbitrary string.
4174+
The default tag, when none is specified, is the empty string.
4175+
4176+
Examples:
4177+
>>> import stim
4178+
>>> stim.Circuit("H[test] 0")[0].tag
4179+
'test'
4180+
>>> stim.Circuit("H 0")[0].tag
4181+
''
4182+
"""
4183+
```
4184+
41504185
<a name="stim.CircuitInstruction.target_groups"></a>
41514186
```python
41524187
# stim.CircuitInstruction.target_groups
@@ -4266,12 +4301,15 @@ def __init__(
42664301
self,
42674302
repeat_count: int,
42684303
body: stim.Circuit,
4304+
*,
4305+
tag: str = '',
42694306
) -> None:
42704307
"""Initializes a `stim.CircuitRepeatBlock`.
42714308
42724309
Args:
42734310
repeat_count: The number of times to repeat the block.
42744311
body: The body of the block, as a circuit.
4312+
tag: Defaults to empty. A custom string attached to the REPEAT instruction.
42754313
"""
42764314
```
42774315

@@ -4407,6 +4445,39 @@ def repeat_count(
44074445
"""
44084446
```
44094447

4448+
<a name="stim.CircuitRepeatBlock.tag"></a>
4449+
```python
4450+
# stim.CircuitRepeatBlock.tag
4451+
4452+
# (in class stim.CircuitRepeatBlock)
4453+
@property
4454+
def tag(
4455+
self,
4456+
) -> str:
4457+
"""The custom tag attached to the REPEAT instruction.
4458+
4459+
The tag is an arbitrary string.
4460+
The default tag, when none is specified, is the empty string.
4461+
4462+
Examples:
4463+
>>> import stim
4464+
4465+
>>> stim.Circuit('''
4466+
... REPEAT[test] 5 {
4467+
... H 0
4468+
... }
4469+
... ''')[0].tag
4470+
'test'
4471+
4472+
>>> stim.Circuit('''
4473+
... REPEAT 5 {
4474+
... H 0
4475+
... }
4476+
... ''')[0].tag
4477+
''
4478+
"""
4479+
```
4480+
44104481
<a name="stim.CircuitTargetsInsideInstruction"></a>
44114482
```python
44124483
# stim.CircuitTargetsInsideInstruction
@@ -6149,6 +6220,18 @@ def __init__(
61496220
coords: List[float],
61506221
) -> None:
61516222
"""Creates a stim.DemTargetWithCoords.
6223+
6224+
Examples:
6225+
>>> import stim
6226+
>>> err = stim.Circuit('''
6227+
... R 0 1
6228+
... X_ERROR(0.25) 0 1
6229+
... M 0 1
6230+
... DETECTOR(2, 3) rec[-1] rec[-2]
6231+
... OBSERVABLE_INCLUDE(0) rec[-1]
6232+
... ''').shortest_graphlike_error()
6233+
>>> err[0].dem_error_terms[0]
6234+
stim.DemTargetWithCoords(dem_target=stim.DemTarget('D0'), coords=[2, 3])
61526235
"""
61536236
```
61546237

@@ -6164,6 +6247,18 @@ def coords(
61646247
"""Returns the associated coordinate information as a list of floats.
61656248
61666249
If there is no coordinate information, returns an empty list.
6250+
6251+
Examples:
6252+
>>> import stim
6253+
>>> err = stim.Circuit('''
6254+
... R 0 1
6255+
... X_ERROR(0.25) 0 1
6256+
... M 0 1
6257+
... DETECTOR(2, 3) rec[-1] rec[-2]
6258+
... OBSERVABLE_INCLUDE(0) rec[-1]
6259+
... ''').shortest_graphlike_error()
6260+
>>> err[0].dem_error_terms[0].coords
6261+
[2.0, 3.0]
61676262
"""
61686263
```
61696264

@@ -6177,6 +6272,18 @@ def dem_target(
61776272
self,
61786273
) -> stim.DemTarget:
61796274
"""Returns the actual DEM target as a `stim.DemTarget`.
6275+
6276+
Examples:
6277+
>>> import stim
6278+
>>> err = stim.Circuit('''
6279+
... R 0 1
6280+
... X_ERROR(0.25) 0 1
6281+
... M 0 1
6282+
... DETECTOR(2, 3) rec[-1] rec[-2]
6283+
... OBSERVABLE_INCLUDE(0) rec[-1]
6284+
... ''').shortest_graphlike_error()
6285+
>>> err[0].dem_error_terms[0].dem_target
6286+
stim.DemTarget('D0')
61806287
"""
61816288
```
61826289

0 commit comments

Comments
 (0)