예제 #1
0
    def test_schedule_with_multiple_parameters_under_same_name(self):
        """Test getting schedule with parameters that have the same name."""
        param1 = Parameter('param')
        param2 = Parameter('param')
        param3 = Parameter('param')

        target_sched = Schedule()
        target_sched.insert(0,
                            ShiftPhase(param1, DriveChannel(0)),
                            inplace=True)
        target_sched.insert(10,
                            ShiftPhase(param2, DriveChannel(0)),
                            inplace=True)
        target_sched.insert(20,
                            ShiftPhase(param3, DriveChannel(0)),
                            inplace=True)

        inst_map = InstructionScheduleMap()
        inst_map.add('target_sched', (0, ), target_sched)

        ref_sched = Schedule()
        ref_sched.insert(0, ShiftPhase(1.23, DriveChannel(0)), inplace=True)
        ref_sched.insert(10, ShiftPhase(1.23, DriveChannel(0)), inplace=True)
        ref_sched.insert(20, ShiftPhase(1.23, DriveChannel(0)), inplace=True)

        test_sched = inst_map.get('target_sched', (0, ), param=1.23)

        for test_inst, ref_inst in zip(test_sched.instructions,
                                       ref_sched.instructions):
            self.assertEqual(test_inst[0], ref_inst[0])
            self.assertAlmostEqual(test_inst[1], ref_inst[1])
    def test_partially_bound_callable(self):
        """Test register partial function."""
        import functools

        def callable_schedule(par_b, par_a):
            sched = Schedule()
            sched.insert(10, Play(Constant(10, par_b), DriveChannel(0)), inplace=True)
            sched.insert(20, Play(Constant(10, par_a), DriveChannel(0)), inplace=True)
            return sched

        ref_sched = Schedule()
        ref_sched.insert(10, Play(Constant(10, 0.1), DriveChannel(0)), inplace=True)
        ref_sched.insert(20, Play(Constant(10, 0.2), DriveChannel(0)), inplace=True)

        inst_map = InstructionScheduleMap()

        def test_callable_sched1(par_b):
            return callable_schedule(par_b, 0.2)

        inst_map.add("my_gate1", (0,), test_callable_sched1, ["par_b"])
        ret_sched = inst_map.get("my_gate1", (0,), par_b=0.1)
        self.assertEqual(ret_sched, ref_sched)

        # bind partially
        test_callable_sched2 = functools.partial(callable_schedule, par_a=0.2)

        inst_map.add("my_gate2", (0,), test_callable_sched2, ["par_b"])
        ret_sched = inst_map.get("my_gate2", (0,), par_b=0.1)
        self.assertEqual(ret_sched, ref_sched)
