Skip to content

Commit

Permalink
fix: single shot classification works
Browse files Browse the repository at this point in the history
  • Loading branch information
stavros11 committed Jul 4, 2024
1 parent 574c934 commit 765a1a3
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 49 deletions.
20 changes: 15 additions & 5 deletions src/qibolab/instruments/qm/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,16 @@
"""


def operation(pulse):
"""Generate operation name in QM ``config`` for the given pulse."""
return str(hash(pulse))


def element(pulse):
"""Generate element name in QM ``config`` for the given pulse."""
return pulse.channel


def float_serial(x):
"""Convert float to string to use in config keys."""
return format(x, ".6f").rstrip("0").rstrip(".")
Expand Down Expand Up @@ -256,7 +266,7 @@ def register_element(self, qubit, pulse, time_of_flight=0, smearing=0):
element = self.register_flux_element(qubit, pulse.frequency)
return element

def register_pulse(self, pulse, operation, element, qubit):
def register_pulse(self, pulse, qubit):
"""Registers pulse, waveforms and integration weights in QM config.
Args:
Expand Down Expand Up @@ -350,7 +360,7 @@ def register_waveform(self, pulse, mode="i"):
phase = (pulse.relative_phase % (2 * np.pi)) / (2 * np.pi)
amplitude = float_serial(pulse.amplitude)
phase_str = float_serial(phase)
if isinstance(pulse.shape, Rectangular):
if isinstance(pulse.envelope, Rectangular):
serial = f"constant_wf({amplitude}, {phase_str})"
if serial not in self.waveforms:
if mode == "i":
Expand All @@ -359,10 +369,10 @@ def register_waveform(self, pulse, mode="i"):
sample = pulse.amplitude * np.sin(phase)
self.waveforms[serial] = {"type": "constant", "sample": sample}
else:
serial = f"{mode}({pulse.duration}, {amplitude}, {phase_str}, {str(pulse.shape)})"
serial = f"{hash(pulse)}_{mode}"
if serial not in self.waveforms:
samples_i = pulse.envelope_waveform_i(SAMPLING_RATE).data
samples_q = pulse.envelope_waveform_q(SAMPLING_RATE).data
samples_i = pulse.i(SAMPLING_RATE)
samples_q = pulse.q(SAMPLING_RATE)
if mode == "i":
samples = samples_i * np.cos(phase) - samples_q * np.sin(phase)
else:
Expand Down
25 changes: 14 additions & 11 deletions src/qibolab/instruments/qm/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@

from qibolab import AveragingMode
from qibolab.instruments.abstract import Controller
from qibolab.pulses import PulseType
from qibolab.pulses import Delay, PulseType
from qibolab.sweeper import Parameter
from qibolab.unrolling import Bounds

from .acquisition import create_acquisition, fetch_results
from .config import SAMPLING_RATE, QMConfig
from .config import SAMPLING_RATE, QMConfig, element, operation
from .devices import Octave, OPXplus
from .ports import OPXIQ
from .program import Parameters, element, operation
from .program import Parameters
from .sweepers import sweep

OCTAVE_ADDRESS_OFFSET = 11000
Expand Down Expand Up @@ -292,6 +292,9 @@ def register_pulses(self, qubits, sequence, options):
acquisitions = {}
parameters = defaultdict(Parameters)
for pulse in sequence:
if isinstance(pulse, Delay):
continue

qubit = qubits[pulse.qubit]
self.config.register_port(getattr(qubit, pulse.type.name.lower()).port)
if pulse.type is PulseType.READOUT:
Expand All @@ -314,17 +317,14 @@ def register_pulses(self, qubits, sequence, options):
self.config.register_pulse(qubit, qmpulse)
qmsequence.add(qmpulse)

op = operation(hash(pulse))
el = element(pulse)
if op not in self.config.pulses:
self.config.register_pulse(pulse, op, el, qubit)

