stimflow 0.1.0__tar.gz → 1.16.dev0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. {stimflow-0.1.0 → stimflow-1.16.dev0}/PKG-INFO +3 -3
  2. {stimflow-0.1.0 → stimflow-1.16.dev0}/README.md +2 -2
  3. {stimflow-0.1.0 → stimflow-1.16.dev0}/setup.py +1 -1
  4. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/__init__.py +2 -2
  5. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_chunk/_chunk.py +3 -14
  6. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_chunk/_chunk_compiler.py +2 -2
  7. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_chunk/_chunk_interface.py +2 -2
  8. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_chunk/_chunk_loop.py +2 -2
  9. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_chunk/_patch.py +8 -5
  10. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_chunk/_stabilizer_code.py +26 -12
  11. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_core/_flow.py +0 -1
  12. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_core/_pauli_map.py +11 -2
  13. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_layers/_layer_circuit.py +7 -0
  14. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_viz/__init__.py +2 -2
  15. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_viz/_viz_circuit_html.py +2 -2
  16. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_viz/_viz_circuit_html_test.py +1 -1
  17. stimflow-1.16.dev0/src/stimflow/_viz/_viz_html.py +84 -0
  18. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_viz/_viz_patch_svg.py +25 -21
  19. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_viz/_viz_patch_svg_test.py +1 -1
  20. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_viz/_viz_svg.py +35 -27
  21. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow.egg-info/PKG-INFO +3 -3
  22. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow.egg-info/SOURCES.txt +1 -0
  23. {stimflow-0.1.0 → stimflow-1.16.dev0}/requirements.txt +0 -0
  24. {stimflow-0.1.0 → stimflow-1.16.dev0}/setup.cfg +0 -0
  25. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_chunk/__init__.py +0 -0
  26. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_chunk/_chunk_builder.py +0 -0
  27. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_chunk/_chunk_builder_test.py +0 -0
  28. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_chunk/_chunk_compiler_test.py +0 -0
  29. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_chunk/_chunk_reflow.py +0 -0
  30. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_chunk/_chunk_reflow_test.py +0 -0
  31. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_chunk/_chunk_test.py +0 -0
  32. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_chunk/_code_util.py +0 -0
  33. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_chunk/_code_util_test.py +0 -0
  34. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_chunk/_flow_metadata.py +0 -0
  35. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_chunk/_flow_util.py +0 -0
  36. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_chunk/_flow_util_test.py +0 -0
  37. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_chunk/_patch_test.py +0 -0
  38. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_chunk/_stabilizer_code_test.py +0 -0
  39. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_chunk/_test_util.py +0 -0
  40. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_chunk/_weave.py +0 -0
  41. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_chunk/_weave_test.py +0 -0
  42. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_core/__init__.py +0 -0
  43. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_core/_circuit_util.py +0 -0
  44. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_core/_circuit_util_test.py +0 -0
  45. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_core/_complex_util.py +0 -0
  46. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_core/_complex_util_test.py +0 -0
  47. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_core/_flow_test.py +0 -0
  48. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_core/_noise.py +0 -0
  49. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_core/_noise_test.py +0 -0
  50. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_core/_pauli_map_test.py +0 -0
  51. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_core/_str_html.py +0 -0
  52. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_core/_str_svg.py +0 -0
  53. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_core/_tile.py +0 -0
  54. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_core/_tile_test.py +0 -0
  55. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_layers/__init__.py +0 -0
  56. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_layers/_data.py +0 -0
  57. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_layers/_data_test.py +0 -0
  58. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_layers/_layer.py +0 -0
  59. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_layers/_layer_circuit_test.py +0 -0
  60. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_layers/_layer_det_obs_annotation.py +0 -0
  61. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_layers/_layer_empty.py +0 -0
  62. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_layers/_layer_feedback.py +0 -0
  63. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_layers/_layer_feedback_test.py +0 -0
  64. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_layers/_layer_interact.py +0 -0
  65. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_layers/_layer_interact_swap.py +0 -0
  66. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_layers/_layer_interact_swap_test.py +0 -0
  67. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_layers/_layer_iswap.py +0 -0
  68. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_layers/_layer_loop.py +0 -0
  69. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_layers/_layer_measure.py +0 -0
  70. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_layers/_layer_mpp.py +0 -0
  71. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_layers/_layer_noise.py +0 -0
  72. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_layers/_layer_qubit_coord_annotation.py +0 -0
  73. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_layers/_layer_reset.py +0 -0
  74. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_layers/_layer_rotation.py +0 -0
  75. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_layers/_layer_rotation_test.py +0 -0
  76. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_layers/_layer_shift_coord_annotation.py +0 -0
  77. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_layers/_layer_sqrt_pp.py +0 -0
  78. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_layers/_layer_swap.py +0 -0
  79. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_layers/_layer_tag.py +0 -0
  80. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_layers/_layer_tag_test.py +0 -0
  81. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_layers/_transpile.py +0 -0
  82. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_layers/_transpile_test.py +0 -0
  83. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_viz/_3d_model.py +0 -0
  84. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_viz/_3d_model_test.py +0 -0
  85. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_viz/_3d_model_text_texture.py +0 -0
  86. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_viz/_3d_model_viewer.py +0 -0
  87. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow/_viz/_viz_circuit_layer_svg.py +0 -0
  88. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow.egg-info/dependency_links.txt +0 -0
  89. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow.egg-info/requires.txt +0 -0
  90. {stimflow-0.1.0 → stimflow-1.16.dev0}/src/stimflow.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: stimflow