예제 #3
0
    def test_pass_alive_with_dcx_ish(self):
        """Test if the pass is not terminated by error with direct CX input."""
        cx_sched = Schedule()
        # Fake direct cr
        cx_sched.insert(0,
                        Play(GaussianSquare(800, 0.2, 64, 544),
                             ControlChannel(1)),
                        inplace=True)
        # Fake direct compensation tone
        # Compensation tone doesn't have dedicated pulse class.
        # So it's reported as a waveform now.
        compensation_tone = Waveform(0.1 * np.ones(800, dtype=complex))
        cx_sched.insert(0,
                        Play(compensation_tone, DriveChannel(0)),
                        inplace=True)

        inst_map = InstructionScheduleMap()
        inst_map.add("cx", (1, 0), schedule=cx_sched)

        theta = pi / 3
        rzx_qc = circuit.QuantumCircuit(2)
        rzx_qc.rzx(theta, 1, 0)

        pass_ = RZXCalibrationBuilder(instruction_schedule_map=inst_map)
        with self.assertWarns(UserWarning):
            # User warning that says q0 q1 is invalid
            cal_qc = PassManager(pass_).run(rzx_qc)
        self.assertEqual(cal_qc, rzx_qc)
    def test_schedule_with_non_alphanumeric_ordering(self):
        """Test adding and getting schedule with non obvious parameter ordering."""
        theta = Parameter("theta")
        phi = Parameter("phi")
        lamb = Parameter("lambda")

        target_sched = Schedule()
        target_sched.insert(0, ShiftPhase(theta, DriveChannel(0)), inplace=True)
        target_sched.insert(10, ShiftPhase(phi, DriveChannel(0)), inplace=True)
        target_sched.insert(20, ShiftPhase(lamb, DriveChannel(0)), inplace=True)

        inst_map = InstructionScheduleMap()
        inst_map.add("target_sched", (0,), target_sched, arguments=["theta", "phi", "lambda"])

        ref_sched = Schedule()
        ref_sched.insert(0, ShiftPhase(0, DriveChannel(0)), inplace=True)
        ref_sched.insert(10, ShiftPhase(1, DriveChannel(0)), inplace=True)
        ref_sched.insert(20, ShiftPhase(2, DriveChannel(0)), inplace=True)

        # if parameter is alphanumerical ordering this maps to
        # theta -> 2
        # phi -> 1
        # lamb -> 0
        # however non alphanumerical ordering is specified in add method thus mapping should be
        # theta -> 0
        # phi -> 1
        # lamb -> 2
        test_sched = inst_map.get("target_sched", (0,), 0, 1, 2)

        for test_inst, ref_inst in zip(test_sched.instructions, ref_sched.instructions):
            self.assertEqual(test_inst[0], ref_inst[0])
            self.assertEqual(test_inst[1], ref_inst[1])
 def callable_schedule(par_b, par_a):
     sched = Schedule()
     sched.insert(10,
                  Play(Constant(10, par_b), DriveChannel(0)),
                  inplace=True)
     sched.insert(20,
                  Play(Constant(10, par_a), DriveChannel(0)),
                  inplace=True)
     return sched
    def test_binding_too_many_parameters(self):
        """Test getting schedule with too many parameter binding."""
        param = Parameter('param')

        target_sched = Schedule()
        target_sched.insert(0, ShiftPhase(param, DriveChannel(0)), inplace=True)

        inst_map = InstructionScheduleMap()
        inst_map.add('target_sched', (0,), target_sched)

        with self.assertRaises(PulseError):
            inst_map.get('target_sched', (0,), 0, 1, 2, 3)
    def test_binding_unassigned_parameters(self):
        """Test getting schedule with unassigned parameter binding."""
        param = Parameter("param")

        target_sched = Schedule()
        target_sched.insert(0, ShiftPhase(param, DriveChannel(0)), inplace=True)

        inst_map = InstructionScheduleMap()
        inst_map.add("target_sched", (0,), target_sched)

        with self.assertRaises(PulseError):
            inst_map.get("target_sched", (0,), P0=0)
예제 #8
0
    def test_get_schedule_with_unbound_parameter(self):
        """Test get schedule with partial binding."""
        param1 = Parameter('param1')
        param2 = Parameter('param2')

        target_sched = Schedule()
        target_sched.insert(0,
                            ShiftPhase(param1, DriveChannel(0)),
                            inplace=True)
        target_sched.insert(10,
                            ShiftPhase(param2, DriveChannel(0)),
                            inplace=True)

        inst_map = InstructionScheduleMap()
        inst_map.add('target_sched', (0, ), target_sched)

        ref_sched = Schedule()
        ref_sched.insert(0, ShiftPhase(param1, DriveChannel(0)), inplace=True)
        ref_sched.insert(10, ShiftPhase(1.23, DriveChannel(0)), inplace=True)

        test_sched = inst_map.get('target_sched', (0, ), param2=1.23)

        for test_inst, ref_inst in zip(test_sched.instructions,
                                       ref_sched.instructions):
            self.assertEqual(test_inst[0], ref_inst[0])
            self.assertAlmostEqual(test_inst[1], ref_inst[1])
예제 #9
0
    def test_pulse_to_signals(self):
        """Generic test."""

        sched = Schedule(name="Schedule")
        sched += Play(Drag(duration=20, amp=0.5, sigma=4, beta=0.5),
                      DriveChannel(0))
        sched += ShiftPhase(1.0, DriveChannel(0))
        sched += Play(Drag(duration=20, amp=0.5, sigma=4, beta=0.5),
                      DriveChannel(0))
        sched += ShiftFrequency(0.5, DriveChannel(0))
        sched += Play(
            GaussianSquare(duration=200, amp=0.3, sigma=4, width=150),
            DriveChannel(0))

        test_gaussian = GaussianSquare(duration=200,
                                       amp=0.3,
                                       sigma=4,
                                       width=150)
        sched = sched.insert(0, Play(test_gaussian, DriveChannel(1)))

        converter = InstructionToSignals(dt=1, carriers=None)

        signals = converter.get_signals(sched)

        self.assertEqual(len(signals), 2)
        self.assertTrue(isinstance(signals[0], PiecewiseConstant))
        self.assertTrue(isinstance(signals[0], PiecewiseConstant))

        samples = test_gaussian.get_waveform().samples
        self.assertTrue(
            np.allclose(signals[1].samples[0:len(samples)], samples))
