Repository: tqec/tqec

Issue:
Rename YCube to half-cube
From https://github.com/tqec/tqec/pull/492#discussion_r1976490063

> Would it make sense to relabel this class to YHalfCube?
> 
> https://tqec.github.io/tqec/_autosummary/tqec.computation.YCube.html#tqec.computation.YCube
> 
> It is called the YCube in the terminology a couple of sections later. 
> https://tqec.github.io/tqec/user_guide/terminology.html#ycube

It would be better to name Y-cube along the lines of Y half-cube, because that name is more descriptive.

Hints from issue comments:

Solution patch:
diff --git a/docs/user_guide/terminology.rst b/docs/user_guide/terminology.rst
index 89abd84a..b1fccb51 100644
--- a/docs/user_guide/terminology.rst
+++ b/docs/user_guide/terminology.rst
@@ -19,6 +19,38 @@ This is the essence of fault-tolerant quantum computation.
 
 In ``tqec``, a block is either a :ref:`Cube <cube>` or a :ref:`Pipe <pipe>`.
 
+The naming convention for a cube or a pipe is as follows:
+
+- The axes used for labeling are as shown in the figure below. ``RGB`` axes are synonymous to ``XYZ`` axes.
+- We begin by labeling the boundary that is facing the X-axis first, then the one that is facing the Y-axis followed by the one facing the Z-axis.
+
+
+.. figure:: ../media/user_guide/terminology/axes_convention.png
+   :width: 200px
+   :align: center
+
+   X, Y, Z axes
+
+The labels based on color of the boundaries are provided in the table below.
+
+.. list-table::
+   :header-rows: 1
+   :align: center
+
+   * - Color
+     - Boundary
+   * - Red Wall
+     - X
+   * - Green Half-Cube
+     - Y
+   * - Blue Wall
+     - Z
+   * - Yellow band
+     - H
+   * - Open/Hole (no color)
+     - O
+
+
 .. _cube:
 
 Cube
@@ -35,6 +67,7 @@ quantum operations that are applied within the cube. Currently we have the follo
 
 .. _zxcube:
 
+
 :py:class:`~tqec.computation.ZXCube`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -63,13 +96,13 @@ When connected with two or more spatial pipes, they form **spatial junctions**:
 The circuits that implement these spatial cubes are more complex than the circuits for the other cubes, and special care needs to be taken to avoid
 the hook errors from decreasing the circuit-level code distance.
 
-:py:class:`~tqec.computation.YCube`
+:py:class:`~tqec.computation.YHalfCube`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 A green cube representing inplace Y-basis logical initialization or measurement as proposed in `this paper <https://quantum-journal.org/papers/q-2024-04-08-1310/>`_.
 The cube's function, whether for initialization or measurement, is determined by its connection to other cubes, either upwards or downwards.
 
-A ``YCube`` occupies :math:`\approx d^3 /2` spacetime volume, where :math:`d` is the code distance.
+A ``YHalfCube`` occupies :math:`\approx d^3 /2` spacetime volume, where :math:`d` is the code distance.
 
 :py:class:`~tqec.computation.Port`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/src/tqec/__init__.py b/src/tqec/__init__.py
index 506facb6..b32dfa4e 100644
--- a/src/tqec/__init__.py
+++ b/src/tqec/__init__.py
@@ -13,7 +13,7 @@ from .computation import CubeKind as CubeKind
 from .computation import Pipe as Pipe
 from .computation import PipeKind as PipeKind
 from .computation import Port as Port
-from .computation import YCube as YCube
+from .computation import YHalfCube as YHalfCube
 from .computation import ZXCube as ZXCube
 from .interop import RGBA as RGBA
 from .interop import TQECColor as TQECColor
diff --git a/src/tqec/computation/__init__.py b/src/tqec/computation/__init__.py
index 176aac7d..be345b48 100644
--- a/src/tqec/computation/__init__.py
+++ b/src/tqec/computation/__init__.py
@@ -9,7 +9,7 @@ from tqec.computation.block_graph import BlockKind as BlockKind
 from tqec.computation.cube import Cube as Cube
 from tqec.computation.cube import CubeKind as CubeKind
 from tqec.computation.cube import Port as Port
-from tqec.computation.cube import YCube as YCube
+from tqec.computation.cube import YHalfCube as YHalfCube
 from tqec.computation.cube import ZXCube as ZXCube
 from tqec.computation.pipe import Pipe as Pipe
 from tqec.computation.pipe import PipeKind as PipeKind
diff --git a/src/tqec/computation/block_graph.py b/src/tqec/computation/block_graph.py
index 9b70eb34..b60ec778 100644
--- a/src/tqec/computation/block_graph.py
+++ b/src/tqec/computation/block_graph.py
@@ -15,7 +15,7 @@ from tqec.computation.cube import (
     Cube,
     CubeKind,
     Port,
-    YCube,
+    YHalfCube,
     ZXCube,
     cube_kind_from_string,
 )
@@ -314,7 +314,7 @@ class BlockGraph:
         only check the following conditions:
 
         - **No fanout:** ports can only have one pipe connected to them.
