def _build_schedules(
            self, basis_gates: Set[str]) -> Dict[str, pulse.ScheduleBlock]:
        """Dummy schedule building."""
        with pulse.build(name="x") as schedule:
            pulse.play(pulse.Drag(160, 0.1, 40, 0), pulse.DriveChannel(0))

        schedules = dict()
        if "x" in basis_gates:
            schedules["x"] = schedule

        return schedules
Esempio n. 2
0
    def setUp(self):
        """Setup the tests."""
        super().setUp()

        self.qubit = 1

        with pulse.build(name="x") as sched:
            pulse.play(pulse.Drag(160, Parameter("amp"), 40, 0.4),
                       pulse.DriveChannel(self.qubit))

        self.sched = sched
    def test_run_x_cal(self):
        """Test that we can transpile in the calibrations before and after update.

        If this test passes then we were successful in running a calibration experiment,
        updating a pulse parameter, having this parameter propagated to the schedules
        for use the next time the experiment is run.
        """

        # Initial pulse amplitude
        init_amp = 0.5

        amp_cal = FineXAmplitudeCal(0, self.cals, "x")

        circs = transpile(amp_cal.circuits(),
                          self.backend,
                          inst_map=amp_cal.transpile_options.inst_map)

        with pulse.build(name="x") as expected_x:
            pulse.play(pulse.Drag(160, 0.5, 40, 0), pulse.DriveChannel(0))

        with pulse.build(name="sx") as expected_sx:
            pulse.play(pulse.Drag(160, 0.25, 40, 0), pulse.DriveChannel(0))

        self.assertEqual(circs[5].calibrations["x"][((0, ), ())], expected_x)
        self.assertEqual(circs[5].calibrations["sx"][((0, ), ())], expected_sx)

        # run the calibration experiment. This should update the amp parameter of x which we test.
        exp_data = amp_cal.run(self.backend)
        d_theta = exp_data.analysis_results(1).value.value
        new_amp = init_amp * np.pi / (np.pi + d_theta)

        circs = transpile(amp_cal.circuits(),
                          self.backend,
                          inst_map=amp_cal.transpile_options.inst_map)

        x_cal = circs[5].calibrations["x"][((0, ), ())]

        # Requires allclose due to numerical precision.
        self.assertTrue(np.allclose(x_cal.blocks[0].pulse.amp, new_amp))
        self.assertFalse(np.allclose(x_cal.blocks[0].pulse.amp, init_amp))
        self.assertEqual(circs[5].calibrations["sx"][((0, ), ())], expected_sx)
    def test_inst_map_updates(self):
        """Test that updating a parameter will force an inst map update."""

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

        # Test the schedules before the update.
        for qubit in range(5):
            for gate, amp in [("x", 0.5), ("sx", 0.25)]:
                with pulse.build() as expected:
                    pulse.play(pulse.Drag(160, amp, 40, 0), pulse.DriveChannel(qubit))

                self.assertEqual(cals.default_inst_map.get(gate, qubit), expected)

        # Update the duration, this should impact all gates.
        cals.add_parameter_value(200, "duration", schedule="sx")

        # Test that all schedules now have an updated duration in the inst_map
        for qubit in range(5):
            for gate, amp in [("x", 0.5), ("sx", 0.25)]:
                with pulse.build() as expected:
                    pulse.play(pulse.Drag(200, amp, 40, 0), pulse.DriveChannel(qubit))

                self.assertEqual(cals.default_inst_map.get(gate, qubit), expected)

        # Update the amp on a single qubit, this should only update one gate in the inst_map
        cals.add_parameter_value(0.8, "amp", qubits=(4,), schedule="sx")

        # Test that all schedules now have an updated duration in the inst_map
        for qubit in range(5):
            for gate, amp in [("x", 0.5), ("sx", 0.25)]:

                if gate == "sx" and qubit == 4:
                    amp = 0.8

                with pulse.build() as expected:
                    pulse.play(pulse.Drag(200, amp, 40, 0), pulse.DriveChannel(qubit))

                self.assertEqual(cals.default_inst_map.get(gate, qubit), expected)
    def test_setup_withLibrary(self):
        """Test that we can setup with a library."""

        cals = BackendCalibrations(
            FakeArmonk(),
            library=FixedFrequencyTransmon(
                basis_gates=["x", "sx"], default_values={"duration": 320}
            ),
        )

        # Check the x gate
        with pulse.build(name="x") as expected:
            pulse.play(pulse.Drag(duration=320, amp=0.5, sigma=80, beta=0), pulse.DriveChannel(0))

        self.assertEqual(cals.get_schedule("x", (0,)), expected)

        # Check the sx gate
        with pulse.build(name="sx") as expected:
            pulse.play(pulse.Drag(duration=320, amp=0.25, sigma=80, beta=0), pulse.DriveChannel(0))

        self.assertEqual(cals.get_schedule("sx", (0,)), expected)
