def _build_cr_schedule(
        self,
        backend: Backend,
        flat_top_width: float,
        sigma: float,
    ) -> pulse.ScheduleBlock:
        """GaussianSquared cross resonance pulse.

        Args:
            backend: The target backend.
            flat_top_width: Total length of flat top part of the pulse in units of dt.
            sigma: Sigma of Gaussian edges in units of dt.

        Returns:
            A schedule definition for the cross resonance pulse to measure.
        """
        opt = self.experiment_options

        # Compute valid integer duration
        cr_duration = round_pulse_duration(backend=backend,
                                           duration=flat_top_width +
                                           2 * sigma * opt.risefall)

        with pulse.build(backend, default_alignment="left",
                         name="cr") as cross_resonance:

            # add cross resonance tone
            pulse.play(
                pulse.GaussianSquare(
                    duration=cr_duration,
                    amp=opt.amp,
                    sigma=sigma,
                    width=flat_top_width,
                ),
                pulse.control_channels(*self.physical_qubits)[0],
            )
            # add cancellation tone
            if not np.isclose(opt.amp_t, 0.0):
                pulse.play(
                    pulse.GaussianSquare(
                        duration=cr_duration,
                        amp=opt.amp_t,
                        sigma=sigma,
                        width=flat_top_width,
                    ),
                    pulse.drive_channel(self.physical_qubits[1]),
                )
            else:
                pulse.delay(cr_duration,
                            pulse.drive_channel(self.physical_qubits[1]))

            # place holder for empty drive channels. this is necessary due to known pulse gate bug.
            pulse.delay(cr_duration,
                        pulse.drive_channel(self.physical_qubits[0]))

        return cross_resonance
    def _schedule(self) -> Tuple[pulse.ScheduleBlock, Parameter]:
        """Create the spectroscopy schedule."""

        dt, granularity = self._dt, self._granularity

        duration = int(granularity *
                       (self.experiment_options.duration / dt // granularity))
        sigma = granularity * (self.experiment_options.sigma / dt //
                               granularity)
        width = granularity * (self.experiment_options.width / dt //
                               granularity)

        qubit = self.physical_qubits[0]

        freq_param = Parameter("frequency")

        with pulse.build(backend=self.backend,
                         name="spectroscopy") as schedule:
            pulse.shift_frequency(freq_param, pulse.MeasureChannel(qubit))
            pulse.play(
                pulse.GaussianSquare(
                    duration=duration,
                    amp=self.experiment_options.amp,
                    sigma=sigma,
                    width=width,
                ),
                pulse.MeasureChannel(qubit),
            )
            pulse.acquire(duration, qubit, pulse.MemorySlot(0))

        return schedule, freq_param
Esempio n. 3
0
    def test_assemble_parametric(self):
        """Test that parametric pulses can be assembled properly into a PulseQobj."""
        sched = pulse.Schedule(name='test_parametric')
        sched += Play(pulse.Gaussian(duration=25, sigma=4, amp=0.5j), DriveChannel(0))
        sched += Play(pulse.Drag(duration=25, amp=0.2+0.3j, sigma=7.8, beta=4), DriveChannel(1))
        sched += Play(pulse.Constant(duration=25, amp=1), DriveChannel(2))
        sched += Play(pulse.GaussianSquare(duration=150, amp=0.2,
                                           sigma=8, width=140), MeasureChannel(0)) << sched.duration
        backend = FakeOpenPulse3Q()
        backend.configuration().parametric_pulses = ['gaussian', 'drag',
                                                     'gaussian_square', 'constant']
        qobj = assemble(sched, backend)

        self.assertEqual(qobj.config.pulse_library, [])
        qobj_insts = qobj.experiments[0].instructions
        self.assertTrue(all(inst.name == 'parametric_pulse'
                            for inst in qobj_insts))
        self.assertEqual(qobj_insts[0].pulse_shape, 'gaussian')
        self.assertEqual(qobj_insts[1].pulse_shape, 'drag')
        self.assertEqual(qobj_insts[2].pulse_shape, 'constant')
        self.assertEqual(qobj_insts[3].pulse_shape, 'gaussian_square')
        self.assertDictEqual(qobj_insts[0].parameters, {'duration': 25, 'sigma': 4, 'amp': 0.5j})
        self.assertDictEqual(qobj_insts[1].parameters,
                             {'duration': 25, 'sigma': 7.8, 'amp': 0.2+0.3j, 'beta': 4})
        self.assertDictEqual(qobj_insts[2].parameters, {'duration': 25, 'amp': 1})
        self.assertDictEqual(qobj_insts[3].parameters,
                             {'duration': 150, 'sigma': 8, 'amp': 0.2, 'width': 140})
        self.assertEqual(
            qobj.to_dict()['experiments'][0]['instructions'][0]['parameters']['amp'],
            0.5j)
    def test_instruction_schedule_map_export(self):
        """Test that exporting the inst map works as planned."""

        backend = FakeBelem()

        cals = BackendCalibrations(
            backend,
            library=FixedFrequencyTransmon(basis_gates=["sx"]),
        )

        u_chan = pulse.ControlChannel(Parameter("ch0.1"))
        with pulse.build(name="cr") as cr:
            pulse.play(pulse.GaussianSquare(640, 0.5, 64, 384), u_chan)

        cals.add_schedule(cr, num_qubits=2)
        cals.update_inst_map({"cr"})

        for qubit in range(backend.configuration().num_qubits):
            self.assertTrue(cals.default_inst_map.has("sx", (qubit,)))

        # based on coupling map of Belem to keep the test robust.
        expected_pairs = [(0, 1), (1, 0), (1, 2), (2, 1), (1, 3), (3, 1), (3, 4), (4, 3)]
        coupling_map = set(tuple(pair) for pair in backend.configuration().coupling_map)

        for pair in expected_pairs:
            self.assertTrue(pair in coupling_map)
            self.assertTrue(cals.default_inst_map.has("cr", pair), pair)
    def _build_cr_schedule(self, flat_top_width: float) -> pulse.ScheduleBlock:
        """GaussianSquared cross resonance pulse.

        Args:
            flat_top_width: Total length of flat top part of the pulse in units of dt.

        Returns:
            A schedule definition for the cross resonance pulse to measure.
        """
        opt = self.experiment_options

        # Compute valid integer duration
        duration = flat_top_width + 2 * opt.sigma * opt.risefall
        valid_duration = int(self._granularity * np.floor(duration / self._granularity))

        with pulse.build(default_alignment="left", name="cr") as cross_resonance:

            # add cross resonance tone
            pulse.play(
                pulse.GaussianSquare(
                    duration=valid_duration,
                    amp=opt.amp,
                    sigma=opt.sigma,
                    width=flat_top_width,
                ),
                pulse.ControlChannel(self._cr_channel),
            )
            # add cancellation tone
            if not np.isclose(opt.amp_t, 0.0):
                pulse.play(
                    pulse.GaussianSquare(
                        duration=valid_duration,
                        amp=opt.amp_t,
                        sigma=opt.sigma,
                        width=flat_top_width,
                    ),
                    pulse.DriveChannel(self.physical_qubits[1]),
                )
            else:
                pulse.delay(valid_duration, pulse.DriveChannel(self.physical_qubits[1]))

            # place holder for empty drive channels. this is necessary due to known pulse gate bug.
            pulse.delay(valid_duration, pulse.DriveChannel(self.physical_qubits[0]))

        return cross_resonance
Esempio n. 6
0
    def test_used_in_calls(self):
        """Test that we can identify schedules by name when calls are present."""

        with pulse.build(name="xp") as xp:
            pulse.play(pulse.Gaussian(160, 0.5, 40), pulse.DriveChannel(1))

        with pulse.build(name="xp2") as xp2:
            pulse.play(pulse.Gaussian(160, 0.5, 40), pulse.DriveChannel(1))

        with pulse.build(name="call_xp") as xp_call:
            pulse.call(xp)

        with pulse.build(name="call_call_xp") as xp_call_call:
            pulse.play(pulse.Drag(160, 0.5, 40, 0.2), pulse.DriveChannel(1))
            pulse.call(xp_call)

        self.assertSetEqual(used_in_calls("xp", [xp_call]), {"call_xp"})
        self.assertSetEqual(used_in_calls("xp", [xp2]), set())
        self.assertSetEqual(used_in_calls("xp", [xp_call, xp_call_call]),
                            {"call_xp", "call_call_xp"})

        with pulse.build(name="xp") as xp:
            pulse.play(pulse.Gaussian(160, 0.5, 40), pulse.DriveChannel(2))

        cr_tone_p = pulse.GaussianSquare(640, 0.2, 64, 500)
        rotary_p = pulse.GaussianSquare(640, 0.1, 64, 500)

        cr_tone_m = pulse.GaussianSquare(640, -0.2, 64, 500)
        rotary_m = pulse.GaussianSquare(640, -0.1, 64, 500)

        with pulse.build(name="cr") as cr:
            with pulse.align_sequential():
                with pulse.align_left():
                    pulse.play(rotary_p, pulse.DriveChannel(3))  # Rotary tone
                    pulse.play(cr_tone_p, pulse.ControlChannel(2))  # CR tone.
                pulse.call(xp)
                with pulse.align_left():
                    pulse.play(rotary_m, pulse.DriveChannel(3))
                    pulse.play(cr_tone_m, pulse.ControlChannel(2))
                pulse.call(xp)

        self.assertSetEqual(used_in_calls("xp", [cr]), {"cr"})
    def test_cx_cz_case(self):
        """Test the case where the coupling map has CX and CZ on different qubits.

        We use FakeBelem which has a linear coupling map and will restrict ourselves to
        qubits 0, 1, and 2. The Cals will define a template schedule for CX and CZ. We will
        mock this with GaussianSquare and Gaussian pulses since the nature of the schedules
        is irrelevant here. The parameters for CX will only have values for qubis 0 and 1 while
        the parameters for CZ will only have values for qubis 1 and 2. We therefore will have
        a CX on qubits 0, 1 in the inst. map and a CZ on qubits 1, 2.
        """

        cals = BackendCalibrations(FakeBelem())

        sig = Parameter("σ")
        dur = Parameter("duration")
        width = Parameter("width")
        amp_cx = Parameter("amp")
        amp_cz = Parameter("amp")
        uchan = Parameter("ch1.0")

        with pulse.build(name="cx") as cx:
            pulse.play(
                pulse.GaussianSquare(duration=dur, amp=amp_cx, sigma=sig, width=width),
                pulse.ControlChannel(uchan),
            )

        with pulse.build(name="cz") as cz:
            pulse.play(
                pulse.Gaussian(duration=dur, amp=amp_cz, sigma=sig), pulse.ControlChannel(uchan)
            )

        cals.add_schedule(cx, num_qubits=2)
        cals.add_schedule(cz, num_qubits=2)

        cals.add_parameter_value(640, "duration", schedule="cx")
        cals.add_parameter_value(64, "σ", schedule="cx")
        cals.add_parameter_value(320, "width", qubits=(0, 1), schedule="cx")
        cals.add_parameter_value(320, "width", qubits=(1, 0), schedule="cx")
        cals.add_parameter_value(0.1, "amp", qubits=(0, 1), schedule="cx")
        cals.add_parameter_value(0.8, "amp", qubits=(1, 0), schedule="cx")
        cals.add_parameter_value(0.1, "amp", qubits=(2, 1), schedule="cz")
        cals.add_parameter_value(0.8, "amp", qubits=(1, 2), schedule="cz")

        # CX only defined for qubits (0, 1) and (1,0)?
        self.assertTrue(cals.default_inst_map.has("cx", (0, 1)))
        self.assertTrue(cals.default_inst_map.has("cx", (1, 0)))
        self.assertFalse(cals.default_inst_map.has("cx", (2, 1)))
        self.assertFalse(cals.default_inst_map.has("cx", (1, 2)))

        # CZ only defined for qubits (2, 1) and (1,2)?
        self.assertTrue(cals.default_inst_map.has("cz", (2, 1)))
        self.assertTrue(cals.default_inst_map.has("cz", (1, 2)))
        self.assertFalse(cals.default_inst_map.has("cz", (0, 1)))
        self.assertFalse(cals.default_inst_map.has("cz", (1, 0)))
Esempio n. 8
0
    def _spec_gate_schedule(
        self,
        backend: Optional[Backend] = None
    ) -> Tuple[pulse.ScheduleBlock, Parameter]:
        """Create the spectroscopy schedule."""
        freq_param = Parameter("frequency")
        with pulse.build(backend=backend, name="spectroscopy") as schedule:
            pulse.shift_frequency(freq_param,
                                  pulse.DriveChannel(self.physical_qubits[0]))
            pulse.play(
                pulse.GaussianSquare(
                    duration=self.experiment_options.duration,
                    amp=self.experiment_options.amp,
                    sigma=self.experiment_options.sigma,
                    width=self.experiment_options.width,
                ),
                pulse.DriveChannel(self.physical_qubits[0]),
            )
            pulse.shift_frequency(-freq_param,
                                  pulse.DriveChannel(self.physical_qubits[0]))

        return schedule, freq_param
    def test_circuit_generation_from_sec(self):
        """Test generated circuits when time unit is sec."""

        backend = CrossResonanceHamiltonianBackend()

        expr = cr_hamiltonian.CrossResonanceHamiltonian(
            qubits=(0, 1),
            flat_top_widths=[500],
            unit="ns",
            amp=0.1,
            sigma=20,
            risefall=2,
        )

        nearlest_16 = 576

        with pulse.build(default_alignment="left", name="cr") as ref_cr_sched:
            pulse.play(
                pulse.GaussianSquare(
                    nearlest_16,
                    amp=0.1,
                    sigma=20,
                    width=500,
                ),
                pulse.ControlChannel(0),
            )
            pulse.delay(nearlest_16, pulse.DriveChannel(0))
            pulse.delay(nearlest_16, pulse.DriveChannel(1))

        cr_gate = circuit.Gate("cr_gate", num_qubits=2, params=[500])
        expr_circs = expr.circuits(backend)

        x0_circ = QuantumCircuit(2, 1)
        x0_circ.append(cr_gate, [0, 1])
        x0_circ.h(1)
        x0_circ.measure(1, 0)

        x1_circ = QuantumCircuit(2, 1)
        x1_circ.x(0)
        x1_circ.append(cr_gate, [0, 1])
        x1_circ.h(1)
        x1_circ.measure(1, 0)

        y0_circ = QuantumCircuit(2, 1)
        y0_circ.append(cr_gate, [0, 1])
        y0_circ.sdg(1)
        y0_circ.h(1)
        y0_circ.measure(1, 0)

        y1_circ = QuantumCircuit(2, 1)
        y1_circ.x(0)
        y1_circ.append(cr_gate, [0, 1])
        y1_circ.sdg(1)
        y1_circ.h(1)
        y1_circ.measure(1, 0)

        z0_circ = QuantumCircuit(2, 1)
        z0_circ.append(cr_gate, [0, 1])
        z0_circ.measure(1, 0)

        z1_circ = QuantumCircuit(2, 1)
        z1_circ.x(0)
        z1_circ.append(cr_gate, [0, 1])
        z1_circ.measure(1, 0)

        ref_circs = [x0_circ, y0_circ, z0_circ, x1_circ, y1_circ, z1_circ]
        for c in ref_circs:
            c.add_calibration(cr_gate, (0, 1), ref_cr_sched)

        self.assertListEqual(expr_circs, ref_circs)
    def test_circuit_generation(self):
        """Test generated circuits."""
        backend = FakeBogota()

        # Add granularity to check duration optimization logic
        setattr(
            backend.configuration(),
            "timing_constraints",
            {"granularity": 16},
        )

        expr = cr_hamiltonian.CrossResonanceHamiltonian(
            qubits=(0, 1),
            flat_top_widths=[1000],
            amp=0.1,
            sigma=64,
            risefall=2,
        )
        expr.backend = backend

        nearlest_16 = 1248

        with pulse.build(default_alignment="left", name="cr") as ref_cr_sched:
            pulse.play(
                pulse.GaussianSquare(
                    nearlest_16,
                    amp=0.1,
                    sigma=64,
                    width=1000,
                ),
                pulse.ControlChannel(0),
            )
            pulse.delay(nearlest_16, pulse.DriveChannel(0))
            pulse.delay(nearlest_16, pulse.DriveChannel(1))

        cr_gate = cr_hamiltonian.CrossResonanceHamiltonian.CRPulseGate(
            width=1000)
        expr_circs = expr.circuits()

        x0_circ = QuantumCircuit(2, 1)
        x0_circ.append(cr_gate, [0, 1])
        x0_circ.h(1)
        x0_circ.measure(1, 0)

        x1_circ = QuantumCircuit(2, 1)
        x1_circ.x(0)
        x1_circ.append(cr_gate, [0, 1])
        x1_circ.h(1)
        x1_circ.measure(1, 0)

        y0_circ = QuantumCircuit(2, 1)
        y0_circ.append(cr_gate, [0, 1])
        y0_circ.sdg(1)
        y0_circ.h(1)
        y0_circ.measure(1, 0)

        y1_circ = QuantumCircuit(2, 1)
        y1_circ.x(0)
        y1_circ.append(cr_gate, [0, 1])
        y1_circ.sdg(1)
        y1_circ.h(1)
        y1_circ.measure(1, 0)

        z0_circ = QuantumCircuit(2, 1)
        z0_circ.append(cr_gate, [0, 1])
        z0_circ.measure(1, 0)

        z1_circ = QuantumCircuit(2, 1)
        z1_circ.x(0)
        z1_circ.append(cr_gate, [0, 1])
        z1_circ.measure(1, 0)

        ref_circs = [x0_circ, y0_circ, z0_circ, x1_circ, y1_circ, z1_circ]
        for c in ref_circs:
            c.add_calibration(cr_gate, (0, 1), ref_cr_sched)

        self.assertListEqual(expr_circs, ref_circs)