-        - **Time-like Y:** Y cubes can only have time-like pipes connected to them.
+        - **Time-like Y:** Y Half Cubes can only have time-like pipes connected to them.
         - **No 3D corner:** a cube cannot have pipes in all three directions.
         - **Match color at passthrough:** two pipes in a "pass-through" should have the same
           color orientation.
@@ -341,11 +341,11 @@ class BlockGraph:
         if cube.is_y_cube:
             if len(pipes) != 1:
                 raise TQECException(
-                    f"Y cube at {cube.position} does not have exactly one pipe connected."
+                    f"Y Half Cube at {cube.position} does not have exactly one pipe connected."
                 )
             if not pipes[0].direction == Direction3D.Z:
                 raise TQECException(
-                    f"Y cube at {cube.position} has non-timelike pipes connected."
+                    f"Y Half Cube at {cube.position} has non-timelike pipes connected."
                 )
             return
 
@@ -650,6 +650,6 @@ def block_kind_from_str(string: str) -> BlockKind:
     if "O" in string:
         return PipeKind.from_str(string)
     elif string == "Y":
-        return YCube()
+        return YHalfCube()
     else:
         return ZXCube.from_str(string)
diff --git a/src/tqec/computation/cube.py b/src/tqec/computation/cube.py
index 145c0b2a..fc5ea64b 100644
--- a/src/tqec/computation/cube.py
+++ b/src/tqec/computation/cube.py
@@ -130,20 +130,20 @@ class Port:
         return isinstance(other, Port)
 
 
-class YCube:
+class YHalfCube:
     """Cube kind representing the Y-basis initialization/measurements."""
 
     def __str__(self) -> str:
         return "Y"
 
     def __hash__(self) -> int:
-        return hash(YCube)
+        return hash(YHalfCube)
 
     def __eq__(self, other: object) -> bool:
-        return isinstance(other, YCube)
+        return isinstance(other, YHalfCube)
 
 
-CubeKind = ZXCube | Port | YCube
+CubeKind = ZXCube | Port | YHalfCube
 """All the possible kinds of cubes."""
 
 
@@ -153,7 +153,7 @@ def cube_kind_from_string(s: str) -> CubeKind:
         case "PORT" | "P":
             return Port()
         case "Y":
-            return YCube()
+            return YHalfCube()
         case _:
             return ZXCube.from_str(s)
 