Esempio n. 6
0
    def test_update_cals(self):
        """Test that the calibrations are updated."""

        init_beta = 0.0

        drag_cal = FineDragCal(0, self.cals, "x", self.backend)

        transpile_opts = copy.copy(drag_cal.transpile_options.__dict__)
        transpile_opts["initial_layout"] = list(drag_cal.physical_qubits)
        circs = transpile(drag_cal.circuits(), **transpile_opts)

        with pulse.build(name="x") as expected_x:
            pulse.play(pulse.Drag(160, 0.5, 40, 0), pulse.DriveChannel(0))

        with pulse.build(name="sx") as expected_sx:
            pulse.play(pulse.Drag(160, 0.25, 40, 0), pulse.DriveChannel(0))

        self.assertEqual(circs[5].calibrations["x"][((0, ), ())], expected_x)
        self.assertEqual(circs[5].calibrations["sx"][((0, ), ())], expected_sx)

        # run the calibration experiment. This should update the beta parameter of x which we test.
        exp_data = drag_cal.run(self.backend)
        self.assertExperimentDone(exp_data)
        d_theta = exp_data.analysis_results(1).value.n
        sigma = 40
        target_angle = np.pi
        new_beta = -np.sqrt(np.pi) * d_theta * sigma / target_angle**2

        transpile_opts = copy.copy(drag_cal.transpile_options.__dict__)
        transpile_opts["initial_layout"] = list(drag_cal.physical_qubits)
        circs = transpile(drag_cal.circuits(), **transpile_opts)

        x_cal = circs[5].calibrations["x"][((0, ), ())]

        # Requires allclose due to numerical precision.
        self.assertTrue(np.allclose(x_cal.blocks[0].pulse.beta, new_beta))
        self.assertFalse(np.allclose(x_cal.blocks[0].pulse.beta, init_beta))
        self.assertEqual(circs[5].calibrations["sx"][((0, ), ())], expected_sx)
Esempio n. 7
0
    def setUp(self):
        """Setup the tests"""
        super().setUp()

        library = FixedFrequencyTransmon()

        self.backend = FakeArmonk()
        self.cals = Calibrations.from_backend(self.backend, library)

        # Add some pulses on the 1-2 transition.
        d0 = pulse.DriveChannel(0)
        with pulse.build(name="x12") as x12:
            with pulse.frequency_offset(-300e6, d0):
                pulse.play(pulse.Drag(160, Parameter("amp"), 40, 0.0), d0)

        with pulse.build(name="sx12") as sx12:
            with pulse.frequency_offset(-300e6, d0):
                pulse.play(pulse.Drag(160, Parameter("amp"), 40, 0.0), d0)

        self.cals.add_schedule(x12, 0)
        self.cals.add_schedule(sx12, 0)
        self.cals.add_parameter_value(0.4, "amp", 0, "x12")
        self.cals.add_parameter_value(0.2, "amp", 0, "sx12")
Esempio n. 8
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.ConstantPulse(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_circuits(self):
        """Test the quantum circuits."""
        test_amps = [-0.5, 0, 0.5]
        rabi = RoughXSXAmplitudeCal(0, self.cals, amplitudes=test_amps)

        circs = transpile(rabi.circuits(), self.backend, inst_map=rabi.transpile_options.inst_map)

        for circ, amp in zip(circs, test_amps):
            self.assertEqual(circ.count_ops()["Rabi"], 1)

            d0 = pulse.DriveChannel(0)
            with pulse.build(name="x") as expected_x:
                pulse.play(pulse.Drag(160, amp, 40, 0), d0)

            self.assertEqual(circ.calibrations["Rabi"][((0,), (amp,))], expected_x)
Esempio n. 10
0
    def test_assemble_parametric_unsupported(self):
        """Test that parametric pulses are translated to Waveform if they're not supported
        by the backend during assemble time.
        """
        sched = pulse.Schedule(name='test_parametric_to_sample_pulse')
        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))

        backend = FakeOpenPulse3Q()
        backend.configuration().parametric_pulses = ['something_extra']

        qobj = assemble(sched, backend)

        self.assertNotEqual(qobj.config.pulse_library, [])
        qobj_insts = qobj.experiments[0].instructions
        self.assertFalse(hasattr(qobj_insts[0], 'pulse_shape'))
