diff --git a/unitary/alpha/qudit_gates.py b/unitary/alpha/qudit_gates.py index fa0a7035..11a45e39 100644 --- a/unitary/alpha/qudit_gates.py +++ b/unitary/alpha/qudit_gates.py @@ -14,6 +14,17 @@ # import numpy as np import cirq +from unitary.alpha.qudit_state_transform import qudit_to_qubit_unitary + + +def _nearest_power_of_two_ceiling(qudit_dim: int) -> int: + """Returns the smallest power of two greater than or equal to qudit_dim.""" + if qudit_dim == 0: + return 0 + result = 1 + while result < qudit_dim: + result = result << 1 + return result class QuditXGate(cirq.Gate): @@ -36,7 +47,7 @@ def __init__( self.destination_state = destination_state def _qid_shape_(self): - return (self.dimension,) + return (_nearest_power_of_two_ceiling(self.dimension),) def _unitary_(self): arr = np.zeros((self.dimension, self.dimension)) @@ -45,7 +56,7 @@ def _unitary_(self): for i in range(self.dimension): if i != self.source_state and i != self.destination_state: arr[i, i] = 1 - return arr + return qudit_to_qubit_unitary(self.dimension, 1, arr) def _circuit_diagram_info_(self, args): return f"X({self.source_state}_{self.destination_state})" @@ -63,13 +74,13 @@ def __init__(self, dimension: int, addend: int = 1): self.addend = addend def _qid_shape_(self): - return (self.dimension,) + return (_nearest_power_of_two_ceiling(self.dimension),) def _unitary_(self): arr = np.zeros((self.dimension, self.dimension)) for i in range(self.dimension): arr[(i + self.addend) % self.dimension, i] = 1 - return arr + return qudit_to_qubit_unitary(self.dimension, 1, arr) def _circuit_diagram_info_(self, args): return f"[+{self.addend}]" @@ -99,7 +110,7 @@ def __init__(self, dimension: int, control_state: int = 1, state: int = 1): self.control_state = control_state def _qid_shape_(self): - return (self.dimension, self.dimension) + return (_nearest_power_of_two_ceiling(self.dimension), _nearest_power_of_two_ceiling(self.dimension)) def _unitary_(self): size = self.dimension * self.dimension @@ -111,7 +122,7 @@ def _unitary_(self): for y in range(self.dimension): if x != self.control_state or (y != self.state and y != 0): arr[x * self.dimension + y, x * self.dimension + y] = 1 - return arr + return qudit_to_qubit_unitary(self.dimension, 2, arr) class QuditSwapPowGate(cirq.Gate): @@ -134,7 +145,7 @@ def __init__(self, dimension: int, exponent: float = 1): self.exponent = exponent def _qid_shape_(self): - return (self.dimension, self.dimension) + return (_nearest_power_of_two_ceiling(self.dimension), _nearest_power_of_two_ceiling(self.dimension)) def _unitary_(self): size = self.dimension * self.dimension @@ -149,7 +160,7 @@ def _unitary_(self): diag = g * np.cos(np.pi * self.exponent / 2) arr[x * self.dimension + y, y * self.dimension + x] = coeff arr[x * self.dimension + y, x * self.dimension + y] = diag - return arr + return qudit_to_qubit_unitary(self.dimension, 2, arr) def _circuit_diagram_info_(self, args): if not args.use_unicode_characters: @@ -181,7 +192,7 @@ def __init__(self, dimension: int, exponent: float = 1): self.exponent = exponent def _qid_shape_(self): - return (self.dimension, self.dimension) + return (_nearest_power_of_two_ceiling(self.dimension), _nearest_power_of_two_ceiling(self.dimension)) def _unitary_(self): size = self.dimension * self.dimension @@ -196,7 +207,7 @@ def _unitary_(self): arr[x * self.dimension + y, y * self.dimension + x] = coeff arr[x * self.dimension + y, x * self.dimension + y] = diag - return arr + return qudit_to_qubit_unitary(self.dimension, 2, arr) def _circuit_diagram_info_(self, args): return cirq.CircuitDiagramInfo( diff --git a/unitary/examples/tictactoe/enums.py b/unitary/examples/tictactoe/enums.py index 8bbd9ac8..c0ac3f30 100644 --- a/unitary/examples/tictactoe/enums.py +++ b/unitary/examples/tictactoe/enums.py @@ -19,6 +19,7 @@ class TicTacSquare(enum.Enum): EMPTY = 0 X = 1 O = 2 + PADDING = 3 class TicTacResult(enum.Enum): diff --git a/unitary/examples/tictactoe/tic_tac_split.py b/unitary/examples/tictactoe/tic_tac_split.py index 897437e9..dc894660 100644 --- a/unitary/examples/tictactoe/tic_tac_split.py +++ b/unitary/examples/tictactoe/tic_tac_split.py @@ -20,6 +20,7 @@ from unitary.alpha import QuantumEffect, QuantumObject from unitary.alpha.qudit_gates import QuditXGate, QuditISwapPowGate from unitary.examples.tictactoe.enums import TicTacSquare, TicTacRules +from unitary.alpha.qudit_state_transform import qudit_to_qubit_unitary class QuditSplitGate(cirq.Gate): @@ -40,7 +41,7 @@ def __init__(self, square: TicTacSquare): raise ValueError("Not a valid square: {self.square}") def _qid_shape_(self): - return (3, 3) + return (4, 4) def _unitary_(self): arr = np.zeros((9, 9), dtype=np.complex64) @@ -59,7 +60,7 @@ def _unitary_(self): arr[3, 1] = coeff arr[3, 3] = diag arr[1, 1] = diag - return arr + return qudit_to_qubit_unitary(3, 2, arr) def _circuit_diagram_info_(self, args): if not args.use_unicode_characters: @@ -81,7 +82,7 @@ def __init__(self, tic_tac_type: TicTacSquare, rules: TicTacRules): self.rules = rules def num_dimension(self) -> Optional[int]: - return 3 + return 4 def num_objects(self) -> Optional[int]: return 2 diff --git a/unitary/examples/tictactoe/tic_tac_toe.py b/unitary/examples/tictactoe/tic_tac_toe.py index db22fdfc..a8b2a61b 100644 --- a/unitary/examples/tictactoe/tic_tac_toe.py +++ b/unitary/examples/tictactoe/tic_tac_toe.py @@ -228,6 +228,8 @@ def print(self) -> str: output = "\n" for row in range(3): for mark in TicTacSquare: + if mark == TicTacSquare.PADDING: + continue output += " " for col in range(3): idx = row * 3 + col