3
- Version: 0.1.0
3
+ Version: 1.16.dev0
4
4
  Summary: A library for creating quantum error correction circuits.
5
5
  Home-page: https://github.com/quantumlib/stim
6
6
  Author: Craig Gidney
@@ -38,7 +38,7 @@ stimflow also includes functionality for:
38
38
 
39
39
  - Transpiling (`stimflow.transpile_to_z_basis_interaction_circuit(...)`)
40
40
  - Adding Noise (`stimflow.NoiseModel.uniform_depolarizing(p).noisy_circuit(...)`)
41
- - Visualizing (`stimflow.make_3d_model`, `stimflow.stim_circuit_html_viewer`)
41
+ - Visualizing (`stimflow.make_3d_model`, `stimflow.html_viewer`)
42
42
 
43
43
  # Documentation
44
44
 
@@ -153,7 +153,7 @@ def main():
153
153
  noisy_circuit = sf.NoiseModel.uniform_depolarizing(1e-3).noisy_circuit(circuit)
154
154
  distance = len(noisy_circuit.shortest_graphlike_error())
155
155
  assert distance == 7
156
- sf.stim_circuit_html_viewer(noisy_circuit, background=code).write_to('tmp2.html')
156
+ sf.html_viewer(noisy_circuit, background=code).write_to('tmp2.html')
157
157
 
158
158
 
159
159
  if __name__ == "__main__":
@@ -16,7 +16,7 @@ stimflow also includes functionality for:
16
16
 
17
17
  - Transpiling (`stimflow.transpile_to_z_basis_interaction_circuit(...)`)
18
18
  - Adding Noise (`stimflow.NoiseModel.uniform_depolarizing(p).noisy_circuit(...)`)
19
- - Visualizing (`stimflow.make_3d_model`, `stimflow.stim_circuit_html_viewer`)
19
+ - Visualizing (`stimflow.make_3d_model`, `stimflow.html_viewer`)
20
20
 
21
21
  # Documentation
22
22
 
@@ -131,7 +131,7 @@ def main():
131
131
  noisy_circuit = sf.NoiseModel.uniform_depolarizing(1e-3).noisy_circuit(circuit)
132
132
  distance = len(noisy_circuit.shortest_graphlike_error())
133
133
  assert distance == 7
134
- sf.stim_circuit_html_viewer(noisy_circuit, background=code).write_to('tmp2.html')
134
+ sf.html_viewer(noisy_circuit, background=code).write_to('tmp2.html')
135
135
 
136
136
 
137
137
  if __name__ == "__main__":
@@ -19,7 +19,7 @@ with open('README.md', encoding='UTF-8') as f:
19
19
  with open('requirements.txt', encoding='UTF-8') as f:
20
20
  requirements = f.read().splitlines()
21
21
 
22
- __version__ = '0.1.0'
22
+ __version__ = '1.16.dev0'
23
23
 
24
24
  setup(
25
25
  name='stimflow',
@@ -46,7 +46,7 @@ from stimflow._viz import (
46
46
  Viewable3dModelGLTF,
47
47
  html_viewer_for_gltf_model,
48
48
  make_3d_model,
49
- stim_circuit_html_viewer,
50
- svg,
49
+ html_viewer,
50
+ svg_viewer,
51
51
  TextDataFor3DModel,
52
52
  )
@@ -509,20 +509,9 @@ class Chunk:
509
509
  tile_color_func: Callable[[Tile], tuple[float, float, float, float]] | None = None,
510
510
  known_error: Iterable[stim.ExplainedError] | None = None,
511
511
  ) -> str_html:
512
- from stimflow._viz import stim_circuit_html_viewer
513
-
514
- circuit = self.to_closed_circuit()
515
- if background is None:
516
- start = self.start_patch()
517
- end = self.end_patch()
518
- if len(start.tiles) == 0:
519
- background = end
520
- elif len(end.tiles) == 0:
521
- background = start
522
- else:
523
- background = {0: start, circuit.num_ticks: end}
524
- return stim_circuit_html_viewer(
525
- circuit, background=background, tile_color_func=tile_color_func, known_error=known_error
512
+ from stimflow._viz import html_viewer
513
+ return html_viewer(
514
+ self, background=background, tile_color_func=tile_color_func, known_error=known_error
526
515
  )
527
516
 
528
517
  def __mul__(self, other: int) -> ChunkLoop:
@@ -89,9 +89,9 @@ class ChunkCompiler:
89
89
  copy = self.copy()
90
90
  if copy.open_flows:
91
91
  copy.append_magic_end_chunk()
92
- from stimflow._viz import stim_circuit_html_viewer
92
+ from stimflow._viz import html_viewer
93
93
 
94
- return stim_circuit_html_viewer(
94
+ return html_viewer(
95
95
  circuit=copy.finish_circuit(), background=self.cur_end_interface()
96
96
  )
97
97
 
@@ -64,9 +64,9 @@ class ChunkInterface:
64
64
  elif other is not None:
65
65
  flat.extend(other)
66
66
 
67
- from stimflow._viz import svg
67
+ from stimflow._viz import svg_viewer
68
68
 
69
- return svg(
69
+ return svg_viewer(
70
70
  objects=flat,
71
71
  show_obs=show_obs,
72
72
  show_measure_qubits=show_measure_qubits,
@@ -161,13 +161,13 @@ class ChunkLoop:
161
161
  known_error: Iterable[stim.ExplainedError] | None = None,
162
162
  ) -> str_html:
163
163
  """Returns an HTML document containing a viewer for the chunk loop's circuit."""
164
- from stimflow._viz import stim_circuit_html_viewer
164
+ from stimflow._viz import html_viewer
165
165
 
166
166
  if patch is None:
167
167
  patch = self.start_patch()
168
168
  if len(patch.tiles) == 0:
169
169
  patch = self.end_patch()
170
- return stim_circuit_html_viewer(
170
+ return html_viewer(
171
171
  self.to_closed_circuit(),
172
172
  background=patch,
173
173
  tile_color_func=tile_color_func,
@@ -5,7 +5,7 @@ import functools
5
5
  from collections.abc import Callable, Iterable, Iterator
6
6
  from typing import Literal, overload, TYPE_CHECKING
7
7
 
8
- from stimflow._core import PauliMap, str_svg, Tile
8
+ from stimflow._core import PauliMap, str_svg, Tile, min_max_complex
9
9
 
10
10
  if TYPE_CHECKING:
11
11
  from stimflow._chunk._stabilizer_code import StabilizerCode
@@ -22,7 +22,7 @@ class Patch:
22
22
  elif isinstance(tile, PauliMap):
23
23
  kept_tiles.append(tile.to_tile())
24
24
  else:
25
- raise ValueError(f"Don't know how to interpret this as a stimflow.Tile: {tile=}")
25
+ raise ValueError(f"Don't know how to convert a {type(tile)} into a stimflow.Tile: {tile=}")
26
26
  if not do_not_sort:
27
27
  kept_tiles = sorted(kept_tiles)
28
28
 
@@ -39,6 +39,9 @@ class Patch:
39
39
  def __getitem__(self, item: slice) -> Patch:
40
40
  pass
41
41
 
42
+ def _min_max_complex_(self) -> tuple[complex, complex]:
43
+ return min_max_complex(self.used_set, default=0)
44
+
42
45
  def __getitem__(self, item: int | slice) -> Patch | Tile:
43
46
  if isinstance(item, slice):
44
47
  return Patch(self.tiles[item])
@@ -113,12 +116,12 @@ class Patch:
113
116
  tile_color_func: Callable[[Tile], str] | None = None,
114
117
  ) -> str_svg:
115
118
  from stimflow._chunk._stabilizer_code import StabilizerCode
116
- from stimflow._viz import svg
119
+ from stimflow._viz import svg_viewer
117
120
 
118
121
  patches = [self] + ([other] if isinstance(other, (Patch, StabilizerCode)) else list(other))
119
122
 
120
- return svg(
121
- objects=patches,
123
+ return svg_viewer(
124
+ patches,
122
125
  show_measure_qubits=show_measure_qubits,
123
126
  show_data_qubits=show_data_qubits,
124
127
  show_order=show_order,
@@ -355,19 +355,33 @@ class StabilizerCode:
355
355
  f"\n {loc2.gate_target.pauli_type} at {loc2.coords}"
356
356
  )
357
357
 
358
+ def _min_max_complex_(self) -> tuple[complex, complex]:
359
+ return min_max_complex(self.used_set, default=0)
360
+
358
361
  def find_distance(self, *, max_search_weight: int) -> int:
359
362
  return len(self.find_logical_error(max_search_weight=max_search_weight))
360
363
 
361
- def find_logical_error(self, *, max_search_weight: int) -> list[stim.ExplainedError]:
364
+ def find_logical_error(self, *, max_search_weight: int, return_stim_explained_error: bool = False) -> PauliMap | list[stim.ExplainedError]:
362
365
  circuit = self.make_code_capacity_circuit(noise=1e-3)
363
366
  if max_search_weight == 2:
364
- return circuit.shortest_graphlike_error(canonicalize_circuit_errors=True)
365
- return circuit.search_for_undetectable_logical_errors(
366
- dont_explore_edges_with_degree_above=max_search_weight,
367
- dont_explore_detection_event_sets_with_size_above=max_search_weight,
368
- dont_explore_edges_increasing_symptom_degree=False,
369
- canonicalize_circuit_errors=True,
370
- )
367
+ result = circuit.shortest_graphlike_error(canonicalize_circuit_errors=True)
368
+ else:
369
+ result = circuit.search_for_undetectable_logical_errors(
370
+ dont_explore_edges_with_degree_above=max_search_weight,
371
+ dont_explore_detection_event_sets_with_size_above=max_search_weight,
372
+ dont_explore_edges_increasing_symptom_degree=False,
373
+ canonicalize_circuit_errors=True,
374
+ )
375
+ if return_stim_explained_error:
376
+ return result
377
+
378
+ pauli_map = {}
379
+ for err in result:
380
+ for loc in err.circuit_error_locations:
381
+ for term in loc.flipped_pauli_product:
382
+ real, imag = term.coords
383
+ pauli_map[real + 1j*imag] = term.gate_target.pauli_type
384
+ return PauliMap(pauli_map)
371
385
 
372
386
  def with_observables_from_basis(self, basis: Literal["X", "Y", "Z"]) -> StabilizerCode:
373
387
  if basis == "X":
@@ -459,7 +473,7 @@ class StabilizerCode:
459
473
  t2 = tile2.to_pauli_map()
460
474
  if not t1.commutes(t2):
461
475
  raise ValueError(
462
- f"Tile stabilizer {t1=} anticommutes with tile stabilizer {t2=}."
476
+ f"The following two stabilizers anticommute:\n {t1}\n {t2}\n\nMore details:\n\n{tile1!r}\n\n{tile2!r}"
463
477
  )
464
478
 
465
479
  for tile in self.stabilizers.tiles:
@@ -538,10 +552,10 @@ class StabilizerCode:
538
552
  elif other is not None:
539
553
  flat.extend(other)
540
554
 
541
- from stimflow._viz import svg
555
+ from stimflow._viz import svg_viewer
542
556
 
543
- return svg(
544
- objects=flat,
557
+ return svg_viewer(
558
+ flat,
545
559
  title=title,
546
560
  show_obs=show_obs,
547
561
  canvas_height=canvas_height,
@@ -281,7 +281,6 @@ class Flow:
281
281
  start=new_start,
282
282
  end=new_end,
283
283
  measurement_indices=xor_sorted(self.measurement_indices + other.measurement_indices),
284
- obs_name=self.obs_name,
285
284
  flags=self.flags | other.flags,
286
285
  center=new_center,
287
286
  sign=(None if self.sign is None else self.sign ^ other.sign),
@@ -5,7 +5,7 @@ from typing import Any, cast, Literal, TYPE_CHECKING
5
5
 
6
6
  import stim
7
7
 
8
- from stimflow._core._complex_util import sorted_complex
8
+ from stimflow._core._complex_util import sorted_complex, min_max_complex
9
9
 
10
10
  if TYPE_CHECKING:
11
11
  from stimflow._core._tile import Tile
@@ -122,6 +122,15 @@ class PauliMap:
122
122
  self._dict = {}
123
123
  self._hash = hash((self.obs_name, tuple(self._dict.items())))
124
124
 
125
+ def _min_max_complex_(self) -> tuple[complex, complex]:
126
+ return min_max_complex(self.keys(), default=0)
127
+
128
+ def _inline_svg_(self, *, q2p: Callable[[complex], complex], out_lines: list[str]):
129
+ scale = abs(q2p(1) - q2p(0))
130
+ for q, p in self.items():
131
+ pt = q2p(q)
132
+ out_lines.append(f'''<text x="{pt.real}" y="{pt.imag}" dominant-baseline="central" text-anchor="middle" font-size="{scale}">{p}</text>''')
133
+
125
134
  @staticmethod
126
135
  def from_xs(xs: Iterable[complex], *, name: Any = None) -> PauliMap:
127
136
  """Returns a PauliMap mapping the given qubits to the X basis."""
@@ -203,7 +212,7 @@ class PauliMap:
203
212
  c = "IXZY"[cx + cz * 2]
204
213
  if c != "I":
205
214
  result[q] = cast(Literal["X", "Y", "Z"], c)
206
- return PauliMap(result)
215
+ return PauliMap(result, obs_name=self.obs_name if self.obs_name == other.obs_name else None)
207
216
 
208
217
  def __repr__(self) -> str:
209
218
  if self.obs_name is None:
@@ -5,6 +5,7 @@ from typing import Any, cast, Literal, TypeVar
5
5
 
6
6
  import stim
7
7
 
8
+ from stimflow._core import min_max_complex
8
9
  from stimflow._layers._layer_det_obs_annotation import DetObsAnnotationLayer
9
10
  from stimflow._layers._layer_empty import LayerEmpty
10
11
  from stimflow._layers._layer_feedback import LayerFeedback
@@ -37,6 +38,12 @@ class LayerCircuit:
37
38
 
38
39
  layers: list[Layer] = dataclasses.field(default_factory=list)
39
40
 
41
+ def _min_max_complex_(self) -> tuple[complex, complex]:
42
+ return min_max_complex(
43
+ v[0] + v[1] * 1j
44
+ for v in obj.to_stim_circuit().get_final_qubit_coordinates().values()
45
+ )
46
+
40
47
  def touched(self) -> set[int]:
41
48
  result = set()
42
49
  for layer in self.layers:
@@ -2,11 +2,11 @@ from stimflow._viz._3d_model_viewer import (
2
2
  Viewable3dModelGLTF,
3
3
  html_viewer_for_gltf_model,
4
4
  )
5
- from stimflow._viz._viz_circuit_html import stim_circuit_html_viewer
5
+ from stimflow._viz._viz_html import html_viewer
6
6
  from stimflow._viz._3d_model import (
7
7
  LineDataFor3DModel,
8
8
  TriangleDataFor3DModel,
9
9
  TextDataFor3DModel,
10
10
  make_3d_model,
11
11
  )
12
- from stimflow._viz._viz_svg import svg
12
+ from stimflow._viz._viz_svg import svg_viewer
@@ -7,7 +7,7 @@ import math
7
7
  import random
8
8
  import sys
9
9
  from collections.abc import Callable, Iterable
10
- from typing import TYPE_CHECKING
10
+ from typing import TYPE_CHECKING, Any
11
11
 
12
12
  import stim
13
13
 
@@ -750,7 +750,7 @@ def append_patch_polygons(
750
750
  out.append(line)
751
751
 
752
752
 
753
- def stim_circuit_html_viewer(
753
+ def _stim_circuit_html_viewer(
754
754
  circuit: stim.Circuit,
755
755
  *,
756
756
  background: (
@@ -25,5 +25,5 @@ def test_viewer_works_with_all_gates():
25
25
  else:
26
26
  targets = [0, 1]
27
27
  circuit.append(name, targets, args)
28
- viewer = stimflow.stim_circuit_html_viewer(circuit)
28
+ viewer = stimflow.html_viewer(circuit)
29
29
  assert viewer is not None
@@ -0,0 +1,84 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Callable, Iterable
4
+ from typing import TYPE_CHECKING, Any
5
+
6
+ import stim
7
+
8
+ from stimflow._viz._viz_circuit_html import _stim_circuit_html_viewer
9
+
10
+ if TYPE_CHECKING:
11
+ import stimflow
12
+ from stimflow._core import str_html
13
+
14
+
15
+ def html_viewer(
16
+ obj: stim.Circuit | Any,
17
+ *,
18
+ background: (
19
+ stimflow.Patch
20
+ | stimflow.StabilizerCode
21
+ | stimflow.ChunkInterface
22
+ | dict[int, stimflow.Patch | stimflow.StabilizerCode | stimflow.ChunkInterface]
23
+ | None
24
+ ) = None,
25
+ tile_color_func: (
26
+ Callable[[stimflow.Tile], tuple[float, float, float, float] | tuple[float, float, float] | str]
27
+ | None
28
+ ) = None,
29
+ width: int = 500,
30
+ height: int = 500,
31
+ known_error: Iterable[stim.ExplainedError] | None = None,
32
+ ) -> str_html:
33
+ """Creates an HTML page for viewing the given object.
34
+
35
+ Args:
36
+ obj: The object to be visualized.
37
+ background: Something to draw in the background of the viewer (e.g. the
38
+ stimflow.StabilizerCode implemented by the circuit being viewed).
39
+ tile_color_func: Customizes how stabilizers and other operators are drawn.
40
+ width: The width of the viewer.
41
+ height: The height of the viewer.
42
+ known_error: An error (e.g. returned from stim.Circuit.shortest_graphlike_error)
43
+ to show as part of the object.
44
+
45
+ Returns:
46
+ The HTML string (as a stimflow.str_html, which inherits from python's `str`).
47
+
48
+ (The result is of type stimflow.str_html so that its viewer is shown automatically
49
+ in Jupyter notebooks, and also for convenience methods like `write_to`.)
50
+ """
51
+
52
+ from stimflow._chunk import Chunk
53
+ if isinstance(obj, stim.Circuit):
54
+ return _stim_circuit_html_viewer(
55
+ obj,
56
+ background=background,
57
+ tile_color_func=tile_color_func,
58
+ width=width,
59
+ height=height,
60
+ known_error=known_error,
61
+ )
62
+
63
+ elif isinstance(obj, Chunk):
64
+ circuit = obj.to_closed_circuit()
65
+ if background is None:
66
+ start = obj.start_patch()
67
+ end = obj.end_patch()
68
+ if len(start.tiles) == 0:
69
+ background = end
70
+ elif len(end.tiles) == 0:
71
+ background = start
72
+ else:
73
+ background = {0: start, circuit.num_ticks: end}
74
+ return _stim_circuit_html_viewer(
75
+ circuit,
76
+ background=background,
77
+ tile_color_func=tile_color_func,
78
+ known_error=known_error,
79
+ width=width,
80
+ height=height,
81
+ )
82
+
83
+ else:
84
+ raise NotImplementedError(f"Don't know how to make an html viewer for {type(obj)=}.")
@@ -245,6 +245,15 @@ def _draw_patch(
245
245
  stabilizer_style: Literal["polygon", "circles"] | None,
246
246
  observable_style: Literal["label", "polygon", "circles"],
247
247
  ) -> None:
248
+ from stimflow._chunk import Patch, StabilizerCode, ChunkInterface
249
+ if hasattr(obj, "_inline_svg_"):
250
+ obj._inline_svg_(
251
+ out_lines=out_lines,
252
+ q2p=q2p,
253
+ )
254
+ return
255
+ if not isinstance(obj, (Patch, StabilizerCode, ChunkInterface, stim.Circuit)):
256
+ raise NotImplementedError(f'{type(obj)=}')
248
257
  if isinstance(obj, stim.Circuit):
249
258
  from stimflow._viz._viz_circuit_layer_svg import append_circuit_layer_to_svg
250
259
 
@@ -275,25 +284,20 @@ def _draw_patch(
275
284
  f"WARNING: No logical error will be drawn.\n Reason: {ex}",
276
285
  file=sys.stderr,
277
286
  )
278
- err = []
279
- for e in err:
280
- for loc in e.circuit_error_locations:
281
- for loc2 in loc.flipped_pauli_product:
282
- real, imag = loc2.coords
283
- q = real + 1j * imag
284
- p = loc2.gate_target.pauli_type
285
- labels.append(
286
- (
287
- q,
288
- p + "!",
289
- {
290
- "text-anchor": "middle",
291
- "dominant-baseline": "central",
292
- "font-size": scale_factor * 1.1,
293
- "fill": BASE_COLORS_DARK[p],
294
- },
295
- )
296
- )
287
+ err = {}
288
+ for q, p in err.items():
289
+ labels.append(
290
+ (
291
+ q,
292
+ p + "!",
293
+ {
294
+ "text-anchor": "middle",
295
+ "dominant-baseline": "central",
296
+ "font-size": scale_factor * 1.1,
297
+ "fill": BASE_COLORS_DARK[p],
298
+ },
299
+ )
300
+ )
297
301
 
298
302
  if isinstance(obj, StabilizerCode) and show_obs:
299
303
  _draw_obs(
@@ -314,9 +318,9 @@ def _draw_patch(
314
318
 
315
319
  all_points = set(system_qubits)
316
320
  if show_data_qubits:
317
- all_points |= obj.data_set
321
+ all_points |= getattr(obj, 'data_set', set())
318
322
  if show_measure_qubits:
319
- all_points |= obj.measure_set
323
+ all_points |= getattr(obj, 'measure_set', set())
320
324
  if show_coords and all_points:
321
325
  all_x = sorted({q.real for q in all_points})
322
326
  all_y = sorted({q.imag for q in all_points})
@@ -30,5 +30,5 @@ def test_patch_svg_runs():
30
30
  ),
31
31
  ]
32
32
  )
33
- svg_content = stimflow.svg([patch])
33
+ svg_content = stimflow.svg_viewer([patch])
34
34
  assert svg_content is not None
@@ -2,9 +2,10 @@ from __future__ import annotations
2
2
 
3
3
  import math
4
4
  from collections.abc import Callable, Iterable
5
- from typing import Literal, TYPE_CHECKING
5
+ from typing import Literal, TYPE_CHECKING, Any
6
6
 
7
7
  import stim
8
+ from stimflow import PauliMap
8
9
 
9
10
  from stimflow._viz._viz_patch_svg import _draw_patch
10
11
 
@@ -12,10 +13,10 @@ if TYPE_CHECKING:
12
13
  import stimflow
13
14
 
14
15
 
15
- def svg(
16
- objects: Iterable[stimflow.Patch | stimflow.StabilizerCode | stimflow.ChunkInterface | stim.Circuit],
16
+ def svg_viewer(
17
+ obj: stimflow.Patch | stimflow.StabilizerCode | stimflow.ChunkInterface | stim.Circuit | PauliMap | Any | Iterable[stimflow.Patch | stimflow.StabilizerCode | stimflow.ChunkInterface | stim.Circuit | PauliMap | Any],
17
18
  *,
18
- background: stimflow.Patch | stimflow.StabilizerCode | stimflow.ChunkInterface | stim.Circuit | None = None,
19
+ background: stimflow.Patch | stimflow.StabilizerCode | stimflow.ChunkInterface | stim.Circuit | PauliMap | Any | None = None,
19
20
  title: str | list[str] | None = None,
20
21
  canvas_height: int | None = None,
21
22
  show_order: bool = False,
@@ -41,32 +42,39 @@ def svg(
41
42
  show_frames: bool = True,
42
43
  pad: float | None = None,
43
44
  ) -> stimflow.str_svg:
44
- """Returns an SVG image of the given objects."""
45
+ """Returns an SVG image of the given objects.
46
+ """
47
+ from stimflow._chunk import Patch, StabilizerCode, ChunkInterface
48
+ if hasattr(obj, '_inline_svg_') or isinstance(obj, (Patch, StabilizerCode, ChunkInterface, stim.Circuit, PauliMap)):
49
+ objects = [obj]
50
+ else:
51
+ objects = obj
52
+
45
53
  system_qubits = frozenset(system_qubits)
46
54
  if canvas_height is None:
47
55
  canvas_height = 500
48
56
 
49
57
  extra_used_coords = frozenset(extra_used_coords)
50
- from stimflow._layers import LayerCircuit
51
-
52
- patches = tuple(
53
- patch.to_stim_circuit() if isinstance(patch, LayerCircuit) else patch for patch in objects
54
- )
55
- all_points: set[complex] = set()
56
- all_points.update(system_qubits)
57
- all_points.update(extra_used_coords)
58
- for patch in patches:
59
- if isinstance(patch, stim.Circuit):
60
- all_points.update(
61
- v[0] + v[1] * 1j for v in patch.get_final_qubit_coordinates().values()
58
+
59
+ min_max_points: set[complex] = set()
60
+ min_max_points.update(system_qubits)
61
+ min_max_points.update(extra_used_coords)
62
+ for e in [*objects, background]:
63
+ if e is None:
64
+ continue
65
+ elif hasattr(e, '_min_max_complex_'):
66
+ min_max_points.update(e._min_max_complex_())
67
+ elif isinstance(e, stim.Circuit):
68
+ min_max_points.update(
69
+ v[0] + v[1] * 1j for v in e.get_final_qubit_coordinates().values()
62
70
  )
63
71
  else:
64
- all_points.update(patch.used_set)
72
+ raise NotImplementedError(f"Don't know how to determine qubits used by {type(e)=}")
65
73
  if show_all_qubits:
66
- system_qubits = frozenset(all_points)
74
+ system_qubits = frozenset(min_max_points)
67
75
  from stimflow._core import min_max_complex
68
76
 
69
- min_c, max_c = min_max_complex(all_points, default=0)
77
+ min_c, max_c = min_max_complex(min_max_points, default=0)
70
78
  min_c -= 0.5 + 0.5j
71
79
  max_c += 0.5 + 0.5j
72
80
  offset: complex = 0
@@ -82,14 +90,14 @@ def svg(
82
90
  box_x_pitch = box_width + pad
83
91
  box_y_pitch = box_height + pad
84
92
  if cols is None and rows is None:
85
- cols = min(len(patches), math.ceil(math.sqrt(len(patches) * 2)))
86
- rows = math.ceil(len(patches) / max(1, cols))
93
+ cols = min(len(objects), math.ceil(math.sqrt(len(objects) * 2)))
94
+ rows = math.ceil(len(objects) / max(1, cols))
87
95
  elif cols is None:
88
- cols = math.ceil(len(patches) / max(1, rows))
96
+ cols = math.ceil(len(objects) / max(1, rows))
89
97
  elif rows is None:
90
- rows = math.ceil(len(patches) / max(1, cols))
98
+ rows = math.ceil(len(objects) / max(1, cols))
91
99
  else:
92
- assert cols * rows >= len(patches)
100
+ assert cols * rows >= len(objects)
93
101
  total_height = max(1.0, box_y_pitch * rows - pad + offset.imag)
94
102
  total_width = max(1.0, box_x_pitch * cols - pad + offset.real)
95
103
  scale_factor = canvas_height / max(total_height, 1)
@@ -132,7 +140,7 @@ def svg(
132
140
  )
133
141
 
134
142
  clip_path_id_ptr = [0]
135
- for plan_i, plan in enumerate(patches):
143
+ for plan_i, plan in enumerate(objects):
136
144
  layers = [plan]
137
145
  if background is not None:
138
146
  if isinstance(background, (tuple, list)):
@@ -160,7 +168,7 @@ def svg(
160
168
 
161
169
  # Draw frame outlines
162
170
  if show_frames:
163
- for outline_index in range(len(patches)):
171
+ for outline_index in range(len(objects)):
164
172
  a = patch_q2p(outline_index, min_c)
165
173
  a += offset
166
174
  b = patch_q2p(outline_index, max_c)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: stimflow
3
- Version: 0.1.0
3
+ Version: 1.16.dev0
4
4
  Summary: A library for creating quantum error correction circuits.
5
5
  Home-page: https://github.com/quantumlib/stim
6
6
  Author: Craig Gidney
@@ -38,7 +38,7 @@ stimflow also includes functionality for:
38
38
 
39
39
  - Transpiling (`stimflow.transpile_to_z_basis_interaction_circuit(...)`)
40
40
  - Adding Noise (`stimflow.NoiseModel.uniform_depolarizing(p).noisy_circuit(...)`)
41
- - Visualizing (`stimflow.make_3d_model`, `stimflow.stim_circuit_html_viewer`)
41
+ - Visualizing (`stimflow.make_3d_model`, `stimflow.html_viewer`)
42
42
 
43
43
  # Documentation
44
44
 
@@ -153,7 +153,7 @@ def main():
153
153
  noisy_circuit = sf.NoiseModel.uniform_depolarizing(1e-3).noisy_circuit(circuit)
154
154
  distance = len(noisy_circuit.shortest_graphlike_error())
155
155
  assert distance == 7
156
- sf.stim_circuit_html_viewer(noisy_circuit, background=code).write_to('tmp2.html')
156
+ sf.html_viewer(noisy_circuit, background=code).write_to('tmp2.html')
157
157
 
158
158
 
159
159
  if __name__ == "__main__":
@@ -82,6 +82,7 @@ src/stimflow/_viz/__init__.py
82
82
  src/stimflow/_viz/_viz_circuit_html.py
83
83
  src/stimflow/_viz/_viz_circuit_html_test.py
84
84
  src/stimflow/_viz/_viz_circuit_layer_svg.py
85
+ src/stimflow/_viz/_viz_html.py
85
86
  src/stimflow/_viz/_viz_patch_svg.py
86
87
  src/stimflow/_viz/_viz_patch_svg_test.py
87
88
  src/stimflow/_viz/_viz_svg.py
File without changes
File without changes