Esempio n. 11
0
    def _single_qubit_schedule(
        name: str,
        dur: Parameter,
        amp: Parameter,
        sigma: Parameter,
        beta: Parameter,
    ) -> ScheduleBlock:
        """Build a single qubit pulse."""

        chan = pulse.DriveChannel(Parameter("ch0"))

        with pulse.build(name=name) as sched:
            pulse.play(
                pulse.Drag(duration=dur, amp=amp, sigma=sigma, beta=beta),
                chan)

        return sched
    def _single_qubit_schedule(
        name: str,
        dur: Parameter,
        amp: Parameter,
        sigma: Parameter,
        beta: Optional[Parameter] = None,
    ) -> ScheduleBlock:
        """Build a single qubit pulse."""

        chan = pulse.DriveChannel(Parameter("ch0"))

        if beta is not None:
            with pulse.build(name=name) as sched:
                pulse.play(pulse.Drag(duration=dur, amp=amp, sigma=sigma, beta=beta), chan)
        else:
            with pulse.build(name=name) as sched:
                pulse.play(pulse.Gaussian(duration=dur, amp=amp, sigma=sigma), chan)

        return sched
Esempio n. 13
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"})
Esempio n. 14
0
    def circuits(self,
                 backend: Optional[Backend] = None) -> List[QuantumCircuit]:
        """Create the circuits for the Drag calibration.

        Args:
            backend: A backend object.

        Returns:
            circuits: The circuits that will run the Drag calibration.

        Raises:
            CalibrationError:
                - If the beta parameters in the xp and xm pulses are not the same.
                - If either the xp or xm pulse do not have at least one Drag pulse.
                - If the number of different repetition series is not three.
        """
        schedule = self.experiment_options.schedule

        if schedule is None:
            beta = Parameter("β")
            with pulse.build(backend=backend, name="drag") as schedule:
                pulse.play(
                    pulse.Drag(
                        duration=self.experiment_options.duration,
                        amp=self.experiment_options.amp,
                        sigma=self.experiment_options.sigma,
                        beta=beta,
                    ),
                    pulse.DriveChannel(self._physical_qubits[0]),
                )

        if len(schedule.parameters) != 1:
            raise CalibrationError(
                "The schedule for Drag calibration must have one free parameter."
                f"Found {len(schedule.parameters)}.")

        beta = next(iter(schedule.parameters))

        drag_gate = Gate(name=schedule.name, num_qubits=1, params=[beta])

        reps = self.experiment_options.reps
        if len(reps) != 3:
            raise CalibrationError(
                f"{self.__class__.__name__} must use exactly three repetition numbers. "
                f"Received {reps} with length {len(reps)} != 3.")

        circuits = []

        for idx, rep in enumerate(reps):
            circuit = QuantumCircuit(1)
            for _ in range(rep):
                circuit.append(drag_gate, (0, ))
                circuit.rz(np.pi, 0)
                circuit.append(drag_gate, (0, ))
                circuit.rz(np.pi, 0)

            circuit.measure_active()

            circuit.add_calibration(schedule.name,
                                    self.physical_qubits,
                                    schedule,
                                    params=[beta])

            for beta_val in self.experiment_options.betas:
                beta_val = np.round(beta_val, decimals=6)

                assigned_circuit = circuit.assign_parameters({beta: beta_val},
                                                             inplace=False)

                assigned_circuit.metadata = {
                    "experiment_type": self._type,
                    "qubits": self.physical_qubits,
                    "xval": beta_val,
                    "series": idx,
                }

                circuits.append(assigned_circuit)

        return circuits
Esempio n. 15
0
 def test_drag_roundtrip_serializable(self):
     """Test round trip JSON serialization"""
     with pulse.build(name="xp") as sched:
         pulse.play(pulse.Drag(160, 0.5, 40, Parameter("β")), pulse.DriveChannel(0))
     exp = RoughDrag(0, backend=self.backend, schedule=sched)
     self.assertRoundTripSerializable(exp, self.json_equiv)