예제 #10
0
    def test_assemble_meas_map(self):
        """Test assembling a single schedule, no lo config."""
        schedule = Schedule(name='fake_experiment')
        schedule = schedule.insert(
            5, Acquire(5, AcquireChannel(0), MemorySlot(0)))
        schedule = schedule.insert(
            5, Acquire(5, AcquireChannel(1), MemorySlot(1)))

        qobj = assemble(schedule,
                        qubit_lo_freq=self.default_qubit_lo_freq,
                        meas_lo_freq=self.default_meas_lo_freq,
                        meas_map=[[0], [1]])
        validate_qobj_against_schema(qobj)

        with self.assertRaises(QiskitError):
            assemble(schedule,
                     qubit_lo_freq=self.default_qubit_lo_freq,
                     meas_lo_freq=self.default_meas_lo_freq,
                     meas_map=[[0, 1, 2]])
예제 #11
0
def pad(schedule: Schedule,
        channels: Optional[Iterable[Channel]] = None,
        until: Optional[int] = None) -> Schedule:
    """Pad the input ``Schedule`` with ``Delay`` s on all unoccupied timeslots until ``until``
    if it is provided, otherwise until ``schedule.duration``.

    Args:
        schedule: Schedule to pad.
        channels: Channels to pad. Defaults to all channels in ``schedule`` if not provided.
                  If the supplied channel is not a member of ``schedule``, it will be added.
        until: Time to pad until. Defaults to ``schedule.duration`` if not provided.

    Returns:
        The padded schedule.
    """
    until = until or schedule.duration
    channels = channels or schedule.channels

    for channel in channels:
        if channel not in schedule.channels:
            schedule |= Delay(until, channel)
            continue

        curr_time = 0
        # TODO: Replace with method of getting instructions on a channel
        for interval in schedule.timeslots[channel]:
            if curr_time >= until:
                break
            if interval[0] != curr_time:
                end_time = min(interval[0], until)
                schedule = schedule.insert(
                    curr_time, Delay(end_time - curr_time, channel))
            curr_time = interval[1]
        if curr_time < until:
            schedule = schedule.insert(curr_time,
                                       Delay(until - curr_time, channel))

    return schedule
    def get_calibration(self, params: List, qubits: List) -> Schedule:
        """
        Args:
            params: Parameters of the RZXGate(theta). I.e. params[0] is theta.
            qubits: List of qubits for which to get the schedules. The first qubit is
                the control and the second is the target.

        Returns:
            schedule: The calibration schedule for the RZXGate(theta).

        Raises:
            QiskitError: if the control and target qubits cannot be identified or the backend
                does not support cx between the qubits.
        """
        theta = params[0]
        q1, q2 = qubits[0], qubits[1]

        if not self._inst_map.has('cx', qubits):
            raise QiskitError(
                'This transpilation pass requires the backend to support cx '
                'between qubits %i and %i.' % (q1, q2))

        cx_sched = self._inst_map.get('cx', qubits=(q1, q2))
        rzx_theta = Schedule(name='rzx(%.3f)' % theta)

        if theta == 0.0:
            return rzx_theta

        crs, comp_tones, shift_phases = [], [], []
        control, target = None, None

        for time, inst in cx_sched.instructions:

            if isinstance(inst, ShiftPhase) and time == 0:
                shift_phases.append(ShiftPhase(-theta, inst.channel))

            # Identify the CR pulses.
            if isinstance(inst, Play) and not isinstance(inst, ShiftPhase):
                if isinstance(inst.channel, ControlChannel):
                    crs.append((time, inst))

            # Identify the compensation tones.
            if isinstance(inst.channel,
                          DriveChannel) and not isinstance(inst, ShiftPhase):
                if isinstance(inst.pulse, GaussianSquare):
                    comp_tones.append((time, inst))
                    target = inst.channel.index
                    control = q1 if target == q2 else q2

        if control is None:
            raise QiskitError('Control qubit is None.')
        if target is None:
            raise QiskitError('Target qubit is None.')

        echo_x = self._inst_map.get('x', qubits=control)

        # Build the schedule
        for inst in shift_phases:
            rzx_theta = rzx_theta.insert(0, inst)

        # Stretch/compress the CR gates and compensation tones
        cr1 = self.rescale_cr_inst(crs[0][1], theta)
        cr2 = self.rescale_cr_inst(crs[1][1], theta)

        if len(comp_tones) == 0:
            comp1, comp2 = None, None
        elif len(comp_tones) == 2:
            comp1 = self.rescale_cr_inst(comp_tones[0][1], theta)
            comp2 = self.rescale_cr_inst(comp_tones[1][1], theta)
        else:
            raise QiskitError(
                'CX must have either 0 or 2 rotary tones between qubits %i and %i '
                'but %i were found.' % (control, target, len(comp_tones)))

        # Build the schedule for the RZXGate
        rzx_theta = rzx_theta.insert(0, cr1)

        if comp1 is not None:
            rzx_theta = rzx_theta.insert(0, comp1)

        rzx_theta = rzx_theta.insert(comp1.duration, echo_x)
        time = comp1.duration + echo_x.duration
        rzx_theta = rzx_theta.insert(time, cr2)

        if comp2 is not None:
            rzx_theta = rzx_theta.insert(time, comp2)

        time = 2 * comp1.duration + echo_x.duration
        rzx_theta = rzx_theta.insert(time, echo_x)

        # Reverse direction of the ZX with Hadamard gates
        if control == qubits[0]:
            return rzx_theta
        else:
            rzc = self._inst_map.get('rz', [control], np.pi / 2)
            sxc = self._inst_map.get('sx', [control])
            rzt = self._inst_map.get('rz', [target], np.pi / 2)
            sxt = self._inst_map.get('sx', [target])
            h_sched = Schedule(name='hadamards')
            h_sched = h_sched.insert(0, rzc)
            h_sched = h_sched.insert(0, sxc)
            h_sched = h_sched.insert(sxc.duration, rzc)
            h_sched = h_sched.insert(0, rzt)
            h_sched = h_sched.insert(0, sxt)
            h_sched = h_sched.insert(sxc.duration, rzt)
            rzx_theta = h_sched.append(rzx_theta)
            return rzx_theta.append(h_sched)
