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))
def test_parametric_pulses_with_no_duplicates(self): """Test parametric pulses with no duplicates.""" schedule = Schedule() drive_channel = DriveChannel(0) schedule += Play(Gaussian(duration=25, sigma=4, amp=0.5j), drive_channel) schedule += Play(Gaussian(duration=25, sigma=4, amp=0.49j), drive_channel) schedule += Play( GaussianSquare(duration=150, amp=0.2, sigma=8, width=140), drive_channel) schedule += Play( GaussianSquare(duration=150, amp=0.19, sigma=8, width=140), drive_channel) schedule += Play(Constant(duration=150, amp=0.1 + 0.4j), drive_channel) schedule += Play(Constant(duration=150, amp=0.1 + 0.41j), drive_channel) schedule += Play(Drag(duration=25, amp=0.2 + 0.3j, sigma=7.8, beta=4), drive_channel) schedule += Play(Drag(duration=25, amp=0.2 + 0.31j, sigma=7.8, beta=4), drive_channel) compressed_schedule = transforms.compress_pulses([schedule]) original_pulse_ids = get_pulse_ids([schedule]) compressed_pulse_ids = get_pulse_ids(compressed_schedule) self.assertEqual(len(original_pulse_ids), len(compressed_pulse_ids))
def rescale_cr_inst(instruction: Play, theta: float, sample_mult: int = 16) -> Play: """ Args: instruction: The instruction from which to create a new shortened or lengthened pulse. theta: desired angle, pi/2 is assumed to be the angle that the pulse in the given play instruction implements. sample_mult: All pulses must be a multiple of sample_mult. Returns: qiskit.pulse.Play: The play instruction with the stretched compressed GaussianSquare pulse. Raises: QiskitError: if the pulses are not GaussianSquare. """ pulse_ = instruction.pulse if isinstance(pulse_, GaussianSquare): amp = pulse_.amp width = pulse_.width sigma = pulse_.sigma n_sigmas = (pulse_.duration - width) / sigma # The error function is used because the Gaussian may have chopped tails. gaussian_area = abs(amp) * sigma * np.sqrt( 2 * np.pi) * math.erf(n_sigmas) area = gaussian_area + abs(amp) * width target_area = abs(theta) / (np.pi / 2.0) * area sign = theta / abs(theta) if target_area > gaussian_area: width = (target_area - gaussian_area) / abs(amp) duration = math.ceil( (width + n_sigmas * sigma) / sample_mult) * sample_mult return Play( GaussianSquare(amp=sign * amp, width=width, sigma=sigma, duration=duration), channel=instruction.channel, ) else: amp_scale = sign * target_area / gaussian_area duration = math.ceil( n_sigmas * sigma / sample_mult) * sample_mult return Play( GaussianSquare(amp=amp * amp_scale, width=0, sigma=sigma, duration=duration), channel=instruction.channel, ) else: raise QiskitError( "RZXCalibrationBuilder only stretches/compresses GaussianSquare." )
def rescale_cr_inst(instruction: Play, theta: float, sample_mult: int = 16) -> Play: """ Args: instruction: The instruction from which to create a new shortened or lengthened pulse. theta: desired angle, pi/2 is assumed to be the angle that the pulse in the given play instruction implements. sample_mult: All pulses must be a multiple of sample_mult. Returns: qiskit.pulse.Play: The play instruction with the stretched compressed GaussianSquare pulse. Raises: QiskitError: if rotation angle is not assigned. """ try: theta = float(theta) except TypeError as ex: raise QiskitError("Target rotation angle is not assigned.") from ex # This method is called for instructions which are guaranteed to play GaussianSquare pulse amp = instruction.pulse.amp width = instruction.pulse.width sigma = instruction.pulse.sigma n_sigmas = (instruction.pulse.duration - width) / sigma # The error function is used because the Gaussian may have chopped tails. gaussian_area = abs(amp) * sigma * np.sqrt( 2 * np.pi) * math.erf(n_sigmas) area = gaussian_area + abs(amp) * width target_area = abs(theta) / (np.pi / 2.0) * area sign = np.sign(theta) if target_area > gaussian_area: width = (target_area - gaussian_area) / abs(amp) duration = round( (width + n_sigmas * sigma) / sample_mult) * sample_mult return Play( GaussianSquare(amp=sign * amp, width=width, sigma=sigma, duration=duration), channel=instruction.channel, ) else: amp_scale = sign * target_area / gaussian_area duration = round(n_sigmas * sigma / sample_mult) * sample_mult return Play( GaussianSquare(amp=amp * amp_scale, width=0, sigma=sigma, duration=duration), channel=instruction.channel, )
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 rescale_cr_inst(instruction: Play, theta: float, sample_mult: int = 16, phase_delta: float = 0, amp_increase: float = 0.) -> Play: """ Args: instruction: The instruction from which to create a new shortened or lengthened instruction. theta: desired angle, pi/2 is assumed to be the angle that the schedule with name 'name' in 'sched' implements. sample_mult: All pulses must be a multiple of sample_mult. phase_delta: Multiplies the pulse samples by np.exp(1.0j*phase_delta). amp_increase: Multiplies the amplitude of the samples by (1. + amp_increase). """ if not isinstance(instruction.pulse, GaussianSquare): raise QiskitError('Parameteric builder only stretches/compresses ' 'GaussianSquare.') amp = instruction.pulse.amp width = instruction.pulse.width sigma = instruction.pulse.sigma n_sigmas = (instruction.pulse.duration - width) / sigma # The error function is used because the Gaussian may have chopped tails. gaussian_area = abs(amp) * sigma * np.sqrt( 2 * np.pi) * math.erf(n_sigmas) area = gaussian_area + abs(amp) * width target_area = theta / (np.pi / 2.) * area if target_area > gaussian_area: width = (target_area - gaussian_area) / abs(amp) duration = math.ceil( (width + n_sigmas * sigma) / sample_mult) * sample_mult return Play(GaussianSquare(amp=amp, width=width, sigma=sigma, duration=duration), channel=instruction.channel) else: amp_scale = target_area / gaussian_area duration = math.ceil(n_sigmas * sigma / sample_mult) * sample_mult return Play(GaussianSquare(amp=amp * amp_scale, width=0, sigma=sigma, duration=duration), channel=instruction.channel)
def test_gauss_square_samples(self): """Test that the gaussian square samples match the formula.""" duration = 125 sigma = 4 amp = 0.5j # formulaic times = np.array(range(25), dtype=np.complex_) times = times - (25 / 2) + 0.5 gauss = amp * np.exp(-(times / sigma)**2 / 2) # command command = GaussianSquare(duration=duration, sigma=sigma, amp=amp, width=100) samples = command.get_sample_pulse().samples np.testing.assert_almost_equal(samples[50], amp) np.testing.assert_almost_equal(samples[100], amp) np.testing.assert_almost_equal(samples[:10], gauss[:10])
def test_param_validation(self): """Test that parametric pulse parameters are validated when initialized.""" with self.assertRaises(PulseError): Gaussian(duration=25, sigma=0, amp=0.5j) with self.assertRaises(PulseError): GaussianSquare(duration=150, amp=0.2, sigma=8, width=160) with self.assertRaises(PulseError): ConstantPulse(duration=150, amp=0.9 + 0.8j) with self.assertRaises(PulseError): Drag(duration=25, amp=0.2 + 0.3j, sigma=-7.8, beta=4) with self.assertRaises(PulseError): Drag(duration=25, amp=0.2 + 0.3j, sigma=7.8, beta=4j)
def test_parametric_commands_in_sched(self): """Test that schedules can be built with parametric commands.""" sched = Schedule(name='test_parametric') sched += Play(Gaussian(duration=25, sigma=4, amp=0.5j), DriveChannel(0)) sched += Play(Drag(duration=25, amp=0.2+0.3j, sigma=7.8, beta=4), DriveChannel(1)) sched += Play(Constant(duration=25, amp=1), DriveChannel(2)) sched_duration = sched.duration sched += Play(GaussianSquare(duration=1500, amp=0.2, sigma=8, width=140), MeasureChannel(0)) << sched_duration self.assertEqual(sched.duration, 1525) self.assertTrue('sigma' in sched.instructions[0][1].pulse.parameters)
def stretch_sub_sched(sim_pulse_array, factor): ''' Input: A set of pulses happening at the same time (sim = simultaneous) and factor to be stretched by Output: A schedule consisting of the stretched pulses ''' sub_sched = qiskit.pulse.Schedule() for instruc in sim_pulse_array: #anything except shift phase if (isinstance(instruc, Play)): if (isinstance(instruc.pulse, Drag)): drag = instruc.pulse ## param = {"duration": self.duration, "amp": self.amp, "sigma": self.sigma, "width": self.width} param = drag.parameters duration = int(factor * param['duration']) sigma = (factor * param['sigma']) #stretching the drag pulse s_pulse = Drag(duration, param['amp'] / factor, sigma, param['beta']) channel = instruc.channels[0] sub_sched = sub_sched.append(pulse.Play(s_pulse, channel)) elif (isinstance(instruc.pulse, GaussianSquare)): gauss = instruc.pulse ## param = {"duration": self.duration, "amp": self.amp, "sigma": self.sigma, "width": self.width} param = gauss.parameters #print('------Old Param') #print(param) #stretching the drag pulse duration = get_closest_multiple_of_16(factor * param['duration']) sigma = (factor * param['sigma']) width = get_closest_multiple_of_16(factor * param['width']) s_pulse = GaussianSquare(duration, param['amp'] / factor, sigma, width) #print('------new Param') #print('Duration') #print(str(duration) + ' '+ str(param['amp']/factor) + ' '+ str(sigma) + ' '+ str(width)) #print(param) channel = instruc.channels[0] sub_sched = sub_sched.append(pulse.Play(s_pulse, channel)) #if not acquire elif (not isinstance(instruc, Acquire)): sub_sched += instruc else: sub_sched += instruc return sub_sched
def test_repr(self): """Test the repr methods for parametric pulses.""" gaussian = Gaussian(duration=25, amp=0.7, sigma=4) self.assertEqual(repr(gaussian), 'Gaussian(duration=25, amp=(0.7+0j), sigma=4)') gaus_square = GaussianSquare(duration=20, sigma=30, amp=1.0, width=3) self.assertEqual( repr(gaus_square), 'GaussianSquare(duration=20, amp=(1+0j), sigma=30, width=3)') drag = Drag(duration=5, amp=0.5, sigma=7, beta=1) self.assertEqual(repr(drag), 'Drag(duration=5, amp=(0.5+0j), sigma=7, beta=1)') const = ConstantPulse(duration=150, amp=0.1 + 0.4j) self.assertEqual(repr(const), 'ConstantPulse(duration=150, amp=(0.1+0.4j))')
def test_measure_with_custom_inst_map(self): """Test measure with custom inst_map, meas_map with measure_name.""" q0_sched = Play(GaussianSquare(1200, 1, 0.4, 1150), MeasureChannel(0)) q0_sched += Acquire(1200, AcquireChannel(0), MemorySlot(0)) inst_map = InstructionScheduleMap() inst_map.add('my_sched', 0, q0_sched) sched = macros.measure(qubits=[0], measure_name='my_sched', inst_map=inst_map, meas_map=[[0]]) self.assertEqual(sched.instructions, q0_sched.instructions) with self.assertRaises(PulseError): macros.measure(qubits=[0], measure_name="name", inst_map=inst_map, meas_map=[[0]])
def test_pulse_amp_typecasted(self): """Test if scaled pulse amplitude is complex type.""" fake_play = Play( GaussianSquare(duration=800, amp=0.1, sigma=64, risefall_sigma_ratio=2), ControlChannel(0), ) fake_theta = circuit.Parameter("theta") assigned_theta = fake_theta.assign(fake_theta, 0.01) scaled = RZXCalibrationBuilderNoEcho.rescale_cr_inst( instruction=fake_play, theta=assigned_theta) scaled_pulse = scaled.pulse self.assertIsInstance(scaled_pulse.amp, complex)
def test_rzx_calibration_builder_duration(self, theta: float): """Test that pulse durations are computed correctly.""" width = 512.00000001 sigma = 64 n_sigmas = 4 duration = width + n_sigmas * sigma sample_mult = 16 amp = 1.0 pulse = GaussianSquare(duration=duration, amp=amp, sigma=sigma, width=width) instruction = Play(pulse, ControlChannel(1)) scaled = RZXCalibrationBuilder.rescale_cr_inst(instruction, theta, sample_mult=sample_mult) gaussian_area = abs(amp) * sigma * np.sqrt(2 * np.pi) * erf(n_sigmas) area = gaussian_area + abs(amp) * width target_area = abs(theta) / (np.pi / 2.0) * area width = (target_area - gaussian_area) / abs(amp) expected_duration = round( (width + n_sigmas * sigma) / sample_mult) * sample_mult self.assertEqual(scaled.duration, expected_duration)
def test_gauss_square_extremes(self): """Test that the gaussian square pulse can build a gaussian.""" duration = 125 sigma = 4 amp = 0.5j gaus_square = GaussianSquare(duration=duration, sigma=sigma, amp=amp, width=0) gaus = Gaussian(duration=duration, sigma=sigma, amp=amp) np.testing.assert_almost_equal(gaus_square.get_sample_pulse().samples, gaus.get_sample_pulse().samples) gaus_square = GaussianSquare(duration=duration, sigma=sigma, amp=amp, width=121) const = ConstantPulse(duration=duration, amp=amp) np.testing.assert_almost_equal( gaus_square.get_sample_pulse().samples[2:-2], const.get_sample_pulse().samples[2:-2])
def test_construction(self): """Test that parametric pulses can be constructed without error.""" Gaussian(duration=25, sigma=4, amp=0.5j) GaussianSquare(duration=150, amp=0.2, sigma=8, width=140) ConstantPulse(duration=150, amp=0.1 + 0.4j) Drag(duration=25, amp=0.2 + 0.3j, sigma=7.8, beta=4)