def _schedule_2Q_interaction(self, total_samples): """Creates schedule for testing two qubit interaction. Specifically, do a pi pulse on qub 0 so it starts in the `1` state (drive channel) and then apply constant pulses to each qubit (on control channel 1). This will allow us to test a swap gate. Args: total_samples (int): length of pulses Returns: schedule (pulse schedule): schedule for 2q experiment """ # create acquire schedule acq_sched = Schedule(name='acq_sched') acq_sched |= Acquire(total_samples, AcquireChannel(0), MemorySlot(0)) acq_sched += Acquire(total_samples, AcquireChannel(1), MemorySlot(1)) # set up const pulse const_pulse = SamplePulse(np.ones(total_samples), name='const_pulse') # add commands to schedule schedule = Schedule(name='2q_schedule') schedule |= Play(const_pulse, DriveChannel(0)) schedule += Play(const_pulse, ControlChannel(1)) << schedule.duration schedule |= acq_sched << schedule.duration return schedule
def test_can_construct_valid_acquire_command(self): """Test if valid acquire command can be constructed.""" kernel_opts = { 'start_window': 0, 'stop_window': 10 } kernel = Kernel(name='boxcar', **kernel_opts) discriminator_opts = { 'neighborhoods': [{'qubits': 1, 'channels': 1}], 'cal': 'coloring', 'resample': False } discriminator = Discriminator(name='linear_discriminator', **discriminator_opts) acq = Acquire(10, AcquireChannel(0), MemorySlot(0), kernel=kernel, discriminator=discriminator, name='acquire') self.assertEqual(acq.duration, 10) self.assertEqual(acq.discriminator.name, 'linear_discriminator') self.assertEqual(acq.discriminator.params, discriminator_opts) self.assertEqual(acq.kernel.name, 'boxcar') self.assertEqual(acq.kernel.params, kernel_opts) self.assertIsInstance(acq.id, int) self.assertEqual(acq.name, 'acquire') self.assertEqual(acq.operands, (10, AcquireChannel(0), MemorySlot(0), None))
def test_isntructions_hash(self): """Test hashing for acquire instruction.""" kernel_opts = {'start_window': 0, 'stop_window': 10} kernel = Kernel(name='boxcar', **kernel_opts) discriminator_opts = { 'neighborhoods': [{ 'qubits': 1, 'channels': 1 }], 'cal': 'coloring', 'resample': False } discriminator = Discriminator(name='linear_discriminator', **discriminator_opts) acq_1 = Acquire(10, AcquireChannel(0), MemorySlot(0), kernel=kernel, discriminator=discriminator, name='acquire') acq_2 = Acquire(10, AcquireChannel(0), MemorySlot(0), kernel=kernel, discriminator=discriminator, name='acquire') hash_1 = hash(acq_1) hash_2 = hash(acq_2) self.assertEqual(hash_1, hash_2)
def test_measure_combined(self): """ Test to check for measure on the same qubit which generated another measure schedule. The measures on different qubits are combined, but measures on the same qubit adds another measure to the schedule. """ q = QuantumRegister(2) c = ClassicalRegister(2) qc = QuantumCircuit(q, c) qc.u2(3.14, 1.57, q[0]) qc.cx(q[0], q[1]) qc.measure(q[0], c[0]) qc.measure(q[1], c[1]) qc.measure(q[1], c[1]) sched = schedule(qc, self.backend, method="as_soon_as_possible") expected = Schedule( self.inst_map.get('u2', [0], 3.14, 1.57), (28, self.inst_map.get('cx', [0, 1])), (50, self.inst_map.get('measure', [0, 1])), (60, self.inst_map.get( 'measure', [0, 1]).filter(channels=[MeasureChannel(1)])), (60, Acquire(10, AcquireChannel(0), MemorySlot(0))), (60, Acquire(10, AcquireChannel(1), MemorySlot(1)))) self.assertEqual(sched.instructions, expected.instructions)
def test_measure(self): """Test macro - measure.""" sched = macros.measure(qubits=[0], backend=self.backend) expected = Schedule( self.inst_map.get('measure', [0, 1]).filter(channels=[MeasureChannel(0)]), Acquire(10, AcquireChannel(0), MemorySlot(0)), Acquire(10, AcquireChannel(1), MemorySlot(1))) self.assertEqual(sched.instructions, expected.instructions)
def test_measure(self): """Test utility function - measure.""" acquire = Acquire(duration=10) sched = measure(qubits=[0], backend=self.backend) expected = Schedule( self.inst_map.get('measure', [0, 1]).filter(channels=[MeasureChannel(0)]), acquire(AcquireChannel(0), MemorySlot(0)), acquire(AcquireChannel(1), MemorySlot(1))) self.assertEqual(sched.instructions, expected.instructions)
def test_measure_sched_with_qubit_mem_slots(self): """Test measure with custom qubit_mem_slots.""" sched = macros.measure(qubits=[0], backend=self.backend, qubit_mem_slots={0: 1}) expected = Schedule( self.inst_map.get('measure', [0, 1]).filter(channels=[MeasureChannel(0)]), Acquire(10, AcquireChannel(0), MemorySlot(1)), Acquire(10, AcquireChannel(1), MemorySlot(0))) self.assertEqual(sched.instructions, expected.instructions)
def test_measure_sched_with_meas_map(self): """Test measure with custom meas_map as list and dict.""" sched_with_meas_map_list = macros.measure(qubits=[0], backend=self.backend, meas_map=[[0, 1]]) sched_with_meas_map_dict = macros.measure(qubits=[0], backend=self.backend, meas_map={0: [0, 1], 1: [0, 1]}) expected = Schedule( self.inst_map.get('measure', [0, 1]).filter(channels=[MeasureChannel(0)]), Acquire(10, AcquireChannel(0), MemorySlot(0)), Acquire(10, AcquireChannel(1), MemorySlot(1))) self.assertEqual(sched_with_meas_map_list.instructions, expected.instructions) self.assertEqual(sched_with_meas_map_dict.instructions, expected.instructions)
def test_user_mapping_for_memslots(self): """ Test that the new schedule only has required `MeasureChannel`s and that the `MemorySlot`s are mapped according to the input circuit. """ q = QuantumRegister(2) c = ClassicalRegister(2) qc = QuantumCircuit(q, c) qc.measure(q[0], c[1]) sched = schedule(qc, self.backend) expected = Schedule( self.cmd_def.get('measure', [0, 1]).filter(channels=[MeasureChannel(0)]), Acquire(duration=10)([AcquireChannel(0), AcquireChannel(1)], [MemorySlot(1), MemorySlot(0)])) self.assertEqual(sched.instructions, expected.instructions)
def _3Q_constant_sched(self, total_samples, amp=1., u_idx=0, subsystem_list=[0, 2]): """Creates a runnable schedule for the 3Q system after the system is restricted to 2 qubits. Args: total_samples (int): length of pulse amp (float): amplitude of constant pulse (can be complex) u_idx (int): index of U channel subsystem_list (list): list of qubits to restrict to Returns: schedule (pulse schedule): schedule with a drive pulse followed by an acquire """ # set up constant pulse for doing a pi pulse drive_pulse = Waveform(amp * np.ones(total_samples)) schedule = Schedule() schedule |= Play(drive_pulse, ControlChannel(u_idx)) for idx in subsystem_list: schedule |= Acquire(total_samples, AcquireChannel(idx), MemorySlot(idx)) << total_samples return schedule
def test_set_phase_rwa(self): """Test SetPhase command using an RWA approximate solution.""" omega_0 = 5.123 r = 0.01 system_model = self._system_model_1Q(omega_0, r) sched = Schedule() sched += SetPhase(np.pi / 2, DriveChannel(0)) sched += Play(Waveform(np.ones(100)), DriveChannel(0)) sched |= Acquire(1, AcquireChannel(0), MemorySlot(0)) << sched.duration y0 = np.array([1., 1.]) / np.sqrt(2) pulse_sim = PulseSimulator(system_model=system_model, initial_state=y0) qobj = assemble([sched], backend=pulse_sim, meas_level=2, meas_return='single', meas_map=[[0]], qubit_lo_freq=[omega_0], memory_slots=2, shots=1) results = pulse_sim.run(qobj).result() pulse_sim_yf = results.get_statevector() #run independent simulation phases = np.exp( (-1j * 2 * np.pi * omega_0 * np.array([1, -1]) / 2) * 100) approx_yf = phases * (expm(-1j * (np.pi / 2) * self.Y) @ y0) self.assertGreaterEqual(state_fidelity(pulse_sim_yf, approx_yf), 0.99)
def _1Q_frame_change_schedule(self, phi, fc_phi, total_samples, dur_drive1, dur_drive2): """Creates schedule for frame change test. Does a pulse w/ phase phi of duration dur_drive1, then frame change of phase fc_phi, then another pulse of phase phi of duration dur_drive2. The different durations for the pulses allow manipulation of rotation angles on Bloch sphere Args: phi (float): drive phase (phi in Hamiltonian) fc_phi (float): phase for frame change total_samples (int): length of pulses dur_drive1 (int): duration of first pulse dur_drive2 (int): duration of second pulse Returns: schedule (pulse schedule): schedule for frame change test """ phase = np.exp(1j * phi) drive_pulse_1 = SamplePulse(phase * np.ones(dur_drive1), name='drive_pulse_1') drive_pulse_2 = SamplePulse(phase * np.ones(dur_drive2), name='drive_pulse_2') # add commands to schedule schedule = Schedule(name='fc_schedule') schedule |= Play(drive_pulse_1, DriveChannel(0)) schedule += ShiftPhase(fc_phi, DriveChannel(0)) schedule += Play(drive_pulse_2, DriveChannel(0)) schedule |= Acquire(total_samples, AcquireChannel(0), MemorySlot(0)) << schedule.duration return schedule
def _simple_1Q_schedule(self, phi, total_samples, shape="square", gauss_sigma=0): """Creates schedule for single pulse test Args: phi (float): drive phase (phi in Hamiltonian) total_samples (int): length of pulses shape (str): shape of the pulse; defaults to square pulse gauss_sigma (float): std dev for gaussian pulse if shape=="gaussian" Returns: schedule (pulse schedule): schedule for this test """ # set up pulse command phase = np.exp(1j * phi) drive_pulse = None if shape == "square": const_pulse = np.ones(total_samples) drive_pulse = SamplePulse(phase * const_pulse, name='drive_pulse') if shape == "gaussian": times = 1.0 * np.arange(total_samples) gaussian = np.exp(-times**2 / 2 / gauss_sigma**2) drive_pulse = SamplePulse(phase * gaussian, name='drive_pulse') # add commands into a schedule for first qubit schedule = Schedule(name='drive_pulse') schedule |= Play(drive_pulse, DriveChannel(0)) schedule |= Acquire(total_samples, AcquireChannel(0), MemorySlot(0)) << schedule.duration return schedule
def test_user_mapping_for_memslots_3Q(self): """Test measuring two of three qubits.""" backend = FakeOpenPulse3Q() cmd_def = backend.defaults().build_cmd_def() q = QuantumRegister(3) c = ClassicalRegister(3) qc = QuantumCircuit(q, c) qc.measure(q[1], c[2]) qc.measure(q[2], c[0]) sched = schedule(qc, backend) expected = Schedule( cmd_def.get('measure', [0, 1, 2]).filter( channels=[MeasureChannel(1), MeasureChannel(2)]), Acquire(duration=10)([AcquireChannel(0), AcquireChannel(1), AcquireChannel(2)], [MemorySlot(1), MemorySlot(2), MemorySlot(0)])) self.assertEqual(sched.instructions, expected.instructions)
def test_gaussian_drive(self): """Test gaussian drive pulse using meas_level_2. Set omega_d0=omega_0 (drive on resonance), phi=0, omega_a = pi/time """ # set omega_0, omega_d0 equal (use qubit frequency) -> drive on resonance total_samples = 100 omega_0 = 1. omega_d = omega_0 # Require omega_a*time = pi to implement pi pulse (x gate) # num of samples gives time r = np.pi / total_samples # initial state and seed y0 = np.array([1., 0.]) seed = 9000 # Test gaussian drive results for a few different sigma gauss_sigmas = [total_samples / 6, total_samples / 3, total_samples] # set up pulse simulator pulse_sim = PulseSimulator(system_model=self._system_model_1Q(omega_0, r)) for gauss_sigma in gauss_sigmas: with self.subTest(gauss_sigma=gauss_sigma): times = 1.0 * np.arange(total_samples) gaussian_samples = np.exp(-times**2 / 2 / gauss_sigma**2) drive_pulse = Waveform(gaussian_samples, name='drive_pulse') # construct schedule schedule = Schedule() schedule |= Play(drive_pulse, DriveChannel(0)) schedule |= Acquire(1, AcquireChannel(0), MemorySlot(0)) << schedule.duration qobj = assemble([schedule], backend=pulse_sim, meas_level=2, meas_return='single', meas_map=[[0]], qubit_lo_freq=[omega_d], memory_slots=2, shots=1) result = pulse_sim.run(qobj, initial_state=y0, seed=seed).result() pulse_sim_yf = result.get_statevector() # run independent simulation yf = simulate_1q_model(y0, omega_0, r, np.array([omega_d]), gaussian_samples, 1.) # Check fidelity of statevectors self.assertGreaterEqual(state_fidelity(pulse_sim_yf, yf), 1 - (10**-5))
def _2Q_constant_sched(self, total_samples, amp=1., u_idx=0): """Creates a runnable schedule with a single pulse on a U channel for two qubits. Args: total_samples (int): length of pulse amp (float): amplitude of constant pulse (can be complex) u_idx (int): index of U channel Returns: schedule (pulse schedule): schedule with a drive pulse followed by an acquire """ # set up constant pulse for doing a pi pulse drive_pulse = SamplePulse(amp * np.ones(total_samples)) schedule = Schedule() schedule |= Play(drive_pulse, ControlChannel(u_idx)) schedule |= Acquire(total_samples, AcquireChannel(0), MemorySlot(0)) << total_samples schedule |= Acquire(total_samples, AcquireChannel(1), MemorySlot(1)) << total_samples return schedule
def test_multiple_measure_in_3Q(self): """Test multiple measure, user memslot mapping, 3Q.""" backend = FakeOpenPulse3Q() cmd_def = backend.defaults().build_cmd_def() q = QuantumRegister(3) c = ClassicalRegister(5) qc = QuantumCircuit(q, c) qc.measure(q[0], c[2]) qc.measure(q[0], c[4]) sched = schedule(qc, backend) expected = Schedule( cmd_def.get('measure', [0, 1, 2]).filter(channels=[MeasureChannel(0)]), Acquire(duration=10)( [AcquireChannel(0), AcquireChannel(1), AcquireChannel(2)], [MemorySlot(2), MemorySlot(0), MemorySlot(1)]), (10, cmd_def.get('measure', [0, 1, 2]).filter(channels=[MeasureChannel(0)])), (10, Acquire(duration=10)( [AcquireChannel(0), AcquireChannel(1), AcquireChannel(2)], [MemorySlot(4), MemorySlot(0), MemorySlot(1)]))) self.assertEqual(sched.instructions, expected.instructions)
def test_set_phase(self): """Test SetPhase command. Similar to the ShiftPhase test but includes a mixing of ShiftPhase and SetPhase instructions to test relative vs absolute changes""" omega_0 = 1.3981 r = 1. system_model = self._system_model_1Q(omega_0, r) # intermix shift and set phase instructions to verify absolute v.s. relative changes sched = Schedule() amp1 = 0.12 sched += Play(Waveform([amp1]), DriveChannel(0)) phi1 = 0.12374 * np.pi sched += ShiftPhase(phi1, DriveChannel(0)) amp2 = 0.492 sched += Play(Waveform([amp2]), DriveChannel(0)) phi2 = 0.5839 * np.pi sched += SetPhase(phi2, DriveChannel(0)) amp3 = 0.12 + 0.21 * 1j sched += Play(Waveform([amp3]), DriveChannel(0)) phi3 = 0.1 * np.pi sched += ShiftPhase(phi3, DriveChannel(0)) amp4 = 0.2 + 0.3 * 1j sched += Play(Waveform([amp4]), DriveChannel(0)) sched |= Acquire(1, AcquireChannel(0), MemorySlot(0)) << sched.duration y0 = np.array([1., 0.]) pulse_sim = PulseSimulator(system_model=system_model, initial_state=y0) qobj = assemble([sched], backend=pulse_sim, meas_level=2, meas_return='single', meas_map=[[0]], qubit_lo_freq=[omega_0], memory_slots=2, shots=1) results = pulse_sim.run(qobj).result() pulse_sim_yf = results.get_statevector() #run independent simulation samples = np.array([[amp1], [amp2 * np.exp(1j * phi1)], [amp3 * np.exp(1j * phi2)], [amp4 * np.exp(1j * (phi2 + phi3))]]) indep_yf = simulate_1q_model(y0, omega_0, r, np.array([omega_0]), samples, 1.) self.assertGreaterEqual(state_fidelity(pulse_sim_yf, indep_yf), 1 - (10**-5))
def test_calibrated_measurements(self): """Test scheduling calibrated measurements.""" q = QuantumRegister(2) c = ClassicalRegister(2) qc = QuantumCircuit(q, c) qc.append(U2Gate(0, 0), [q[0]]) qc.measure(q[0], c[0]) meas_sched = Play(Gaussian(1200, 0.2, 4), MeasureChannel(0)) meas_sched |= Acquire(1200, AcquireChannel(0), MemorySlot(0)) qc.add_calibration("measure", [0], meas_sched) sched = schedule(qc, self.backend) expected = Schedule(self.inst_map.get("u2", [0], 0, 0), (2, meas_sched)) self.assertEqual(sched.instructions, expected.instructions)
def test_clbits_of_calibrated_measurements(self): """Test that calibrated measurements are only used when the classical bits also match.""" q = QuantumRegister(2) c = ClassicalRegister(2) qc = QuantumCircuit(q, c) qc.measure(q[0], c[1]) meas_sched = Play(Gaussian(1200, 0.2, 4), MeasureChannel(0)) meas_sched |= Acquire(1200, AcquireChannel(0), MemorySlot(0)) qc.add_calibration("measure", [0], meas_sched) sched = schedule(qc, self.backend) # Doesn't use the calibrated schedule because the classical memory slots do not match expected = Schedule(macros.measure([0], self.backend, qubit_mem_slots={0: 1})) self.assertEqual(sched.instructions, expected.instructions)
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 _1Q_schedule(self, total_samples=100, amp=1., num_acquires=1): """Creates a schedule for a single qubit. Args: total_samples (int): number of samples in the drive pulse amp (complex): amplitude of drive pulse num_acquires (int): number of acquire instructions to include in the schedule Returns: schedule (pulse schedule): """ schedule = Schedule() schedule |= Play(Waveform(amp * np.ones(total_samples)), DriveChannel(0)) for _ in range(num_acquires): schedule |= Acquire(total_samples, AcquireChannel(0), MemorySlot(0)) << schedule.duration return schedule
def _1Q_constant_sched(self, total_samples, amp=1.): """Creates a runnable schedule for 1Q with a constant drive pulse of a given length. Args: total_samples (int): length of pulse amp (float): amplitude of constant pulse (can be complex) Returns: schedule (pulse schedule): schedule with a drive pulse followed by an acquire """ # set up constant pulse for doing a pi pulse drive_pulse = SamplePulse(amp * np.ones(total_samples)) schedule = Schedule() schedule |= Play(drive_pulse, DriveChannel(0)) schedule |= Acquire(total_samples, AcquireChannel(0), MemorySlot(0)) << schedule.duration return schedule
def test_subset_calibrated_measurements(self): """Test that measurement calibrations can be added and used for some qubits, even if the other qubits do not also have calibrated measurements.""" qc = QuantumCircuit(3, 3) qc.measure(0, 0) qc.measure(1, 1) qc.measure(2, 2) meas_scheds = [] for qubit in [0, 2]: meas = (Play(Gaussian(1200, 0.2, 4), MeasureChannel(qubit)) + Acquire(1200, AcquireChannel(qubit), MemorySlot(qubit))) meas_scheds.append(meas) qc.add_calibration('measure', [qubit], meas) meas = macros.measure([1], FakeOpenPulse3Q()) meas = meas.exclude(channels=[AcquireChannel(0), AcquireChannel(2)]) sched = schedule(qc, FakeOpenPulse3Q()) expected = Schedule(meas_scheds[0], meas_scheds[1], meas) self.assertEqual(sched.instructions, expected.instructions)
def model_and_pi_schedule(): """Return a simple model and schedule for pulse simulation""" # construct model model = duffing_system_model(dim_oscillators=2, oscillator_freqs=[5.0], anharm_freqs=[0], drive_strengths=[0.01], coupling_dict={}, dt=1.0) # note: parameters set so that area under curve is 1/4 sample_pulse = SamplePulse(np.ones(50)) # construct schedule schedule = Schedule(name='test_sched') schedule |= Play(sample_pulse, DriveChannel(0)) schedule += Acquire(10, AcquireChannel(0), MemorySlot(0)) << schedule.duration return model, schedule
def model_and_pi_schedule(): """Return a simple model and schedule for pulse simulation""" # construct model model = duffing_system_model(dim_oscillators=2, oscillator_freqs=[5.0], anharm_freqs=[0], drive_strengths=[1.0], coupling_dict={}, dt=1.0) # note: parameters set so that area under curve is 1/4 gauss_pulse = Gaussian(duration=10, amp=(1.0 / 4) / 2.506627719963857, sigma=1) # construct schedule schedule = Schedule(name='test_sched') schedule |= Play(gauss_pulse, DriveChannel(0)) schedule += Acquire(10, AcquireChannel(0), MemorySlot(0)) << schedule.duration return model, schedule
def test_2Q_exchange(self): r"""Test a more complicated 2q simulation""" q_freqs = [5., 5.1] r = 0.02 j = 0.02 total_samples = 25 hamiltonian = {} hamiltonian['h_str'] = [ '2*np.pi*v0*0.5*Z0', '2*np.pi*v1*0.5*Z1', '2*np.pi*r*0.5*X0||D0', '2*np.pi*r*0.5*X1||D1', '2*np.pi*j*0.5*I0*I1', '2*np.pi*j*0.5*X0*X1', '2*np.pi*j*0.5*Y0*Y1', '2*np.pi*j*0.5*Z0*Z1' ] hamiltonian['vars'] = { 'v0': q_freqs[0], 'v1': q_freqs[1], 'r': r, 'j': j } hamiltonian['qub'] = {'0': 2, '1': 2} ham_model = HamiltonianModel.from_dict(hamiltonian) # set the U0 to have frequency of drive channel 0 u_channel_lo = [] subsystem_list = [0, 1] dt = 1. system_model = PulseSystemModel(hamiltonian=ham_model, u_channel_lo=u_channel_lo, subsystem_list=subsystem_list, dt=dt) # try some random schedule schedule = Schedule() drive_pulse = Waveform(np.ones(total_samples)) schedule += Play(drive_pulse, DriveChannel(0)) schedule |= Play(drive_pulse, DriveChannel(1)) << 2 * total_samples schedule |= Acquire(total_samples, AcquireChannel(0), MemorySlot(0)) << 3 * total_samples schedule |= Acquire(total_samples, AcquireChannel(1), MemorySlot(1)) << 3 * total_samples y0 = np.array([1., 0., 0., 0.]) pulse_sim = PulseSimulator(system_model=system_model, initial_state=y0, seed=9000) qobj = assemble([schedule], backend=pulse_sim, meas_level=2, meas_return='single', meas_map=[[0]], qubit_lo_freq=q_freqs, memory_slots=2, shots=1000) result = pulse_sim.run(qobj).result() pulse_sim_yf = result.get_statevector() # set up and run independent simulation d0_samps = np.concatenate( (np.ones(total_samples), np.zeros(2 * total_samples))) d1_samps = np.concatenate( (np.zeros(2 * total_samples), np.ones(total_samples))) samples = np.array([d0_samps, d1_samps]).transpose() q_freqs = np.array(q_freqs) yf = simulate_2q_exchange_model(y0, q_freqs, r, j, q_freqs, samples, 1.) # Check fidelity of statevectors self.assertGreaterEqual(state_fidelity(pulse_sim_yf, yf), 1 - (10**-5))
def test_delay_instruction(self): """Test for delay instruction.""" # construct system model specifically for this hamiltonian = {} hamiltonian['h_str'] = ['0.5*r*X0||D0', '0.5*r*Y0||D1'] hamiltonian['vars'] = {'r': np.pi} hamiltonian['qub'] = {'0': 2} ham_model = HamiltonianModel.from_dict(hamiltonian) u_channel_lo = [] subsystem_list = [0] dt = 1. system_model = PulseSystemModel(hamiltonian=ham_model, u_channel_lo=u_channel_lo, subsystem_list=subsystem_list, dt=dt) # construct a schedule that should result in a unitary -Z if delays are correctly handled # i.e. do a pi rotation about x, sandwiched by pi/2 rotations about y in opposite directions # so that the x rotation is transformed into a z rotation. # if delays are not handled correctly this process should fail sched = Schedule() sched += Play(Waveform([0.5]), DriveChannel(1)) sched += Delay(1, DriveChannel(1)) sched += Play(Waveform([-0.5]), DriveChannel(1)) sched += Delay(1, DriveChannel(0)) sched += Play(Waveform([1.]), DriveChannel(0)) sched |= Acquire(1, AcquireChannel(0), MemorySlot(0)) << sched.duration # Result of schedule should be the unitary -1j*Z, so check rotation of an X eigenstate pulse_sim = PulseSimulator(system_model=system_model, initial_state=np.array([1., 1.]) / np.sqrt(2)) qobj = assemble([sched], backend=pulse_sim, meas_level=2, meas_return='single', meas_map=[[0]], qubit_lo_freq=[0., 0.], memory_slots=2, shots=1) results = pulse_sim.run(qobj).result() statevector = results.get_statevector() expected_vector = np.array([-1j, 1j]) / np.sqrt(2) self.assertGreaterEqual(state_fidelity(statevector, expected_vector), 1 - (10**-5)) # verify validity of simulation when no delays included sched = Schedule() sched += Play(Waveform([0.5]), DriveChannel(1)) sched += Play(Waveform([-0.5]), DriveChannel(1)) sched += Play(Waveform([1.]), DriveChannel(0)) sched |= Acquire(1, AcquireChannel(0), MemorySlot(0)) << sched.duration qobj = assemble([sched], backend=pulse_sim, meas_level=2, meas_return='single', meas_map=[[0]], qubit_lo_freq=[0., 0.], memory_slots=2, shots=1) results = pulse_sim.run(qobj).result() statevector = results.get_statevector() U = expm(1j * np.pi * self.Y / 4) @ expm(-1j * np.pi * (self.Y / 4 + self.X / 2)) expected_vector = U @ np.array([1., 1.]) / np.sqrt(2) self.assertGreaterEqual(state_fidelity(statevector, expected_vector), 1 - (10**-5))
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
def test_shift_phase(self): """Test ShiftPhase command.""" omega_0 = 1.123 r = 1. system_model = self._system_model_1Q(omega_0, r) # run a schedule in which a shifted phase causes a pulse to cancel itself. # Also do it in multiple phase shifts to test accumulation sched = Schedule() amp1 = 0.12 sched += Play(Waveform([amp1]), DriveChannel(0)) phi1 = 0.12374 * np.pi sched += ShiftPhase(phi1, DriveChannel(0)) amp2 = 0.492 sched += Play(Waveform([amp2]), DriveChannel(0)) phi2 = 0.5839 * np.pi sched += ShiftPhase(phi2, DriveChannel(0)) amp3 = 0.12 + 0.21 * 1j sched += Play(Waveform([amp3]), DriveChannel(0)) sched |= Acquire(1, AcquireChannel(0), MemorySlot(0)) << sched.duration y0 = np.array([1., 0]) pulse_sim = PulseSimulator(system_model=system_model, initial_state=y0) qobj = assemble([sched], backend=pulse_sim, meas_level=2, meas_return='single', meas_map=[[0]], qubit_lo_freq=[omega_0], memory_slots=2, shots=1) results = pulse_sim.run(qobj).result() pulse_sim_yf = results.get_statevector() #run independent simulation samples = np.array([[amp1], [amp2 * np.exp(1j * phi1)], [amp3 * np.exp(1j * (phi1 + phi2))]]) indep_yf = simulate_1q_model(y0, omega_0, r, np.array([omega_0]), samples, 1.) self.assertGreaterEqual(state_fidelity(pulse_sim_yf, indep_yf), 1 - (10**-5)) # run another schedule with only a single shift phase to verify sched = Schedule() amp1 = 0.12 sched += Play(Waveform([amp1]), DriveChannel(0)) phi1 = 0.12374 * np.pi sched += ShiftPhase(phi1, DriveChannel(0)) amp2 = 0.492 sched += Play(Waveform([amp2]), DriveChannel(0)) sched |= Acquire(1, AcquireChannel(0), MemorySlot(0)) << sched.duration qobj = assemble([sched], backend=pulse_sim, meas_level=2, meas_return='single', meas_map=[[0]], qubit_lo_freq=[omega_0], memory_slots=2, shots=1) results = pulse_sim.run(qobj).result() pulse_sim_yf = results.get_statevector() #run independent simulation samples = np.array([[amp1], [amp2 * np.exp(1j * phi1)]]) indep_yf = simulate_1q_model(y0, omega_0, r, np.array([omega_0]), samples, 1.) self.assertGreaterEqual(state_fidelity(pulse_sim_yf, indep_yf), 1 - (10**-5))