예제 #13
0
    def get_calibration(self, params: List, qubits: List) -> Schedule:
        """
        Builds the calibration schedule for the RZXGate(theta) without echos.
        Args:
            params: Parameters of the RZXGate(theta). I.e. params[0] is theta.
            qubits: List of qubits for which to get the schedules. The first qubit is
                the control and the second is the target.
        Returns:
            schedule: The calibration schedule for the RZXGate(theta).
        Raises:
            QiskitError: If the control and target qubits cannot be identified, or the backend
                does not support a cx gate between the qubits, or the backend does not natively
                support the specified direction of the cx.
        """
        theta = params[0]
        q1, q2 = qubits[0], qubits[1]

        if not self._inst_map.has("cx", qubits):
            raise QiskitError(
                "This transpilation pass requires the backend to support cx "
                "between qubits %i and %i." % (q1, q2))

        cx_sched = self._inst_map.get("cx", qubits=(q1, q2))
        rzx_theta = Schedule(name="rzx(%.3f)" % theta)

        if theta == 0.0:
            return rzx_theta

        control, target = None, None

        for _, inst in cx_sched.instructions:
            # Identify the compensation tones.
            if isinstance(inst.channel, DriveChannel) and isinstance(
                    inst, Play):
                if isinstance(inst.pulse, GaussianSquare):
                    target = inst.channel.index
                    control = q1 if target == q2 else q2

        if control is None:
            raise QiskitError("Control qubit is None.")
        if target is None:
            raise QiskitError("Target qubit is None.")

        if control != qubits[0]:
            raise QiskitError(
                "RZXCalibrationBuilderNoEcho only supports hardware-native RZX gates."
            )

        # Get the filtered Schedule instructions for the CR gates and compensation tones.
        crs = cx_sched.filter(*[self._filter_control]).instructions
        rotaries = cx_sched.filter(*[self._filter_drive]).instructions

        # Stretch/compress the CR gates and compensation tones.
        cr = self.rescale_cr_inst(crs[0][1], 2 * theta)
        rot = self.rescale_cr_inst(rotaries[0][1], 2 * theta)

        # Build the schedule for the RZXGate without the echos.
        rzx_theta = rzx_theta.insert(0, cr)
        rzx_theta = rzx_theta.insert(0, rot)
        rzx_theta = rzx_theta.insert(0,
                                     Delay(cr.duration, DriveChannel(control)))

        return rzx_theta