op = self.config.register_pulse(pulse, qubit)
if pulse.type is PulseType.READOUT:
if op not in acquisitions:
el = element(pulse)
acquisitions[op] = create_acquisition(
op, el, options, qubit.threshold, qubit.iq_angle
op, el, pulse.qubit, options, qubit.threshold, qubit.iq_angle
)
parameters[op].acquisition = acquisitions[op]
parameters[op].acquisition = acquisitions[op]
acquisitions[op].keys.append(pulse.id)

return acquisitions, parameters
Expand Down Expand Up @@ -369,8 +369,11 @@ def sweep(self, qubits, couplers, sequence, options, *sweepers):
acquisition.download(*buffer_dims)

if self.script_file_name is not None:
script = generate_qua_script(experiment, self.config.__dict__)
for pulse in sequence:
script = script.replace(operation(pulse), str(pulse))
with open(self.script_file_name, "w") as file:
file.write(generate_qua_script(experiment, self.config.__dict__))
file.write(script)

if self.simulation_duration is not None:
result = self.simulate_program(experiment)
Expand Down
15 changes: 3 additions & 12 deletions src/qibolab/instruments/qm/program.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,7 @@
from qibolab.pulses import Delay, PulseType

from .acquisition import Acquisition


def operation(pulse):
"""Generate operation name in QM ``config`` for the given pulse."""
return str(hash(pulse))


def element(pulse):
"""Generate element name in QM ``config`` for the given pulse."""
return pulse.channel
from .config import element, operation


@dataclass
Expand All @@ -30,7 +21,7 @@ class Parameters:

def _delay(pulse):
# TODO: How to play delays on multiple elements?
qua.wait(pulse.duration, element(pulse))
qua.wait(pulse.duration // 4 + 1, element(pulse))


def _play(pulse, parameters):
Expand All @@ -51,7 +42,7 @@ def _play(pulse, parameters):
qua.reset_frame(el)


def play(self, sequence, parameters, relaxation_time=0):
def play(sequence, parameters, relaxation_time=0):
"""Part of QUA program that plays an arbitrary pulse sequence.
Should be used inside a ``program()`` context.
Expand Down
3 changes: 2 additions & 1 deletion src/qibolab/instruments/qm/sweepers.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
from qibolab.channels import check_max_offset
from qibolab.pulses import PulseType

from .program import element, operation, play
from .config import element, operation
from .program import play


def maximum_sweep_value(values, value0):
Expand Down
39 changes: 19 additions & 20 deletions src/qibolab/pulses/pulse.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"""Pulse class."""

from dataclasses import fields
from enum import Enum
from typing import Optional, Union

Expand Down Expand Up @@ -117,25 +116,25 @@ def modulated_waveforms(self, sampling_rate): # -> tuple[Waveform, Waveform]:
def __hash__(self):
"""Hash the content.
.. warning::
unhashable attributes are not taken into account, so there will be more
clashes than those usually expected with a regular hash
.. todo::
This method should be eventually dropped, and be provided automatically by
freezing the dataclass (i.e. setting ``frozen=true`` in the decorator).
However, at the moment is not possible nor desired, because it contains
unhashable attributes and because some instances are mutated inside Qibolab.
"""
return hash(
tuple(
getattr(self, f.name)
for f in fields(self)
if f.name not in ("type", "shape")
)
)
# .. warning::
# unhashable attributes are not taken into account, so there will be more
# clashes than those usually expected with a regular hash
# .. todo::
# This method should be eventually dropped, and be provided automatically by
# freezing the dataclass (i.e. setting ``frozen=true`` in the decorator).
# However, at the moment is not possible nor desired, because it contains
# unhashable attributes and because some instances are mutated inside Qibolab.
# """
# return hash(self)
# # tuple(
# # getattr(self, f.name)
# # for f in fields(self)
# # if f.name not in ("type", "shape")
# # )
# #)

def __add__(self, other):
if isinstance(other, Pulse):
Expand Down

0 comments on commit 765a1a3

Please sign in to comment.