def result_collector(self, result: dl.DUInt(dl.DSize(32))) -> bool:
        """Method to receive the results and update state.

        Parameters
        ----------
        result : int
            Result from quantum HAL node.

        Returns
        -------
        bool
            Flag to signal to the circuit node to send again.

        Raises
        ------
        DeltaRuntimeExit
            Stops the deltaflow program when statistics have been aggregated
        """
        measurement = dl.lib.measurement_unpacker(result, [0])
        self._results.append(measurement)
        self._counter += 1

        if self._counter == self._repetitions:

            print("Expectation value: " +
                  f"{np.round(np.sum(self._results) / self._repetitions, 1)}")

            raise dl.DeltaRuntimeExit

        return True
示例#2
0
def get_graph():
    """Return the experiments graph `DeltaGraph` and data store instances.

    Note that the aggregator and commanger files can be provided with
    `vcd_name` which will lead to saving VCD of all signals for further
    debugging.
    """
    result_storage = dl.lib.StateSaver(int)
    cmds_storage = dl.lib.StateSaver(dl.DUInt(dl.DSize(32)))
    hal_template = dl.lib.hal_template

    with dl.DeltaGraph() as graph:
        ph_hal_result = dl.placeholder_node_factory()
        ph_commander = dl.placeholder_node_factory()

        # aggregator node of HAL results
        result_aggregator = Aggregator(
            name="result_aggregator",
            vcd_name=None).call(hal_result=ph_hal_result,
                                shot_completed=ph_commander.shot_completed)

        # commander node to send HAL instructions
        command_sender = Commander(
            name="command_sender",
            vcd_name=None).call(angle=result_aggregator.next_angle)

        hal_result = hal_template.call(hal_command=command_sender.hal_command)

        # local store for experiment results
        result_storage.save(result_aggregator.agg_result)
        cmds_storage.save(command_sender.hal_command)

        # tie up placeholders
        ph_hal_result.specify_by_node(hal_result)
        ph_commander.specify_by_node(command_sender)

        # listen for flag to stop runtime
        experiment_stopper(result_aggregator.completed)

    return graph, result_storage, cmds_storage
示例#3
0
    def migen_body(self, template):
        # creation of input/output ports
        angle = template.add_pa_in_port(
            'angle',
            dl.DOptional(dl.DRaw(dl.DUInt(dl.DSize(ANGLE_MEMORY_WIDTH))))
        )

        hal_command = template.add_pa_out_port('hal_command',
                                               dl.DUInt(dl.DSize(32)))
        shot_completed = template.add_pa_out_port('shot_completed',
                                               dl.DBool())
        # set up  internal signals
        _rotation_command = Signal(32)

        self.comb += (
            # declare input/output ports always happy to receive/transmit data
            angle.ready.eq(1)
        )

        # define finite state machine for triggering HAL command sequences
        self.submodules.commander_fsm = \
            commander_fsm = FSM(reset_state="STATE_PREPARATION")

        # waits for angle signal before kicking off HAL sequence
        commander_fsm.act(
            "STATE_PREPARATION",
            NextValue(shot_completed.valid, 0),
            If(
                angle.valid == 1,
                NextValue(
                    _rotation_command,
                    dl.lib.command_creator("RX", argument=angle.data)
                ),
                NextValue(hal_command.valid, 1),
                NextValue(
                    hal_command.data,
                    dl.lib.command_creator("STATE_PREPARATION")
                ),
                NextState("ROTATION")
            ).Else(
                NextValue(hal_command.valid, 0),
                NextState("STATE_PREPARATION")
            )
        )

        # align HAL command to rotation
        commander_fsm.act(
            "ROTATION",
            NextValue(hal_command.valid, 1),
            NextValue(hal_command.data, _rotation_command),
            NextValue(shot_completed.valid, 0),
            NextState("STATE_MEASURE")
        )

        # align HAL command to state measure
        commander_fsm.act(
            "STATE_MEASURE",
            NextValue(hal_command.valid, 1),
            NextValue(hal_command.data,
                      dl.lib.command_creator("STATE_MEASURE")),
            NextValue(shot_completed.valid, 1),
            NextValue(shot_completed.data, 1),
            NextState("STATE_PREPARATION")
        )