예제 #14
0
    def get_calibration(self, node_op: CircuitInst,
                        qubits: List) -> Union[Schedule, ScheduleBlock]:
        """Builds the calibration schedule for the RZXGate(theta) without echos.

        Args:
            node_op: Instruction of the RZXGate(theta). I.e. params[0] is theta.
            qubits: List of qubits for which to get the schedules. The first qubit is
                the control and the second is the target.

        Returns:
            schedule: The calibration schedule for the RZXGate(theta).

        Raises:
            QiskitError: If the control and target qubits cannot be identified,
                or the backend does not natively support the specified direction of the cx.
            CalibrationNotAvailable: RZX schedule cannot be built for input node.
        """
        theta = node_op.params[0]

        rzx_theta = Schedule(name="rzx(%.3f)" % theta)
        rzx_theta.metadata["publisher"] = CalibrationPublisher.QISKIT

        if np.isclose(theta, 0.0):
            return rzx_theta

        cx_sched = self._inst_map.get("cx", qubits=qubits)
        cal_type, cr_tones, comp_tones = _check_calibration_type(cx_sched)

        if cal_type != CXCalType.ECR:
            if self._verbose:
                warnings.warn(
                    f"CX instruction for qubits {qubits} is likely {cal_type.value} sequence. "
                    "Pulse stretch for this calibration is not currently implemented. "
                    "RZX schedule is not generated for this qubit pair.",
                    UserWarning,
                )
            raise CalibrationNotAvailable

        if len(comp_tones) == 0:
            raise QiskitError(
                f"{repr(cx_sched)} has no target compensation tones. "
                "Native CR direction cannot be determined.")

        # Determine native direction, assuming only single drive channel per qubit.
        # This guarantees channel and qubit index equality.
        is_native = comp_tones[0].channel.index == qubits[1]

        stretched_cr_tone = self.rescale_cr_inst(cr_tones[0], 2 * theta)
        stretched_comp_tone = self.rescale_cr_inst(comp_tones[0], 2 * theta)

        if is_native:
            # Placeholder to make pulse gate work
            delay = Delay(stretched_cr_tone.duration, DriveChannel(qubits[0]))

            # This doesn't remove unwanted instruction such as ZI
            # These terms are eliminated along with other gates around the pulse gate.
            rzx_theta = rzx_theta.insert(0, stretched_cr_tone, inplace=True)
            rzx_theta = rzx_theta.insert(0, stretched_comp_tone, inplace=True)
            rzx_theta = rzx_theta.insert(0, delay, inplace=True)

            return rzx_theta

        raise QiskitError(
            "RZXCalibrationBuilderNoEcho only supports hardware-native RZX gates."
        )
