Skip to content

Commit

Permalink
Add generalized Hadamard gate
Browse files Browse the repository at this point in the history
  • Loading branch information
madcpf committed Jul 7, 2024
1 parent 7d31d3f commit 31bf745
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 10 deletions.
2 changes: 1 addition & 1 deletion unitary/alpha/quantum_effect_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,4 @@ def test_no_qutrits(compile_to_qubits):
piece = alpha.QuantumObject("q0", 2)
board.add_object(piece)
with pytest.raises(ValueError, match="Cannot apply effect to qids"):
alpha.Superposition()(piece)
alpha.Phase()(piece)
6 changes: 3 additions & 3 deletions unitary/alpha/quantum_world.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,9 @@ def copy(self) -> "QuantumWorld":
for remap in self.qubit_remapping_dict:
new_dict = {}
for key_obj, value_obj in remap.items():
new_dict[new_world.get_object_by_name(key_obj.name)] = (
new_world.get_object_by_name(value_obj.name)
)
new_dict[
new_world.get_object_by_name(key_obj.name)
] = new_world.get_object_by_name(value_obj.name)
new_world.qubit_remapping_dict.append(new_dict)
new_world.qubit_remapping_dict_length = self.qubit_remapping_dict_length.copy()
return new_world
Expand Down
13 changes: 8 additions & 5 deletions unitary/alpha/qubit_effects.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import cirq

from unitary.alpha.quantum_effect import QuantumEffect
from unitary.alpha.qudit_gates import QuditHadamardGate


class Phase(QuantumEffect):
Expand Down Expand Up @@ -67,14 +68,16 @@ def __eq__(self, other):


class Superposition(QuantumEffect):
"""Takes a qubit in a basis state into a superposition."""

def num_dimension(self) -> Optional[int]:
return 2
"""Transforms a qubit (or qudit) in a basis state into a (equal, in terms of
absolute magnitude) superposition of all basis states.
"""

def effect(self, *objects):
for q in objects:
yield cirq.H(q.qubit)
if q.qubit.dimension == 2:
yield cirq.H(q.qubit)
else:
yield QuditHadamardGate(dimension=q.qubit.dimension)(q.qubit)

def __eq__(self, other):
return isinstance(other, Superposition) or NotImplemented
Expand Down
20 changes: 19 additions & 1 deletion unitary/alpha/qubit_effects_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,20 @@
# limitations under the License.
#

import enum
import pytest

import cirq

import unitary.alpha as alpha


class StopLight(enum.Enum):
RED = 0
YELLOW = 1
GREEN = 2


@pytest.mark.parametrize("compile_to_qubits", [False, True])
@pytest.mark.parametrize("simulator", [cirq.Simulator, alpha.SparseSimulator])
def test_flip(simulator, compile_to_qubits):
Expand Down Expand Up @@ -78,7 +85,7 @@ def test_partial_phase(simulator, compile_to_qubits):

@pytest.mark.parametrize("compile_to_qubits", [False, True])
@pytest.mark.parametrize("simulator", [cirq.Simulator, alpha.SparseSimulator])
def test_superposition(simulator, compile_to_qubits):
def test_qubit_superposition(simulator, compile_to_qubits):
board = alpha.QuantumWorld(sampler=simulator(), compile_to_qubits=compile_to_qubits)
piece = alpha.QuantumObject("t", 0)
board.add_object(piece)
Expand All @@ -87,6 +94,17 @@ def test_superposition(simulator, compile_to_qubits):
assert str(alpha.Superposition()) == "Superposition"


def test_qudit_superposition():
board = alpha.QuantumWorld(sampler=cirq.Simulator(), compile_to_qubits=False)
piece = alpha.QuantumObject("t", StopLight.GREEN)
board.add_object(piece)
alpha.Superposition()(piece)
results = board.peek([piece], count=100)
assert any(result == [StopLight.RED] for result in results)
assert any(result == [StopLight.YELLOW] for result in results)
assert any(result == [StopLight.GREEN] for result in results)


@pytest.mark.parametrize("compile_to_qubits", [False, True])
@pytest.mark.parametrize("simulator", [cirq.Simulator, alpha.SparseSimulator])
def test_move(simulator, compile_to_qubits):
Expand Down
36 changes: 36 additions & 0 deletions unitary/alpha/qudit_gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,3 +202,39 @@ def _circuit_diagram_info_(self, args):
return cirq.CircuitDiagramInfo(
wire_symbols=("iSwap", "iSwap"), exponent=self._diagram_exponent(args)
)


class QuditHadamardGate(cirq.Gate):
"""Performs a Hadamard operation on the given qudit.
This is the equivalent of a H gate for qubits. When applied to a given pure state,
the state will be transformed to a (equal, in terms of absolute magnitude) superposition of
all pure states.
Args:
dimension: dimension of the qudits, for instance,
a dimension of 3 would be a qutrit.
"""

def __init__(self, dimension: int):
self.dimension = dimension

def _qid_shape_(self):
return (self.dimension,)

def _unitary_(self):
arr = (
1.0
/ np.sqrt(self.dimension)
* np.ones((self.dimension, self.dimension), dtype=np.complex64)
)
w = np.exp(1j * 2 * np.pi / self.dimension)
# Note: this unitary matrice always has first row and first column elements equal to one,
# so we only do calculation for rest of the elements.
for i in range(1, self.dimension):
for j in range(1, self.dimension):
arr[i, j] *= w ** (i * j)
return arr

def _circuit_diagram_info_(self, args):
return cirq.CircuitDiagramInfo(
wire_symbols=("H", "H"), exponent=self._diagram_exponent(args)
)
18 changes: 18 additions & 0 deletions unitary/alpha/qudit_gates_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,9 @@ def test_control_of_0_x(dest: int):
qudit_gates.QuditISwapPowGate(3),
qudit_gates.QuditSwapPowGate(3, exponent=0.5),
qudit_gates.QuditISwapPowGate(3, exponent=0.5),
qudit_gates.QuditHadamardGate(2),
qudit_gates.QuditHadamardGate(3),
qudit_gates.QuditHadamardGate(4),
],
)
def test_gates_are_unitary(gate: cirq.Gate):
Expand Down Expand Up @@ -294,3 +297,18 @@ def test_sqrt_iswap(q0: int, q1: int):
results = sim.run(c, repetitions=1000)
assert np.all(results.measurements["m0"] == q1)
assert np.all(results.measurements["m1"] == q0)


@pytest.mark.parametrize(
"d, q0", [(2, 0), (2, 1), (3, 0), (3, 1), (3, 2), (4, 0), (4, 1), (4, 2), (4, 3)]
)
def test_hadamard(d: int, q0: int):
qutrit0 = cirq.NamedQid("q0", dimension=d)
c = cirq.Circuit()
c.append(qudit_gates.QuditPlusGate(d, addend=q0)(qutrit0))
c.append(qudit_gates.QuditHadamardGate(d)(qutrit0))
c.append(cirq.measure(qutrit0, key="m0"))
sim = cirq.Simulator()
results = sim.run(c, repetitions=1000)
for each_possible_outcome in range(d):
assert np.any(results.measurements["m0"] == each_possible_outcome)

0 comments on commit 31bf745

Please sign in to comment.