Skip to content

Commit

Permalink
Add stim.Circuit.insert and numpy 2 compat (#787)
Browse files Browse the repository at this point in the history
- Also fix an issue where enormous stats cause sinter to fail to plot
- Also fix an issue where circuits with the same blocks could be
considered not equal if their internal representation was different
- Also bump pybind version to make numpy 2 start working
- Also fix an issue where the scipy linear regression type was accessed
from a private module; use the public API as a fallback

Fixes #780

Fixes #779
  • Loading branch information
Strilanc authored Jun 25, 2024
1 parent 2b3b645 commit 345de6c
Show file tree
Hide file tree
Showing 13 changed files with 504 additions and 42 deletions.
10 changes: 6 additions & 4 deletions WORKSPACE
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
load("@pybind11_bazel//:python_configure.bzl", "python_configure")

http_archive(
name = "pybind11",
build_file = "@pybind11_bazel//:pybind11.BUILD",
sha256 = "d475978da0cdc2d43b73f30910786759d593a9d8ee05b1b6846d1eb16c6d2e0c",
strip_prefix = "pybind11-2.11.1",
urls = ["https://github.com/pybind/pybind11/archive/refs/tags/v2.11.1.tar.gz"],
sha256 = "bf8f242abd1abcd375d516a7067490fb71abd79519a282d22b6e4d19282185a7",
strip_prefix = "pybind11-2.12.0",
urls = ["https://github.com/pybind/pybind11/archive/refs/tags/v2.12.0.tar.gz"],
)
load("@pybind11_bazel//:python_configure.bzl", "python_configure")

python_configure(name = "local_config_python")
6 changes: 6 additions & 0 deletions dev/util_gen_stub_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,12 @@ def __init__(self):


def splay_signature(sig: str) -> List[str]:
# Maintain backwards compatibility with python 3.6
sig = sig.replace('list[', 'List[')
sig = sig.replace('dict[', 'Dict[')
sig = sig.replace('tuple[', 'Tuple[')
sig = sig.replace('set[', 'Set[')

assert sig.startswith('def')
out = []

Expand Down
2 changes: 1 addition & 1 deletion doc/gates.md
Original file line number Diff line number Diff line change
Expand Up @@ -3111,7 +3111,7 @@ Decomposition (into H, S, CX, M, R):
<a name="SPP_DAG"></a>
### The 'SPP_DAG' Instruction

The generalized S gate. Phases the -1 eigenspace of Pauli product observables by i.
The generalized S_DAG gate. Phases the -1 eigenspace of Pauli product observables by -i.

Parens Arguments:

Expand Down
82 changes: 76 additions & 6 deletions doc/python_api_reference_vDev.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ API references for stable versions are kept on the [stim github wiki](https://gi
- [`stim.Circuit.get_final_qubit_coordinates`](#stim.Circuit.get_final_qubit_coordinates)
- [`stim.Circuit.has_all_flows`](#stim.Circuit.has_all_flows)
- [`stim.Circuit.has_flow`](#stim.Circuit.has_flow)
- [`stim.Circuit.insert`](#stim.Circuit.insert)
- [`stim.Circuit.inverse`](#stim.Circuit.inverse)
- [`stim.Circuit.likeliest_error_sat_problem`](#stim.Circuit.likeliest_error_sat_problem)
- [`stim.Circuit.num_detectors`](#stim.Circuit.num_detectors)
Expand Down Expand Up @@ -2223,6 +2224,64 @@ def has_flow(
"""
```

<a name="stim.Circuit.insert"></a>
```python
# stim.Circuit.insert

# (in class stim.Circuit)
def insert(
self,
index: int,
operation: Union[stim.CircuitInstruction, stim.Circuit],
) -> None:
"""Inserts an operation at the given index, pushing existing operations forward.
Note that, unlike when appending operations or parsing stim circuit files,
inserted operations aren't automatically fused into the preceding operation.
This is to avoid creating complicated situations where it's difficult to reason
about how the indices of operations change in response to insertions.
Args:
index: The index to insert at.
Must satisfy -len(circuit) <= index < len(circuit). Negative indices
are made non-negative by adding len(circuit) to them, so they refer to
indices relative to the end of the circuit instead of the start.
Instructions before the index are not shifted. Instructions that
were at or after the index are shifted forwards.
operation: The object to insert. This can be a single
stim.CircuitInstruction or an entire stim.Circuit.
Examples:
>>> import stim
>>> c = stim.Circuit('''
... H 0
... S 1
... X 2
... ''')
>>> c.insert(1, stim.CircuitInstruction("Y", [3, 4, 5]))
>>> c
stim.Circuit('''
H 0
Y 3 4 5
S 1
X 2
''')
>>> c.insert(-1, stim.Circuit("S 999\nCX 0 1\nCZ 2 3"))
>>> c
stim.Circuit('''
H 0
Y 3 4 5
S 1
S 999
CX 0 1
CZ 2 3
X 2
''')
"""
```

<a name="stim.Circuit.inverse"></a>
```python
# stim.Circuit.inverse
Expand Down Expand Up @@ -2569,6 +2628,14 @@ def reference_sample(
Returns:
reference_sample: reference sample sampled from the given circuit.
Examples:
>>> import stim
>>> stim.Circuit('''
... X 1
... M 0 1
... ''').reference_sample()
array([False, True])
"""
```

Expand Down Expand Up @@ -13832,15 +13899,18 @@ def state_vector(
>>> import numpy as np
>>> s = stim.TableauSimulator()
>>> s.x(2)
>>> list(s.state_vector(endian='little'))
[0j, 0j, 0j, 0j, (1+0j), 0j, 0j, 0j]
>>> s.state_vector(endian='little')
array([0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
dtype=complex64)
>>> list(s.state_vector(endian='big'))
[0j, (1+0j), 0j, 0j, 0j, 0j, 0j, 0j]
>>> s.state_vector(endian='big')
array([0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
dtype=complex64)
>>> s.sqrt_x(1, 2)
>>> list(s.state_vector())
[(0.5+0j), 0j, -0.5j, 0j, 0.5j, 0j, (0.5+0j), 0j]
>>> s.state_vector()
array([0.5+0.j , 0. +0.j , 0. -0.5j, 0. +0.j , 0. +0.5j, 0. +0.j ,
0.5+0.j , 0. +0.j ], dtype=complex64)
"""
```

Expand Down
74 changes: 68 additions & 6 deletions doc/stim.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -1600,6 +1600,57 @@ class Circuit:
True, there is technically still a 2^-256 chance the circuit doesn't have
the flow. This is lower than the chance of a cosmic ray flipping the result.
"""
def insert(
self,
index: int,
operation: Union[stim.CircuitInstruction, stim.Circuit],
) -> None:
"""Inserts an operation at the given index, pushing existing operations forward.
Note that, unlike when appending operations or parsing stim circuit files,
inserted operations aren't automatically fused into the preceding operation.
This is to avoid creating complicated situations where it's difficult to reason
about how the indices of operations change in response to insertions.
Args:
index: The index to insert at.
Must satisfy -len(circuit) <= index < len(circuit). Negative indices
are made non-negative by adding len(circuit) to them, so they refer to
indices relative to the end of the circuit instead of the start.
Instructions before the index are not shifted. Instructions that
were at or after the index are shifted forwards.
operation: The object to insert. This can be a single
stim.CircuitInstruction or an entire stim.Circuit.
Examples:
>>> import stim
>>> c = stim.Circuit('''
... H 0
... S 1
... X 2
... ''')
>>> c.insert(1, stim.CircuitInstruction("Y", [3, 4, 5]))
>>> c
stim.Circuit('''
H 0
Y 3 4 5
S 1
X 2
''')
>>> c.insert(-1, stim.Circuit("S 999\nCX 0 1\nCZ 2 3"))
>>> c
stim.Circuit('''
H 0
Y 3 4 5
S 1
S 999
CX 0 1
CZ 2 3
X 2
''')
"""
def inverse(
self,
) -> stim.Circuit:
Expand Down Expand Up @@ -1885,6 +1936,14 @@ class Circuit:
Returns:
reference_sample: reference sample sampled from the given circuit.
Examples:
>>> import stim
>>> stim.Circuit('''
... X 1
... M 0 1
... ''').reference_sample()
array([False, True])
"""
def search_for_undetectable_logical_errors(
self,
Expand Down Expand Up @@ -10851,15 +10910,18 @@ class TableauSimulator:
>>> import numpy as np
>>> s = stim.TableauSimulator()
>>> s.x(2)
>>> list(s.state_vector(endian='little'))
[0j, 0j, 0j, 0j, (1+0j), 0j, 0j, 0j]
>>> s.state_vector(endian='little')
array([0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
dtype=complex64)
>>> list(s.state_vector(endian='big'))
[0j, (1+0j), 0j, 0j, 0j, 0j, 0j, 0j]
>>> s.state_vector(endian='big')
array([0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
dtype=complex64)
>>> s.sqrt_x(1, 2)
>>> list(s.state_vector())
[(0.5+0j), 0j, -0.5j, 0j, 0.5j, 0j, (0.5+0j), 0j]
>>> s.state_vector()
array([0.5+0.j , 0. +0.j , 0. -0.5j, 0. +0.j , 0. +0.5j, 0. +0.j ,
0.5+0.j , 0. +0.j ], dtype=complex64)
"""
def swap(
self,
Expand Down
74 changes: 68 additions & 6 deletions glue/python/src/stim/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -1600,6 +1600,57 @@ class Circuit:
True, there is technically still a 2^-256 chance the circuit doesn't have
the flow. This is lower than the chance of a cosmic ray flipping the result.
"""
def insert(
self,
index: int,
operation: Union[stim.CircuitInstruction, stim.Circuit],
) -> None:
"""Inserts an operation at the given index, pushing existing operations forward.
Note that, unlike when appending operations or parsing stim circuit files,
inserted operations aren't automatically fused into the preceding operation.
This is to avoid creating complicated situations where it's difficult to reason
about how the indices of operations change in response to insertions.
Args:
index: The index to insert at.
Must satisfy -len(circuit) <= index < len(circuit). Negative indices
are made non-negative by adding len(circuit) to them, so they refer to
indices relative to the end of the circuit instead of the start.
Instructions before the index are not shifted. Instructions that
were at or after the index are shifted forwards.
operation: The object to insert. This can be a single
stim.CircuitInstruction or an entire stim.Circuit.
Examples:
>>> import stim
>>> c = stim.Circuit('''
... H 0
... S 1
... X 2
... ''')
>>> c.insert(1, stim.CircuitInstruction("Y", [3, 4, 5]))
>>> c
stim.Circuit('''
H 0
Y 3 4 5
S 1
X 2
''')
>>> c.insert(-1, stim.Circuit("S 999\nCX 0 1\nCZ 2 3"))
>>> c
stim.Circuit('''
H 0
Y 3 4 5
S 1
S 999
CX 0 1
CZ 2 3
X 2
''')
"""
def inverse(
self,
) -> stim.Circuit:
Expand Down Expand Up @@ -1885,6 +1936,14 @@ class Circuit:
Returns:
reference_sample: reference sample sampled from the given circuit.
Examples:
>>> import stim
>>> stim.Circuit('''
... X 1
... M 0 1
... ''').reference_sample()
array([False, True])
"""
def search_for_undetectable_logical_errors(
self,
Expand Down Expand Up @@ -10851,15 +10910,18 @@ class TableauSimulator:
>>> import numpy as np
>>> s = stim.TableauSimulator()
>>> s.x(2)
>>> list(s.state_vector(endian='little'))
[0j, 0j, 0j, 0j, (1+0j), 0j, 0j, 0j]
>>> s.state_vector(endian='little')
array([0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
dtype=complex64)
>>> list(s.state_vector(endian='big'))
[0j, (1+0j), 0j, 0j, 0j, 0j, 0j, 0j]
>>> s.state_vector(endian='big')
array([0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
dtype=complex64)
>>> s.sqrt_x(1, 2)
>>> list(s.state_vector())
[(0.5+0j), 0j, -0.5j, 0j, 0.5j, 0j, (0.5+0j), 0j]
>>> s.state_vector()
array([0.5+0.j , 0. +0.j , 0. -0.5j, 0. +0.j , 0. +0.5j, 0. +0.j ,
0.5+0.j , 0. +0.j ], dtype=complex64)
"""
def swap(
self,
Expand Down
Loading

0 comments on commit 345de6c

Please sign in to comment.