Esempio n. 16
0
    def test_fine_drag(self):
        """Test that we can update from a fine DRAG experiment."""

        d_theta = 0.03  # rotation error per single gate.
        backend = FineDragTestBackend(error=d_theta)

        qubit = 0
        test_tol = 0.005
        beta = Parameter("β")
        chan = Parameter("ch0")

        with pulse.build(backend=backend, name="xp") as x_plus:
            pulse.play(
                pulse.Drag(duration=160, amp=0.208519, sigma=40, beta=beta),
                pulse.DriveChannel(chan),
            )

        # Setup the calibrations
        cals = BackendCalibrations(backend)

        cals.add_schedule(x_plus, num_qubits=1)

        old_beta = 0.2
        cals.add_parameter_value(old_beta, "β", qubit, x_plus)
        cals.inst_map_add("xp", (qubit, ))

        # Check that the inst_map has the default beta
        beta_val = cals.default_inst_map.get("xp",
                                             (qubit, )).blocks[0].pulse.beta
        self.assertEqual(beta_val, old_beta)

        # Run a Drag calibration experiment.
        drag = FineXDrag(qubit)
        drag.set_experiment_options(schedule=cals.get_schedule("xp", qubit))
        drag.set_transpile_options(basis_gates=["rz", "xp", "ry"])
        exp_data = drag.run(backend).block_for_results()

        result = exp_data.analysis_results(1)

        # Test the fit for good measure.
        self.assertTrue(abs(result.value.value - d_theta) < test_tol)
        self.assertEqual(result.quality, "good")

        # Check schedules pre-update
        expected = x_plus.assign_parameters({
            beta: 0.2,
            chan: qubit
        },
                                            inplace=False)
        self.assertEqual(cals.get_schedule("xp", qubit), expected)

        FineDragUpdater.update(cals, exp_data, parameter="β", schedule="xp")

        # Check schedules post-update. Here the FineDragTestBackend has a leakage
        # of 0.03 per gate so the DRAG update rule
        # -np.sqrt(np.pi) * d_theta * sigma / target_angle ** 2 should give a new beta of
        # 0.2 - np.sqrt(np.pi) * 0.03 * 40 / (np.pi ** 2)
        new_beta = old_beta - np.sqrt(
            np.pi) * result.value.value * 40 / np.pi**2
        expected = x_plus.assign_parameters({
            beta: new_beta,
            chan: qubit
        },
                                            inplace=False)
        self.assertEqual(cals.get_schedule("xp", qubit), expected)

        # Check the inst map post update
        beta_val = cals.default_inst_map.get("xp",
                                             (qubit, )).blocks[0].pulse.beta
        self.assertTrue(np.allclose(beta_val, new_beta))
Esempio n. 17
0
    def test_drag(self):
        """Test calibrations update from drag."""

        backend = DragBackend(gate_name="xp")
        beta = Parameter("β")
        qubit = 1
        test_tol = 0.02
        chan = Parameter("ch0")

        with pulse.build(backend=backend, name="xp") as x_plus:
            pulse.play(
                pulse.Drag(duration=160, amp=0.208519, sigma=40, beta=beta),
                pulse.DriveChannel(chan),
            )

        # Setup the calibrations
        cals = BackendCalibrations(backend)

        cals.add_schedule(x_plus, num_qubits=1)

        cals.add_parameter_value(0.2, "β", qubit, x_plus)
        cals.inst_map_add("xp", (qubit, ))

        # Check that the inst_map has the default beta
        beta_val = cals.default_inst_map.get("xp",
                                             (qubit, )).blocks[0].pulse.beta
        self.assertEqual(beta_val, 0.2)

        # Run a Drag calibration experiment.
        drag = DragCal(qubit)
        drag.set_experiment_options(schedule=cals.get_schedule(
            "xp", qubit, assign_params={"β": beta}), )

        exp_data = drag.run(backend)
        exp_data.block_for_results()
        result = exp_data.analysis_results(1)

        # Test the fit for good measure.
        self.assertTrue(
            abs(result.value.value - backend.ideal_beta) < test_tol)
        self.assertEqual(result.quality, "good")

        # Check schedules pre-update
        expected = x_plus.assign_parameters({
            beta: 0.2,
            chan: 1
        },
                                            inplace=False)
        self.assertEqual(cals.get_schedule("xp", qubit), expected)

        Drag.update(cals, exp_data, parameter="β", schedule="xp")

        # Check schedules post-update
        expected = x_plus.assign_parameters({
            beta: result.value.value,
            chan: 1
        },
                                            inplace=False)
        self.assertEqual(cals.get_schedule("xp", qubit), expected)

        # Check the inst map post update
        beta_val = cals.default_inst_map.get("xp",
                                             (qubit, )).blocks[0].pulse.beta
        self.assertTrue(np.allclose(beta_val, result.value.value))