예제 #15
0
    def get_calibration(self, node_op: CircuitInst,
                        qubits: List) -> Union[Schedule, ScheduleBlock]:
        """Builds the calibration schedule for the RZXGate(theta) with echos.

        Args:
            node_op: Instruction of the RZXGate(theta). I.e. params[0] is theta.
            qubits: List of qubits for which to get the schedules. The first qubit is
                the control and the second is the target.

        Returns:
            schedule: The calibration schedule for the RZXGate(theta).

        Raises:
            QiskitError: If the control and target qubits cannot be identified.
            CalibrationNotAvailable: RZX schedule cannot be built for input node.
        """
        theta = node_op.params[0]

        rzx_theta = Schedule(name="rzx(%.3f)" % theta)
        rzx_theta.metadata["publisher"] = CalibrationPublisher.QISKIT

        if np.isclose(theta, 0.0):
            return rzx_theta

        cx_sched = self._inst_map.get("cx", qubits=qubits)
        cal_type, cr_tones, comp_tones = _check_calibration_type(cx_sched)

        if cal_type != CXCalType.ECR:
            if self._verbose:
                warnings.warn(
                    f"CX instruction for qubits {qubits} is likely {cal_type.value} sequence. "
                    "Pulse stretch for this calibration is not currently implemented. "
                    "RZX schedule is not generated for this qubit pair.",
                    UserWarning,
                )
            raise CalibrationNotAvailable

        if len(comp_tones) == 0:
            raise QiskitError(
                f"{repr(cx_sched)} has no target compensation tones. "
                "Native CR direction cannot be determined.")

        # Determine native direction, assuming only single drive channel per qubit.
        # This guarantees channel and qubit index equality.
        is_native = comp_tones[0].channel.index == qubits[1]

        stretched_cr_tones = list(
            map(lambda p: self.rescale_cr_inst(p, theta), cr_tones))
        stretched_comp_tones = list(
            map(lambda p: self.rescale_cr_inst(p, theta), comp_tones))

        if is_native:
            xgate = self._inst_map.get("x", qubits[0])

            for cr, comp in zip(stretched_cr_tones, stretched_comp_tones):
                current_dur = rzx_theta.duration
                rzx_theta.insert(current_dur, cr, inplace=True)
                rzx_theta.insert(current_dur, comp, inplace=True)
                rzx_theta.append(xgate, inplace=True)

        else:
            # Add hadamard gate to flip
            xgate = self._inst_map.get("x", qubits[1])
            szc = self._inst_map.get("rz", qubits[1], np.pi / 2)
            sxc = self._inst_map.get("sx", qubits[1])
            szt = self._inst_map.get("rz", qubits[0], np.pi / 2)
            sxt = self._inst_map.get("sx", qubits[0])

            # Hadamard to control
            rzx_theta.insert(0, szc, inplace=True)
            rzx_theta.insert(0, sxc, inplace=True)
            rzx_theta.insert(sxc.duration, szc, inplace=True)

            # Hadamard to target
            rzx_theta.insert(0, szt, inplace=True)
            rzx_theta.insert(0, sxt, inplace=True)
            rzx_theta.insert(sxt.duration, szt, inplace=True)

            for cr, comp in zip(stretched_cr_tones, stretched_comp_tones):
                current_dur = rzx_theta.duration
                rzx_theta.insert(current_dur, cr, inplace=True)
                rzx_theta.insert(current_dur, comp, inplace=True)
                rzx_theta.append(xgate, inplace=True)

            current_dur = rzx_theta.duration

            # Hadamard to control
            rzx_theta.insert(current_dur, szc, inplace=True)
            rzx_theta.insert(current_dur, sxc, inplace=True)
            rzx_theta.insert(current_dur + sxc.duration, szc, inplace=True)

            # Hadamard to target
            rzx_theta.insert(current_dur, szt, inplace=True)
            rzx_theta.insert(current_dur, sxt, inplace=True)
            rzx_theta.insert(current_dur + sxt.duration, szt, inplace=True)

        return rzx_theta