示例#4
0
    def migen_body(self, template):
        # creation of input/output ports
        shot_completed = template.add_pa_in_port('shot_completed',
                                              dl.DOptional(dl.DBool()))
        hal_result = template.add_pa_in_port(
            'hal_result',
            dl.DOptional(dl.DUInt(dl.DSize(32)))
        )

        agg_result = template.add_pa_out_port('agg_result',
                                              dl.DInt(dl.DSize(32)))
        # Completed is currently returning a simple 0/1 value but we make space
        # for an error code to be returned e.g. 255, 0b11111111 can be in the
        # future used to represent an error.
        completed = template.add_pa_out_port('completed', dl.DInt(dl.DSize(8)))
        next_angle = template.add_pa_out_port(
            'next_angle',
            dl.DRaw(dl.DUInt(dl.DSize(ANGLE_MEMORY_WIDTH)))
        )

        # generate a ROM of 10-bit angle values
        angles = generate_angles(RESOLUTION)

        self.specials.angle_memory = angle_memory = Memory(
            ANGLE_MEMORY_WIDTH, len(angles), init=angles, name="ANGLE_ROM"
        )
        angle_rom_port = angle_memory.get_port(write_capable=False)
        self.specials += angle_rom_port

        # set up internal signals
        _shots_counter = Signal(32)
        _high_hal_results = Signal(32)
        _reset_high_hal = Signal(1)
        _angle_rom_index = Signal(RESOLUTION+1)

        self.comb += (
            # declare input/output ports always happy to receive/transmit data
            hal_result.ready.eq(1),
            shot_completed.ready.eq(1),

            # align angle ROM address with ROM index signal
            angle_rom_port.adr.eq(_angle_rom_index),
        )

        # define finite state machine for triggering angle and result signals
        self.submodules.rabi_aggregator_fsm = \
            rabi_aggregator_fsm = FSM(reset_state="IDLE")

        # Logic to accumulate measurements
        self.sync += (
            If (_reset_high_hal == 1,
                _high_hal_results.eq(0)
            ).Else (
                If (hal_result.valid == 1,
                    If ((hal_result.data &
                        dl.lib.Masks.MEASUREMENTS.value) == 1,
                        _high_hal_results.eq(_high_hal_results + 1)
                    )
                )
            )
        )

        # waits for the experiment to be kicked off

        rabi_aggregator_fsm.act(
            "IDLE",
            NextValue(agg_result.valid, 0),
            NextValue(next_angle.valid, 0),
            NextValue(completed.valid, 0),
            NextValue(_shots_counter, 0),
            NextValue(_reset_high_hal, 1),
            NextState("DO_SHOTS")
        )

        rabi_aggregator_fsm.act(
            "DO_SHOTS",
            NextValue(agg_result.valid, 0),
            NextValue(_reset_high_hal, 0),
            If (_shots_counter == REPETITIONS,
                NextState("CHECK_IF_COMPLETE"),
                NextValue(_angle_rom_index, _angle_rom_index + 1),
                NextValue(agg_result.data, _high_hal_results),
                NextValue(agg_result.valid, 1),
                NextValue(_reset_high_hal, 1),
             ).Else (
                NextValue(next_angle.data, angle_rom_port.dat_r),
                NextValue(next_angle.valid, 1),
                NextState("WAIT_SHOT")
            )
        )

        rabi_aggregator_fsm.act(
            "WAIT_SHOT",
            NextValue(next_angle.valid, 0),
            If ((shot_completed.valid == 1) & (shot_completed.data == 1),
                NextValue(_shots_counter, _shots_counter + 1),
                NextState("DO_SHOTS"),
            )
        )

        rabi_aggregator_fsm.act(
            "CHECK_IF_COMPLETE",
            NextState("IDLE"),
            NextValue(agg_result.valid, 0),
            If(_angle_rom_index == 2 ** RESOLUTION,
                NextValue(completed.data, 1),
                NextValue(completed.valid, 1),
            )
        )
import numpy as np
import deltalanguage as dl


### ---------------------------- CONSTRUCT NODES -------------------------- ###
# One node to send circuit to HAL node, another to digest result from HAL node
@dl.Interactive([("input_params", dl.DArray(int, dl.DSize(6))),
                 ("repeat", bool)], dl.DUInt(dl.DSize(32)))
def send_gate_sequence(node):
    """Interactive node to define the circuit.
    Accepts the circuit parameters and sends the HAL commands to the HAL node.

    Parameters
    ----------
    node : PythonNode
        The node that sends the HAL command outputs.
    """

    params = node.receive("input_params")
    repeat = True

    # send each gate at least once
    while repeat:

        node.send(dl.lib.command_creator("STATE_PREPARATION"))
        node.send(dl.lib.command_creator("RX", argument=params[0]))
        node.send(dl.lib.command_creator("RZ", argument=params[1]))
        node.send(dl.lib.command_creator("RY", argument=params[2]))
        node.send(dl.lib.command_creator("R", qubit=0))
        node.send(dl.lib.command_creator("PIXY", argument=params[3]))
        node.send(dl.lib.command_creator("PIYZ", argument=params[4]))
