Skip to content

Commit

Permalink
add qubit ipementations
Browse files Browse the repository at this point in the history
  • Loading branch information
nulinspiratie committed Jun 17, 2024
1 parent 035cea1 commit f6604d3
Show file tree
Hide file tree
Showing 4 changed files with 202 additions and 0 deletions.
40 changes: 40 additions & 0 deletions quam/components/gates/single_qubit_gates.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from abc import ABC, abstractmethod
from typing import Dict
from dataclasses import field
from quam.core import quam_dataclass, QuamComponent
from quam.components.pulses import Pulse


@quam_dataclass
class SingleQubitGate(QuamComponent, ABC):
@property
def qubit(self):
from ..qubit import Qubit

if isinstance(self.parent, Qubit):
return self.parent
elif hasattr(self.parent, "parent") and isinstance(self.parent.parent, Qubit):
return self.parent.parent
else:
raise AttributeError(
"SingleQubitGate is not attached to a qubit. 1Q_gate: {self}"
)

def __call__(self):
self.execute()

@abstractmethod
def execute(self, *args, **kwargs): # TODO Accomodate differing arguments
pass


@quam_dataclass
class SinglePulseGate(SingleQubitGate):
"""Single-qubit gate for a qubit consisting of a single pulse"""

pulse_label: str

def execute(self, amplitude_scale=None, duration=None):
self.qubit.xy.play( # TODO Introduce a "play" method to the qubit
self.pulse_label, amplitude_scale=amplitude_scale, duration=duration
)
106 changes: 106 additions & 0 deletions quam/components/gates/two_qubit_gates.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
from abc import ABC, abstractmethod
from typing import Dict
from dataclasses import field
from copy import copy

from quam.components.pulses import Pulse
from quam.core import quam_dataclass, QuamComponent
from quam.utils import string_reference as str_ref


__all__ = ["TwoQubitGate", "CZGate"]


@quam_dataclass
class TwoQubitGate(QuamComponent, ABC):
@property
def qubit_pair(self):
from ..qubit_pair import QubitPair

if isinstance(self.parent, QubitPair):
return self.parent
elif hasattr(self.parent, "parent") and isinstance(
self.parent.parent, QubitPair
):
return self.parent.parent
else:
raise AttributeError(
"TwoQubitGate is not attached to a QubitPair. 2Q_gate: {self}"
)

@property
def qubit_control(self):
return self.qubit_pair.qubit_control

@property
def qubit_target(self):
return self.qubit_pair.qubit_target

def __call__(self):
self.execute()


@quam_dataclass
class CZGate(TwoQubitGate):
"""CZ Operation for a qubit pair"""

# Pulses will be added to qubit elements
# The reason we don't add "flux_to_q1" directly to q1.z is because it is part of
# the CZ operation, i.e. it is only applied as part of a CZ operation

flux_pulse_control: Pulse

phase_shift_control: float = 0.0
phase_shift_target: float = 0.0

@property
def gate_label(self) -> str:
try:
return self.parent.get_attr_name(self)
except AttributeError:
return "CZ"

@property
def flux_pulse_control_label(self) -> str:
if self.flux_pulse_control.id is not None:
pulse_label = self.flux_pulse_control.id
else:
pulse_label = "flux_pulse_control"

return f"{self.gate_label}{str_ref.DELIMITER}{pulse_label}"

def execute(self, amplitude_scale=None):
self.qubit_control.z.play(
self.flux_pulse_control_label,
validate=False,
amplitude_scale=amplitude_scale,
)
self.qubit_control.align(self.qubit_target)


self.qubit_control.xy.frame_rotation(self.phase_shift_control)
self.qubit_target.xy.frame_rotation(self.phase_shift_target)
self.qubit_control.align(self.qubit_target)

@property
def config_settings(self):
return {"after": [self.qubit_control.z]}

def apply_to_config(self, config: dict) -> None:
pulse = copy(self.flux_pulse_control)
pulse.id = self.flux_pulse_control_label
pulse.parent = None # Reset parent so it can be attached to new parent
pulse.parent = self.qubit_control.z

if self.flux_pulse_control_label in self.qubit_control.z.operations:
raise ValueError(
"Pulse name already exists in pulse operations. "
f"Channel: {self.qubit_control.z.get_reference()}, "
f"Pulse: {self.flux_pulse_control.get_reference()}, "
f"Pulse name: {self.flux_pulse_control_label}"
)

pulse.apply_to_config(config)

element_config = config["elements"][self.qubit_control.z.name]
element_config["operations"][self.flux_pulse_control_label] = pulse.pulse_name
43 changes: 43 additions & 0 deletions quam/components/qubit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from typing import Dict, Any
from dataclasses import field

from quam.core import quam_dataclass, QuamComponent
from .gates.single_qubit_gates import SingleQubitGate
from .gates.two_qubit_gates import TwoQubitGate


__all__ = ["Qubit"]


@quam_dataclass
class Qubit(QuamComponent):
id: str
gates: Dict[str, SingleQubitGate] = field(default_factory=dict)

def __matmul__(self, other):
"""Allows access to qubit pairs using the '@' operator, e.g. (q1 @ q2)"""
if not isinstance(other, Qubit):
raise ValueError(
"Cannot create a qubit pair (q1 @ q2) with a non-qubit object, "
f"where q1={self} and q2={other}"
)

if self is other:
raise ValueError(
"Cannot create a qubit pair with same qubit (q1 @ q1), where q1={self}"
)

if not hasattr(self._root, "qubit_pairs"):
raise AttributeError(
"Qubit pairs not found in the root component. "
"Please add a 'qubit_pairs' attribute to the root component."
)

for qubit_pair in self._root.qubit_pairs:
if qubit_pair.qubit_control is self and qubit_pair.qubit_target is other:
return qubit_pair
else:
raise ValueError(
"Qubit pair not found: qubit_control={self.name}, "
"qubit_target={other.name}"
)
13 changes: 13 additions & 0 deletions quam/components/qubit_pair.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from typing import Dict
from dataclasses import field

from quam.core import quam_dataclass, QuamComponent
from quam.components.qubit import Qubit
from quam.components.gates.two_qubit_gates import TwoQubitGate


@quam_dataclass
class QubitPair(QuamComponent):
qubit_control: Qubit # TODO Discuss alternatives to "control" and "target"
qubit_target: Qubit
gates: Dict[str, TwoQubitGate] = field(default_factory=dict)

0 comments on commit f6604d3

Please sign in to comment.