예제 #16
0
    def get_calibration(self, node_op: CircuitInst,
                        qubits: List) -> Union[Schedule, ScheduleBlock]:
        """Builds the calibration schedule for the RZXGate(theta) with echos.

        Args:
            node_op: Instruction of the RZXGate(theta). I.e. params[0] is theta.
            qubits: List of qubits for which to get the schedules. The first qubit is
                the control and the second is the target.

        Returns:
            schedule: The calibration schedule for the RZXGate(theta).

        Raises:
            QiskitError: if the control and target qubits cannot be identified or the backend
                does not support cx between the qubits.
        """
        theta = node_op.params[0]
        q1, q2 = qubits[0], qubits[1]

        if not self._inst_map.has("cx", qubits):
            raise QiskitError(
                "This transpilation pass requires the backend to support cx "
                "between qubits %i and %i." % (q1, q2))

        cx_sched = self._inst_map.get("cx", qubits=(q1, q2))
        rzx_theta = Schedule(name="rzx(%.3f)" % theta)
        rzx_theta.metadata["publisher"] = CalibrationPublisher.QISKIT

        if theta == 0.0:
            return rzx_theta

        crs, comp_tones = [], []
        control, target = None, None

        for time, inst in cx_sched.instructions:

            # Identify the CR pulses.
            if isinstance(inst, Play) and not isinstance(inst, ShiftPhase):
                if isinstance(inst.channel, ControlChannel):
                    crs.append((time, inst))

            # Identify the compensation tones.
            if isinstance(inst.channel,
                          DriveChannel) and not isinstance(inst, ShiftPhase):
                if isinstance(inst.pulse, GaussianSquare):
                    comp_tones.append((time, inst))
                    target = inst.channel.index
                    control = q1 if target == q2 else q2

        if control is None:
            raise QiskitError("Control qubit is None.")
        if target is None:
            raise QiskitError("Target qubit is None.")

        echo_x = self._inst_map.get("x", qubits=control)

        # Build the schedule

        # Stretch/compress the CR gates and compensation tones
        cr1 = self.rescale_cr_inst(crs[0][1], theta)
        cr2 = self.rescale_cr_inst(crs[1][1], theta)

        if len(comp_tones) == 0:
            comp1, comp2 = None, None
        elif len(comp_tones) == 2:
            comp1 = self.rescale_cr_inst(comp_tones[0][1], theta)
            comp2 = self.rescale_cr_inst(comp_tones[1][1], theta)
        else:
            raise QiskitError(
                "CX must have either 0 or 2 rotary tones between qubits %i and %i "
                "but %i were found." % (control, target, len(comp_tones)))

        # Build the schedule for the RZXGate
        rzx_theta = rzx_theta.insert(0, cr1)

        if comp1 is not None:
            rzx_theta = rzx_theta.insert(0, comp1)

        rzx_theta = rzx_theta.insert(comp1.duration, echo_x)
        time = comp1.duration + echo_x.duration
        rzx_theta = rzx_theta.insert(time, cr2)

        if comp2 is not None:
            rzx_theta = rzx_theta.insert(time, comp2)

        time = 2 * comp1.duration + echo_x.duration
        rzx_theta = rzx_theta.insert(time, echo_x)

        # Reverse direction of the ZX with Hadamard gates
        if control == qubits[0]:
            return rzx_theta
        else:
            rzc = self._inst_map.get("rz", [control], np.pi / 2)
            sxc = self._inst_map.get("sx", [control])
            rzt = self._inst_map.get("rz", [target], np.pi / 2)
            sxt = self._inst_map.get("sx", [target])
            h_sched = Schedule(name="hadamards")
            h_sched = h_sched.insert(0, rzc)
            h_sched = h_sched.insert(0, sxc)
            h_sched = h_sched.insert(sxc.duration, rzc)
            h_sched = h_sched.insert(0, rzt)
            h_sched = h_sched.insert(0, sxt)
            h_sched = h_sched.insert(sxc.duration, rzt)
            rzx_theta = h_sched.append(rzx_theta)
            return rzx_theta.append(h_sched)
예제 #17
0
def measure(qubits: List[int],
            backend=None,
            inst_map: Optional[InstructionScheduleMap] = None,
            meas_map: Optional[Union[List[List[int]], Dict[int,
                                                           List[int]]]] = None,
            qubit_mem_slots: Optional[Dict[int, int]] = None,
            measure_name: str = 'measure') -> Schedule:
    """
    Return a schedule which measures the requested qubits according to the given
    instruction mapping and measure map, or by using the defaults provided by the backend.

    By default, the measurement results for each qubit are trivially mapped to the qubit
    index. This behavior is overridden by qubit_mem_slots. For instance, to measure
    qubit 0 into MemorySlot(1), qubit_mem_slots can be provided as {0: 1}.

    Args:
        qubits: List of qubits to be measured.
        backend (BaseBackend): A backend instance, which contains hardware-specific data
            required for scheduling.
        inst_map: Mapping of circuit operations to pulse schedules. If None, defaults to the
                  ``instruction_schedule_map`` of ``backend``.
        meas_map: List of sets of qubits that must be measured together. If None, defaults to
                  the ``meas_map`` of ``backend``.
        qubit_mem_slots: Mapping of measured qubit index to classical bit index.
        measure_name: Name of the measurement schedule.

    Returns:
        A measurement schedule corresponding to the inputs provided.

    Raises:
        PulseError: If both ``inst_map`` or ``meas_map``, and ``backend`` is None.
    """
    schedule = Schedule(
        name="Default measurement schedule for qubits {}".format(qubits))
    try:
        inst_map = inst_map or backend.defaults().instruction_schedule_map
        meas_map = meas_map or backend.configuration().meas_map
    except AttributeError:
        raise PulseError(
            'inst_map or meas_map, and backend cannot be None simultaneously')
    if isinstance(meas_map, List):
        meas_map = format_meas_map(meas_map)

    measure_groups = set()
    for qubit in qubits:
        measure_groups.add(tuple(meas_map[qubit]))
    for measure_group_qubits in measure_groups:
        if qubit_mem_slots is not None:
            unused_mem_slots = set(measure_group_qubits) - set(
                qubit_mem_slots.values())
        try:
            default_sched = inst_map.get(measure_name, measure_group_qubits)
        except PulseError:
            raise PulseError(
                "We could not find a default measurement schedule called '{}'. "
                "Please provide another name using the 'measure_name' keyword "
                "argument. For assistance, the instructions which are defined are: "
                "{}".format(measure_name, inst_map.instructions))

        for time, inst in default_sched.instructions:
            if qubit_mem_slots and isinstance(inst,
                                              (Acquire, AcquireInstruction)):
                if inst.channel.index in qubit_mem_slots:
                    mem_slot = MemorySlot(qubit_mem_slots[inst.channel.index])
                else:
                    mem_slot = MemorySlot(unused_mem_slots.pop())
                schedule = schedule.insert(
                    time,
                    Acquire(inst.duration, inst.channel, mem_slot=mem_slot))
            elif qubit_mem_slots is None and isinstance(
                    inst, (Acquire, AcquireInstruction)):
                schedule = schedule.insert(time, inst)
            # Measurement pulses should only be added if its qubit was measured by the user
            elif inst.channels[0].index in qubits:
                schedule = schedule.insert(time, inst)

    return schedule