示例#6
0
    def migen_body(self, template):

        _TIME_RES = 32
        # Node inputs
        self.time_in = template.add_pa_in_port('time_in',
                                               dl.DOptional(dl.DUInt()))

        # Node outputs
        self.time_out = template.add_pa_out_port('time_out', dl.DUInt())
        self.counter_reset = template.add_pa_out_port('counter_reset',
                                                      dl.DInt())

        # Internal signals
        self.pmt_reg = Signal(_TIME_RES)
        self.rf_reg = Signal(_TIME_RES)
        self.pmt_trig = Signal(1)
        self.rf_trig = Signal(1)

        self.submodules.fsm = FSM(reset_state="RESET_COUNTER")

        self.sync += [
            If(
                self.pmt_trig,
                self.pmt_reg.eq(self.time_in.data),
            ).Elif(self.fsm.ongoing("RESET_COUNTER"),
                   self.pmt_reg.eq(0)).Else(self.pmt_reg.eq(self.pmt_reg)),
            If(
                self.rf_trig,
                self.rf_reg.eq(self.time_in.data),
            ).Elif(self.fsm.ongoing("RESET_COUNTER"),
                   self.rf_reg.eq(0)).Else(self.rf_reg.eq(self.rf_reg))
        ]
        """FSM
        The FSM is used to control the readouts from the HPTDC chip and
        generate a time signal for the accumulator

        RESET_COUNTER
        This is the dinitial state of the FSM at the start of the experiment.
        It resets the "coarse counter" of the HPTDC chip to establish a TO
        time reference.

        WAIT_FOR_PMT
        This state holds until the PMT timestamp is available at the HPTDC
        chip readout (first data_ready sync pulse)

        WAIT_FOR_RF
        This state holds until the RMT timestamp is available at the HPTDC
        chip readout (second data_ready sync pulse)

        SEND_TIME
        In this state, the difference between t_PMT and t_RF is derived and
        sent to the accumulator.

        WAIT_ACC_LATENCY
        This state is used to wait for any delays on inter-node communication
        """

        self.fsm.act(
            "RESET_COUNTER",
            self.pmt_trig.eq(0),
            self.rf_trig.eq(0),
            self.time_in.ready.eq(1),
            self.counter_reset.data.eq(1),  # reset counters
            self.counter_reset.valid.eq(1),
            NextState("WAIT_FOR_PMT"))

        self.fsm.act(
            "WAIT_FOR_PMT", self.counter_reset.data.eq(0),
            self.time_in.ready.eq(1),
            If(self.time_in.valid, self.pmt_trig.eq(1),
               NextState("WAIT_FOR_RF")))

        self.fsm.act(
            "WAIT_FOR_RF", self.time_in.ready.eq(1),
            If(self.time_in.valid, self.rf_trig.eq(1), NextState("SEND_TIME")))

        self.fsm.act("SEND_TIME", self.time_in.ready.eq(1),
                     self.time_out.data.eq(self.rf_reg - self.pmt_reg),
                     self.time_out.valid.eq(1), NextState("WAIT_ACC_LATENCY"))

        self.fsm.act("WAIT_ACC_LATENCY",
                     If(self.time_in.valid == 0, NextState("RESET_COUNTER")))
示例#7
0
            If(self.time_in.valid, self.pmt_trig.eq(1),
               NextState("WAIT_FOR_RF")))

        self.fsm.act(
            "WAIT_FOR_RF", self.time_in.ready.eq(1),
            If(self.time_in.valid, self.rf_trig.eq(1), NextState("SEND_TIME")))

        self.fsm.act("SEND_TIME", self.time_in.ready.eq(1),
                     self.time_out.data.eq(self.rf_reg - self.pmt_reg),
                     self.time_out.valid.eq(1), NextState("WAIT_ACC_LATENCY"))

        self.fsm.act("WAIT_ACC_LATENCY",
                     If(self.time_in.valid == 0, NextState("RESET_COUNTER")))


@dl.Interactive([('time_out', dl.DUInt()), ('reset', dl.DInt())], dl.DUInt())
def testbench(node):
    """ Testbench for Timestamper interface node. Starts with random testing
    and ends with corner cases
    """
    _ITER = 10
    for i in range(_ITER):
        logging.debug(f'---Testbench iter {i}---')
        time_pmt = random.randint(0, 100)
        time_rf = random.randint(0, 100)
        do_test(node, time_pmt, time_rf)

    raise dl.DeltaRuntimeExit


def do_test(node, time_pmt, time_rf):
示例#8
0
import numpy as np
import logging

import deltalanguage as dl

AccumT, AccumC = dl.make_forked_return({
    'DAC_command': int,
    'DAC_param': int,
    'photon': int,
    'reset': int
})

TIME_RES = 30


@dl.Interactive([('new_time', dl.DUInt()), ('DAC_status', int),
                 ('DAC_voltage', int),
                 ('experiment_start', dl.DOptional(bool))], AccumT)
def accumulator(node):
    """ Accumulator Node

    This node collects times sent from the counter FPGA node and issues
    commands to the DAC controller.

    This allows the node to collect data, fit to the data and feedback to the
    experiment. The process can loop until some minimum threshold is reached,
    allowing full automation of micromotion compensation.

    Inputs:
        - new_time: Time from Counter node
        - DAC_status: DAC status from DAC node