@@ -210,8 +210,8 @@ class Cube:
     @property
     def is_y_cube(self) -> bool:
         """Return whether the cube is of kind
-        :py:class:`~tqec.computation.cube.YCube`."""
-        return isinstance(self.kind, YCube)
+        :py:class:`~tqec.computation.cube.YHalfCube`."""
+        return isinstance(self.kind, YHalfCube)
 
     @property
     def is_spatial(self) -> bool:
diff --git a/src/tqec/interop/collada/_correlation.py b/src/tqec/interop/collada/_correlation.py
index 2d313d36..1cdb3256 100644
--- a/src/tqec/interop/collada/_correlation.py
+++ b/src/tqec/interop/collada/_correlation.py
@@ -47,7 +47,7 @@ class CorrelationSurfaceTransformationHelper:
         # Surfaces in the cubes
         for v in correlation_surface.span_vertices():
             cube = self._get_cube(v)
-            # Do not add surfaces in ports or Y-cubes
+            # Do not add surfaces in ports or Y Half Cubes
             if cube.is_port or cube.is_y_cube:
                 continue
             transformations.extend(
diff --git a/src/tqec/interop/collada/_geometry.py b/src/tqec/interop/collada/_geometry.py
index 3e9dd4ac..f67f2295 100644
--- a/src/tqec/interop/collada/_geometry.py
+++ b/src/tqec/interop/collada/_geometry.py
@@ -8,7 +8,7 @@ from dataclasses import astuple, dataclass
 import numpy as np
 import numpy.typing as npt
 
-from tqec.computation.cube import YCube, ZXCube
+from tqec.computation.cube import YHalfCube, ZXCube
 from tqec.computation.pipe import PipeKind
 from tqec.utils.enums import Basis
 from tqec.utils.position import Direction3D, FloatPosition3D, SignedDirection3D
@@ -89,7 +89,7 @@ class BlockGeometries:
         self.geometries: dict[BlockKind, list[Face]] = {}
         # 6 x/z cube blocks
         self._load_zx_cube_geometries()
-        # 1 y cube block
+        # 1 y half cube block
         self._load_y_cube_geometry()
         # 6 pipe blocks without H
         self._load_pipe_without_hadamard_geometries()
@@ -132,7 +132,7 @@ class BlockGeometries:
             self.geometries[kind] = faces
 
     def _load_y_cube_geometry(self) -> None:
-        """Geometry for the y cube."""
+        """Geometry for the Y Half Cube."""
         faces: list[Face] = []
         for direction in Direction3D.all_directions():
             if direction == Direction3D.X:
@@ -146,7 +146,7 @@ class BlockGeometries:
             translation = [0.0, 0.0, 0.0]
             translation[direction.value] = 1.0 if direction != Direction3D.Z else 0.5
             faces.append(face.shift_by(*translation).with_negated_normal_direction())
-        self.geometries[YCube()] = faces
+        self.geometries[YHalfCube()] = faces
 
     def _load_pipe_without_hadamard_geometries(self) -> None:
         """Geometries for ozx, oxz, xoz, zox, xzo, zxo pipes."""
diff --git a/src/tqec/interop/collada/read_write.py b/src/tqec/interop/collada/read_write.py
index d27e29f0..a9238360 100644
--- a/src/tqec/interop/collada/read_write.py
+++ b/src/tqec/interop/collada/read_write.py
@@ -12,7 +12,7 @@ import numpy as np
 import numpy.typing as npt
 
 from tqec.computation.block_graph import BlockGraph, BlockKind, block_kind_from_str
-from tqec.computation.cube import CubeKind, Port, YCube
+from tqec.computation.cube import CubeKind, Port, YHalfCube
 from tqec.computation.pipe import PipeKind
 from tqec.utils.enums import Basis
 from tqec.utils.exceptions import TQECException
@@ -190,7 +190,7 @@ def read_block_graph_from_dae_file(
 
     # Add cubes
     for pos, cube_kind, axes_directions in parsed_cubes:
-        if isinstance(cube_kind, YCube):
+        if isinstance(cube_kind, YHalfCube):
             pos = offset_y_cube_position(pos)
         graph.add_cube(int_position_before_scale(pos), cube_kind)
     port_index = 0
diff --git a/src/tqec/interop/pyzx/synthesis/positioned.py b/src/tqec/interop/pyzx/synthesis/positioned.py
index 4b4e3fb8..3e6b83ab 100644
--- a/src/tqec/interop/pyzx/synthesis/positioned.py
+++ b/src/tqec/interop/pyzx/synthesis/positioned.py
@@ -6,7 +6,7 @@ import pyzx as zx
 from pyzx.utils import vertex_is_zx
 
 from tqec.computation.block_graph import BlockGraph
-from tqec.computation.cube import Cube, Port, YCube, ZXCube
+from tqec.computation.cube import Cube, Port, YHalfCube, ZXCube
 from tqec.computation.pipe import PipeKind
 from tqec.interop.pyzx.positioned import PositionedZX
 from tqec.interop.pyzx.utils import is_boundary, is_zx_no_phase
@@ -241,4 +241,4 @@ def _port_or_y_cube(pg: PositionedZX, v: int) -> Cube:
         else:
             label = f"P_{v}"
         return Cube(pg[v], Port(), label)
-    return Cube(pg[v], YCube())
+    return Cube(pg[v], YHalfCube())
diff --git a/src/tqec/interop/pyzx/utils.py b/src/tqec/interop/pyzx/utils.py
index d1e2ecaa..4ac80dfd 100644
--- a/src/tqec/interop/pyzx/utils.py
+++ b/src/tqec/interop/pyzx/utils.py
@@ -46,7 +46,7 @@ def cube_kind_to_zx(kind: CubeKind) -> tuple[zx.VertexType, FractionLike]:
     The conversion is as follows:
 
     - Port -> BOUNDARY spider with phase 0.
-    - YCube -> Z spider with phase 1/2.
+    - YHalfCube -> Z spider with phase 1/2.
     - ZXCube -> Z spider with phase 0 if it has only one Z basis boundary,
         otherwise X spider with phase 0.
 
@@ -62,5 +62,5 @@ def cube_kind_to_zx(kind: CubeKind) -> tuple[zx.VertexType, FractionLike]:
         return zx.VertexType.X, 0
     if isinstance(kind, Port):
         return zx.VertexType.BOUNDARY, 0
-    else:  # isinstance(kind, YCube)
+    else:  # isinstance(kind, YHalfCube)
         return zx.VertexType.Z, Fraction(1, 2)


Test patch:
diff --git a/src/tqec/interop/pyzx/utils_test.py b/src/tqec/interop/pyzx/utils_test.py
index 8e3c34a4..84c365f6 100644
--- a/src/tqec/interop/pyzx/utils_test.py
+++ b/src/tqec/interop/pyzx/utils_test.py
@@ -3,7 +3,7 @@ from fractions import Fraction
 from pyzx.graph.graph_s import GraphS
 from pyzx.utils import VertexType
 
-from tqec.computation.cube import Port, YCube, ZXCube
+from tqec.computation.cube import Port, YHalfCube, ZXCube
 from tqec.interop.pyzx.utils import cube_kind_to_zx, is_boundary, is_zx_no_phase
 
 
@@ -33,4 +33,4 @@ def test_cube_kind_to_zx() -> None:
     assert cube_kind_to_zx(ZXCube.from_str("XXZ")) == (VertexType.Z, 0)
     assert cube_kind_to_zx(ZXCube.from_str("XZX")) == (VertexType.Z, 0)
     assert cube_kind_to_zx(Port()) == (VertexType.BOUNDARY, 0)
-    assert cube_kind_to_zx(YCube()) == (VertexType.Z, Fraction(1, 2))
+    assert cube_kind_to_zx(YHalfCube()) == (VertexType.Z, Fraction(1, 2))