Skip to content

Commit

Permalink
Merge pull request #161 from dstrain115/no_dims_anymore
Browse files Browse the repository at this point in the history
Refactor Flip and Cycle to take any dimensions
  • Loading branch information
dstrain115 authored Nov 9, 2023
2 parents ab75eb3 + 5698536 commit 32d68be
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 73 deletions.
3 changes: 2 additions & 1 deletion unitary/alpha/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
)

from unitary.alpha.qubit_effects import (
Flip,
Move,
Phase,
PhasedMove,
Expand All @@ -42,6 +41,8 @@
)

from unitary.alpha.qudit_effects import (
Cycle,
Flip,
QuditCycle,
QuditFlip,
)
Expand Down
2 changes: 1 addition & 1 deletion unitary/alpha/quantum_effect_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,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.Flip()(piece)
alpha.Superposition()(piece)
21 changes: 5 additions & 16 deletions unitary/alpha/quantum_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@

import cirq

from unitary.alpha.qubit_effects import Flip
from unitary.alpha.qudit_effects import QuditCycle, QuditFlip
from unitary.alpha.qudit_effects import Cycle, Flip

if TYPE_CHECKING:
from unitary.alpha.quantum_world import QuantumWorld
Expand Down Expand Up @@ -54,13 +53,8 @@ def __init__(self, name: str, initial_state: Union[enum.Enum, int]):
self.qubit = cirq.NamedQid(name, dimension=self.num_states)

def initial_effect(self) -> None:
if self.num_states == 2:
if self.initial_state == 1:
Flip()(self)
else:
if self.initial_state > 0:
QuditFlip(self.num_states, 0, self.initial_state)(self)

if self.initial_state > 0:
Flip(state0=0, state1=self.initial_state)(self)
return None

def __iadd__(self, other: Union[enum.Enum, int]):
Expand All @@ -73,13 +67,8 @@ def __iadd__(self, other: Union[enum.Enum, int]):

if self.world is None:
self.initial_state = (self.initial_state + add_num) % self.num_states
else:
if self.num_states == 2:
if add_num == 1:
Flip()(self)
else:
if add_num > 0:
QuditCycle(self.num_states, add_num)(self)
elif add_num > 0:
Cycle(add_num)(self)
return self

def __neg__(self):
Expand Down
44 changes: 0 additions & 44 deletions unitary/alpha/qubit_effects.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,50 +21,6 @@
from unitary.alpha.quantum_effect import QuantumEffect


class Flip(QuantumEffect):
"""Flips a qubit in |0> to |1> and vice versa.
For a partial flip, use the `effect_fraction` argument.
These effects will be cumulative. For instance, two quarter
flips (effect_fraction=0.25) will be equivalent to a half
flip (effect_fraction=0.5).
Note that most fractions will not produce the corresponding
probabiltity distribution. For instance, a effect_fraction
of 0.25 will not produce a 25%/75% probability distribution
of outcomes.
Args:
effect_fraction: Amount of flip effect to perform.
This results in an exponentiation of the flip (X)
effect. A fraction of 1.0 corresponds to a full
flip (this is the default). A fraction of 0.5
corresponds to a half flip (square root of NOT)
and a fraction of 0.0 has no effect.
"""

def __init__(self, effect_fraction: float = 1.0):
self.effect_fraction = effect_fraction

def num_dimension(self) -> Optional[int]:
return 2

def effect(self, *objects):
for q in objects:
yield cirq.X(q.qubit) ** self.effect_fraction

def __str__(self):
if self.effect_fraction == 1:
return "Flip"
return f"Flip(effect_fraction={self.effect_fraction})"

def __eq__(self, other):
if isinstance(other, Flip):
return self.effect_fraction == other.effect_fraction
return NotImplemented


class Phase(QuantumEffect):
"""Phases a qubit from |+> to |-> and vice versa.
Expand Down
95 changes: 84 additions & 11 deletions unitary/alpha/qudit_effects.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,35 +22,108 @@
from unitary.alpha.quantum_effect import QuantumEffect


class QuditCycle(QuantumEffect):
class Cycle(QuantumEffect):
"""Cycles a qubit from |0> to |1>, |1> to |2>, etc.
Essentially adds `addend` to the state, where `addend`
is the parameter supplied at creation.
"""

def __init__(self, dimenstion, num=1):
self.dimension = dimenstion
def __init__(self, num=1):
self.addend = num

def effect(self, *objects):
for q in objects:
yield QuditPlusGate(self.dimension, addend=self.addend)(q.qubit)
if q.qubit.dimension == 2:
if self.addend % 2:
yield cirq.X(q.qubit)
else:
yield QuditPlusGate(dimension=q.qubit.dimension, addend=self.addend)(
q.qubit
)


class QuditFlip(QuantumEffect):
class QuditCycle(Cycle):
"""Equivalent to Cycle.
Exists only for backwards compatibiltity.
Will be removed in 2024.
"""

def __init__(self, dimension, num=1):
super().__init__(num)


class Flip(QuantumEffect):
"""Flips two states of a qubit, leaving all other states unchanged.
For instance, QuditFlip(3, 0, 1) is a qutrit effect
that flips |0> to |1>, |1> to |0> and leaves
|2> alone. This is also sometimes referred to as the X_0_1 gate.
For instance, Flip(state0 = 0, state1=2) is a qutrit effect
that flips |0> to |2>, |2> to |0> and leaves
|1> alone. This is also sometimes referred to as the X_0_2 gate.
For a partial flip, use the `effect_fraction` argument.
Note that this is only applied so far on qubits and not yet for
qudits.
These effects will be cumulative. For instance, two quarter
flips (effect_fraction=0.25) will be equivalent to a half
flip (effect_fraction=0.5).
Note that most fractions will not produce the corresponding
probabiltity distribution. For instance, a effect_fraction
of 0.25 will not produce a 25%/75% probability distribution
of outcomes.
Args:
effect_fraction: Amount of flip effect to perform.
This results in an exponentiation of the flip (X)
effect. A fraction of 1.0 corresponds to a full
flip (this is the default). A fraction of 0.5
corresponds to a half flip (square root of NOT)
state0: The source state to be flipped. For instance,
if state0=1, this will flip the |1> state to the
state specified in state1.
state1: The destination state to be flipped to.
"""

def __init__(self, dimenstion: int, state0: int, state1: int):
self.dimension = dimenstion
def __init__(self, effect_fraction: float = 1.0, state0: int = 0, state1: int = 1):
self.state0 = state0
self.state1 = state1
self.effect_fraction = effect_fraction

def effect(self, *objects):
for q in objects:
yield QuditXGate(self.dimension, self.state0, self.state1)(q.qubit)
if q.qubit.dimension == 2:
yield cirq.X(q.qubit) ** self.effect_fraction
else:
yield QuditXGate(
dimension=q.qubit.dimension,
source_state=self.state0,
destination_state=self.state1,
)(q.qubit)

def __str__(self):
if self.effect_fraction == 1:
return "Flip"
if self.state0 == 0 and self.state1 == 1:
return f"Flip(effect_fraction={self.effect_fraction})"
return (
f"Flip(effect_fraction={self.effect_fraction}, "
"state0={self.state0}, state1={self.state1})"
)

def __eq__(self, other):
if isinstance(other, Flip):
return self.effect_fraction == other.effect_fraction
return NotImplemented


class QuditFlip(Flip):
"""Equivalent to Flip.
Exists only for backwards compatibiltity.
Will be removed in 2024.
"""

def __init__(self, dimension: int, state0: int, state1: int):
super().__init__(state0=state0, state1=state1)

0 comments on commit 32d68be

Please sign in to comment.