Skip to content

Commit

Permalink
Fix more issues in preparation for v1.10 (#383)
Browse files Browse the repository at this point in the history
- Add fuzz testing of all the read/write shot formats and options
- Add ability to pass pathlib.Path type to read/write shot methods
- Fix a bug in the ptb64 writing logic related to non-multiple-of-64 shot sizes
- Deprecate `bit_pack` argument name in favor of `bit_packed`
- Fix false positive "writingto zero sized region" warning from GCC from std::vector::insert
- Add a dev script for regenerating the texture data as C++ without exceeding allowed literal sizes
- Add missing cp311-macosx_x86_64 wheel

Fixes #382
  • Loading branch information
Strilanc authored Oct 22, 2022
1 parent 427d81b commit a2379f1
Show file tree
Hide file tree
Showing 31 changed files with 349 additions and 1,159 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ jobs:
{os: macos-latest, dist: cp38-macosx_x86_64, macosarch: x86_64},
{os: macos-latest, dist: cp39-macosx_x86_64, macosarch: x86_64},
{os: macos-latest, dist: cp310-macosx_x86_64, macosarch: x86_64},
{os: macos-latest, dist: cp311-macosx_x86_64, macosarch: x86_64},

{os: macos-latest, dist: cp38-macosx_arm64, macosarch: arm64},
{os: macos-latest, dist: cp39-macosx_arm64, macosarch: arm64},
Expand Down
1 change: 1 addition & 0 deletions BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ cc_binary(
"-fvisibility=hidden",
"-march=native",
"-DSTIM_PYBIND11_MODULE_NAME=stim",
"-DVERSION_INFO=0.0.dev"
],
includes = ["src/"],
linkopts = ["-lpthread"],
Expand Down
17 changes: 17 additions & 0 deletions dev/texture_to_cpp_base64_string.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/bash
set -e

#########################################################################
# Transforms binary data into an array of string literals containing the
# base 64 data encoding the data. The strings are split into an array
# to avoid exceeding C++'s maximum string literal length.
#########################################################################

echo '#include "stim/diagram/gate_data_3d_texture_data.h"'
echo ''
echo 'std::string stim_draw_internal::make_gate_3d_texture_data_uri() {'
echo ' std::string result;'
echo ' result.append("data:image/png;base64,");'
base64 -w 1024 | sed 's/.*/ result.append("\0");/g'
echo ' return result;'
echo '}'
26 changes: 13 additions & 13 deletions doc/python_api_reference_vDev.md
Original file line number Diff line number Diff line change
Expand Up @@ -10229,22 +10229,22 @@ def main(
# (at top-level in the stim module)
def read_shot_data_file(
*,
path: str,
format: str,
path: Union[str, pathlib.Path],
format: Union[str, 'Literal["01", "b8", "r8", "ptb64", "hits", "dets"]'],
bit_packed: bool = False,
num_measurements: int = 0,
num_detectors: int = 0,
num_observables: int = 0,
bit_pack: bool = False,
) -> np.ndarray:
"""Reads shot data, such as measurement samples, from a file.
Args:
path: The path to the file to read the data from.
format: The format that the data is stored in, such as 'b8'.
See https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md
bit_pack: Defaults to false. Determines whether the result is a bool8 numpy
array with one bit per byte, or a uint8 numpy array with 8 bits per
byte.
bit_packed: Defaults to false. Determines whether the result is a bool8
numpy array with one bit per byte, or a uint8 numpy array with 8 bits
per byte.
num_measurements: How many measurements there are per shot.
num_detectors: How many detectors there are per shot.
num_observables: How many observables there are per shot.
Expand All @@ -10254,11 +10254,11 @@ def read_shot_data_file(
Returns:
A numpy array containing the loaded data.
If bit_pack=False:
If bit_packed=False:
dtype = np.bool8
shape = (num_shots, num_measurements + num_detectors + num_observables)
bit b from shot s is at result[s, b]
If bit_pack=True:
If bit_packed=True:
dtype = np.uint8
shape = (num_shots, math.ceil(
(num_measurements + num_detectors + num_observables) / 8))
Expand Down Expand Up @@ -10585,12 +10585,12 @@ def target_z(
# (at top-level in the stim module)
def write_shot_data_file(
*,
data: object,
path: str,
data: np.ndarray,
path: Union[str, pathlib.Path],
format: str,
num_measurements: Any = None,
num_detectors: Any = None,
num_observables: Any = None,
num_measurements: int = 0,
num_detectors: int = 0,
num_observables: int = 0,
) -> None:
"""Writes shot data, such as measurement samples, to a file.
Expand Down
21 changes: 10 additions & 11 deletions doc/result_formats.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ def save_b8(shots: List[List[bool]]) -> bytes:
v = 0
for b in reversed(shot):
v <<= 1
v += b
v += int(b)
output += v.to_bytes(bytes_per_shot, 'little')
return output
```
Expand Down Expand Up @@ -363,7 +363,6 @@ def parse_ptb64(data: bytes, bits_per_shot: int) -> List[List[bool]]:
m_bit_offset = m * 64
for shot in range(64):
bit_offset = group_bit_offset + m_bit_offset + shot
byte_offset = bit_offset // 8
bit = data[bit_offset // 8] & (1 << (bit_offset % 8)) != 0
s = group_index * 64 + shot
result[s][m] = bit
Expand All @@ -377,16 +376,16 @@ def save_ptb64(shots: List[List[bool]]):
if len(shots) % 64 != 0:
raise ValueError("Number of shots must be a multiple of 64.")

output = b""
output = []
for shot_offset in range(0, len(shots), 64):
bits_per_shot = len(shots[0])
for measure_index in range(bits_per_shot):
v = 0
for k in range(64)[::-1]:
v <<= 1
v += shots[shot_offset + k][measure_index]
output += v.to_bytes(8, 'little')
return output
v += int(shots[shot_offset + k][measure_index])
output.append(v.to_bytes(8, 'little'))
return b''.join(output)
```

# <a name="r8"></a>The `r8` Format
Expand Down Expand Up @@ -452,18 +451,18 @@ def parse_r8(data: bytes, bits_per_shot: int) -> List[List[bool]]:
from typing import List

def save_r8(shots: List[List[bool]]) -> bytes:
output = b""
output = []
for shot in shots:
gap = 0
for b in shot + [True]:
for b in list(shot) + [True]:
if b:
while gap >= 255:
gap -= 255
output += (255).to_bytes(1, 'big')
output += gap.to_bytes(1, 'big')
output.append((255).to_bytes(1, 'big'))
output.append(gap.to_bytes(1, 'big'))
gap = 0
else:
gap += 1
return output
return b''.join(output)
```

26 changes: 13 additions & 13 deletions doc/stim.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -7813,22 +7813,22 @@ def main(
"""
def read_shot_data_file(
*,
path: str,
format: str,
path: Union[str, pathlib.Path],
format: Union[str, 'Literal["01", "b8", "r8", "ptb64", "hits", "dets"]'],
bit_packed: bool = False,
num_measurements: int = 0,
num_detectors: int = 0,
num_observables: int = 0,
bit_pack: bool = False,
) -> np.ndarray:
"""Reads shot data, such as measurement samples, from a file.
Args:
path: The path to the file to read the data from.
format: The format that the data is stored in, such as 'b8'.
See https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md
bit_pack: Defaults to false. Determines whether the result is a bool8 numpy
array with one bit per byte, or a uint8 numpy array with 8 bits per
byte.
bit_packed: Defaults to false. Determines whether the result is a bool8
numpy array with one bit per byte, or a uint8 numpy array with 8 bits
per byte.
num_measurements: How many measurements there are per shot.
num_detectors: How many detectors there are per shot.
num_observables: How many observables there are per shot.
Expand All @@ -7838,11 +7838,11 @@ def read_shot_data_file(
Returns:
A numpy array containing the loaded data.
If bit_pack=False:
If bit_packed=False:
dtype = np.bool8
shape = (num_shots, num_measurements + num_detectors + num_observables)
bit b from shot s is at result[s, b]
If bit_pack=True:
If bit_packed=True:
dtype = np.uint8
shape = (num_shots, math.ceil(
(num_measurements + num_detectors + num_observables) / 8))
Expand Down Expand Up @@ -8092,12 +8092,12 @@ def target_z(
"""
def write_shot_data_file(
*,
data: object,
path: str,
data: np.ndarray,
path: Union[str, pathlib.Path],
format: str,
num_measurements: Any = None,
num_detectors: Any = None,
num_observables: Any = None,
num_measurements: int = 0,
num_detectors: int = 0,
num_observables: int = 0,
) -> None:
"""Writes shot data, such as measurement samples, to a file.
Expand Down
1 change: 1 addition & 0 deletions file_lists/source_files_no_main
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ src/stim/diagram/circuit_timeline_helper.cc
src/stim/diagram/detector_slice/detector_slice_set.cc
src/stim/diagram/diagram_util.cc
src/stim/diagram/gate_data_3d.cc
src/stim/diagram/gate_data_3d_texture_data.cc
src/stim/diagram/gate_data_svg.cc
src/stim/diagram/gltf.cc
src/stim/diagram/graph/match_graph_3d_drawer.cc
Expand Down
26 changes: 13 additions & 13 deletions glue/python/src/stim/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -7813,22 +7813,22 @@ def main(
"""
def read_shot_data_file(
*,
path: str,
format: str,
path: Union[str, pathlib.Path],
format: Union[str, 'Literal["01", "b8", "r8", "ptb64", "hits", "dets"]'],
bit_packed: bool = False,
num_measurements: int = 0,
num_detectors: int = 0,
num_observables: int = 0,
bit_pack: bool = False,
) -> np.ndarray:
"""Reads shot data, such as measurement samples, from a file.
Args:
path: The path to the file to read the data from.
format: The format that the data is stored in, such as 'b8'.
See https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md
bit_pack: Defaults to false. Determines whether the result is a bool8 numpy
array with one bit per byte, or a uint8 numpy array with 8 bits per
byte.
bit_packed: Defaults to false. Determines whether the result is a bool8
numpy array with one bit per byte, or a uint8 numpy array with 8 bits
per byte.
num_measurements: How many measurements there are per shot.
num_detectors: How many detectors there are per shot.
num_observables: How many observables there are per shot.
Expand All @@ -7838,11 +7838,11 @@ def read_shot_data_file(
Returns:
A numpy array containing the loaded data.
If bit_pack=False:
If bit_packed=False:
dtype = np.bool8
shape = (num_shots, num_measurements + num_detectors + num_observables)
bit b from shot s is at result[s, b]
If bit_pack=True:
If bit_packed=True:
dtype = np.uint8
shape = (num_shots, math.ceil(
(num_measurements + num_detectors + num_observables) / 8))
Expand Down Expand Up @@ -8092,12 +8092,12 @@ def target_z(
"""
def write_shot_data_file(
*,
data: object,
path: str,
data: np.ndarray,
path: Union[str, pathlib.Path],
format: str,
num_measurements: Any = None,
num_detectors: Any = None,
num_observables: Any = None,
num_measurements: int = 0,
num_detectors: int = 0,
num_observables: int = 0,
) -> None:
"""Writes shot data, such as measurement samples, to a file.
Expand Down
2 changes: 1 addition & 1 deletion src/stim/diagram/gate_data_3d.cc
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ std::map<std::string, std::shared_ptr<GltfMesh>> stim_draw_internal::make_gate_p
auto cube = make_cube_triangle_list(actually_square);
auto image = std::shared_ptr<GltfImage>(new GltfImage{
{"gates_image"},
GATE_DATA_3D_TEXTURE_DATA_URI,
make_gate_3d_texture_data_uri(),
});
auto sampler = std::shared_ptr<GltfSampler>(new GltfSampler{
{"gates_sampler"},
Expand Down
Loading

0 comments on commit a2379f1

Please sign in to comment.