예제 #18
0
    def parameterized_cx(self,
                         theta: float,
                         q1: int,
                         q2: int,
                         phase_delta: float = 0.,
                         amp_increase: float = 0.):
        """
        Args:
            theta: Rotation angle of the parameterized CZ gate.
            q1: First qubit.
            q2: Second qubit.
            phase_delta: Multiplies the CR90_u pulses samples by np.exp(1.0j*phase_delta).
            amp_increase: Multiplies the amplitude of the samples by (1. + amp_increase).
        """
        cx_sched = self._inst_map.get('cx', qubits=(q1, q2))
        zx_theta = Schedule(name=self.name(theta, phase_delta))

        crs = []
        comp_tones = []
        shift_phases = []
        control = None
        target = None

        for time, inst in cx_sched.instructions:

            if isinstance(inst, ShiftPhase) and time == 0:
                shift_phases.append(ShiftPhase(-theta, inst.channel))

            # Identify the CR pulses.
            if isinstance(inst, Play) and not isinstance(inst, ShiftPhase):
                if isinstance(inst.channel, ControlChannel):
                    crs.append((time, inst))

            # Identify the compensation tones.
            if isinstance(inst.channel,
                          DriveChannel) and not isinstance(inst, ShiftPhase):
                if isinstance(inst.pulse, GaussianSquare):
                    comp_tones.append((time, inst))
                    target = inst.channel.index
                    control = q1 if target == q2 else q2

        if control is None:
            raise QiskitError('Control qubit is None.')
        if target is None:
            raise QiskitError('Target qubit is None.')

        # ntb - we do not care about the initial x90p
        # Id the X90 gate at the start of the schedule and rescale it.
        #x90 = cx_sched.filter(time_ranges=[(0, crs[0][0])], channels=[DriveChannel(target)]).instructions
        #if len(x90) != 1:
        #    raise QiskitError('Could not extract initial X90.')
        #x90 = x90[0][1]

        echo_x = self._inst_map.get('x', qubits=control)

        # Build the schedule
        for inst in shift_phases:
            zx_theta = zx_theta.insert(0, inst)

        # ntb - these pre-pulses we do not want
        #zx_theta = zx_theta.insert(0, self._inst_map.get('x', qubits=control))
        #zx_theta = zx_theta.insert(0, self.rescale_amp(x90, theta))

        # Stretch/compress the CR gates and compensation tones
        cr1 = self.rescale_cr_inst(crs[0][1], theta)
        cr2 = self.rescale_cr_inst(crs[1][1], theta)
        comp1 = self.rescale_cr_inst(comp_tones[0][1], theta)
        comp2 = self.rescale_cr_inst(comp_tones[1][1], theta)

        if theta != 0.0:
            zx_theta = zx_theta.insert(0, cr1)
            zx_theta = zx_theta.insert(0, comp1)
            zx_theta = zx_theta.insert(0 + comp1.duration, echo_x)
            time = comp1.duration + echo_x.duration
            zx_theta = zx_theta.insert(time, cr2)
            zx_theta = zx_theta.insert(time, comp2)
        else:
            zx_theta = zx_theta.insert(0, echo_x)

        return zx_theta