Skip to content

Commit

Permalink
Mostly working 1Q gates
Browse files Browse the repository at this point in the history
  • Loading branch information
nulinspiratie committed Jun 18, 2024
1 parent f6604d3 commit 9dd59b6
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 6 deletions.
13 changes: 9 additions & 4 deletions quam/components/gates/single_qubit_gates.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from abc import ABC, abstractmethod
from typing import Dict
from typing import Dict, Union
from dataclasses import field
from quam.core import quam_dataclass, QuamComponent
from quam.components.pulses import Pulse
Expand Down Expand Up @@ -30,11 +30,16 @@ def execute(self, *args, **kwargs): # TODO Accomodate differing arguments

@quam_dataclass
class SinglePulseGate(SingleQubitGate):
"""Single-qubit gate for a qubit consisting of a single pulse"""
"""Single-qubit gate for a qubit consisting of a single pulse
pulse_label: str
Args:
pulse (Union[Pulse, str]): The pulse to be played
"""

pulse: Union[Pulse, str]

def execute(self, amplitude_scale=None, duration=None):
self.qubit.xy.play( # TODO Introduce a "play" method to the qubit
self.qubit.play_pulse(
self.pulse_label, amplitude_scale=amplitude_scale, duration=duration
)
1 change: 0 additions & 1 deletion quam/components/gates/two_qubit_gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ def execute(self, amplitude_scale=None):
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)
Expand Down
84 changes: 83 additions & 1 deletion quam/components/qubit.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from typing import Dict, Any
from dataclasses import field

from quam.components.channels import Channel
from quam.core import quam_dataclass, QuamComponent
from .gates.single_qubit_gates import SingleQubitGate
from .gates.two_qubit_gates import TwoQubitGate
Expand All @@ -14,6 +15,10 @@ class Qubit(QuamComponent):
id: str
gates: Dict[str, SingleQubitGate] = field(default_factory=dict)

@property
def name(self):
return self.id if isinstance(self.id, str) else f"q{self.id}"

def __matmul__(self, other):
"""Allows access to qubit pairs using the '@' operator, e.g. (q1 @ q2)"""
if not isinstance(other, Qubit):
Expand All @@ -40,4 +45,81 @@ def __matmul__(self, other):
raise ValueError(
"Qubit pair not found: qubit_control={self.name}, "
"qubit_target={other.name}"
)
)

def play_pulse(
self,
pulse_name: str,
amplitude_scale: Union[float, AmpValuesType] = None,
duration: QuaNumberType = None,
condition: QuaExpressionType = None,
chirp: ChirpType = None,
truncate: QuaNumberType = None,
timestamp_stream: StreamType = None,
continue_chirp: bool = False,
target: str = "",
validate: bool = True,
):
"""Play a pulse on this channel.
Args:
pulse_name (str): The name of the pulse to play. Should be registered in
`self.operations`.
amplitude_scale (float, _PulseAmp): Amplitude scale of the pulse.
Can be either a float, or qua.amp(float).
duration (int): Duration of the pulse in units of the clock cycle (4ns).
If not provided, the default pulse duration will be used. It is possible
to dynamically change the duration of both constant and arbitrary
pulses. Arbitrary pulses can only be stretched, not compressed.
chirp (Union[(list[int], str), (int, str)]): Allows to perform
piecewise linear sweep of the element's intermediate
frequency in time. Input should be a tuple, with the 1st
element being a list of rates and the second should be a
string with the units. The units can be either: 'Hz/nsec',
'mHz/nsec', 'uHz/nsec', 'pHz/nsec' or 'GHz/sec', 'MHz/sec',
'KHz/sec', 'Hz/sec', 'mHz/sec'.
truncate (Union[int, QUA variable of type int]): Allows playing
only part of the pulse, truncating the end. If provided,
will play only up to the given time in units of the clock
cycle (4ns).
condition (A logical expression to evaluate.): Will play analog
pulse only if the condition's value is true. Any digital
pulses associated with the operation will always play.
timestamp_stream (Union[str, _ResultSource]): (Supported from
QOP 2.2) Adding a `timestamp_stream` argument will save the
time at which the operation occurred to a stream. If the
`timestamp_stream` is a string ``label``, then the timestamp
handle can be retrieved with
`qm._results.JobResults.get` with the same ``label``.
validate (bool): If True (default), validate that the pulse is registered
in Channel.operations
Note:
The `element` argument from `qm.qua.play()`is not needed, as it is
automatically set to `self.name`.
"""
attrs = self.get_attrs(follow_references=False, include_defaults=True)
channels = {key: val for key, val in attrs.items() if isinstance(val, Channel)}
for channel in channels.values():
if pulse_name not in channel.operations:
continue

channel.play(
pulse_name=pulse_name,
amplitude_scale=amplitude_scale,
duration=duration,
condition=condition,
chirp=chirp,
truncate=truncate,
timestamp_stream=timestamp_stream,
continue_chirp=continue_chirp,
target=target,
validate=validate,
)
break
else:
raise ValueError(
f"Pulse name not found in any channel operations of qubit: "
f"{pulse_name=}\nqubit={self.name}"
)

0 comments on commit 9dd59b6

Please sign in to comment.