def test_call_gate_and_circuit(self): """Test calling circuit with gates.""" h_control = circuit.QuantumCircuit(2) h_control.h(0) with pulse.build(self.backend) as schedule: with pulse.align_sequential(): # this is circuit, a subroutine stored as Call instruction pulse.call(h_control) # this is instruction, not subroutine pulse.cx(0, 1) # this is macro, not subroutine pulse.measure([0, 1]) # subroutine h_reference = compiler.schedule(compiler.transpile(h_control, self.backend), self.backend) # gate cx_circ = circuit.QuantumCircuit(2) cx_circ.cx(0, 1) cx_reference = compiler.schedule(compiler.transpile(cx_circ, self.backend), self.backend) # measurement measure_reference = macros.measure( qubits=[0, 1], inst_map=self.inst_map, meas_map=self.configuration.meas_map ) reference = pulse.Schedule() reference += pulse.instructions.Call(h_reference) reference += cx_reference reference += measure_reference << reference.duration self.assertScheduleEqual(schedule, reference)
def test_transpile_with_instmap(self): """Test providing instruction schedule map.""" instmap = FakeAthens().defaults().instruction_schedule_map instmap.add("sx", (0, ), self.custom_sx_q0) instmap.add("sx", (1, ), self.custom_sx_q1) # Inst map is renewed backend = FakeAthens() qc = circuit.QuantumCircuit(2) qc.sx(0) qc.x(0) qc.rz(0, 0) qc.sx(1) qc.measure_all() transpiled_qc = transpile(qc, backend, inst_map=instmap, initial_layout=[0, 1]) ref_calibration = { "sx": { ((0, ), ()): self.custom_sx_q0, ((1, ), ()): self.custom_sx_q1, } } self.assertDictEqual(transpiled_qc.calibrations, ref_calibration)
def test_transpile_with_custom_gate(self): """Test providing non-basis gate.""" backend = FakeAthens() backend.defaults().instruction_schedule_map.add("my_gate", (0, ), self.my_gate_q0, arguments=["P0"]) backend.defaults().instruction_schedule_map.add("my_gate", (1, ), self.my_gate_q1, arguments=["P0"]) qc = circuit.QuantumCircuit(2) qc.append(circuit.Gate("my_gate", 1, [1.0]), [0]) qc.append(circuit.Gate("my_gate", 1, [2.0]), [1]) transpiled_qc = transpile(qc, backend, basis_gates=["my_gate"], initial_layout=[0, 1]) my_gate_q0_1_0 = self.my_gate_q0.assign_parameters( {self.sched_param: 1.0}, inplace=False) my_gate_q1_2_0 = self.my_gate_q1.assign_parameters( {self.sched_param: 2.0}, inplace=False) ref_calibration = { "my_gate": { ((0, ), (1.0, )): my_gate_q0_1_0, ((1, ), (2.0, )): my_gate_q1_2_0, } } self.assertDictEqual(transpiled_qc.calibrations, ref_calibration)
def test_rzx_calibration_builder(self): """Test whether RZXCalibrationBuilderNoEcho scales pulses correctly.""" # Define a circuit with one RZX gate and an angle theta. theta = pi / 3 rzx_qc = circuit.QuantumCircuit(2) rzx_qc.rzx(theta / 2, 1, 0) # Verify that there are no calibrations for this circuit yet. self.assertEqual(rzx_qc.calibrations, {}) # apply the RZXCalibrationBuilderNoEcho. pass_ = RZXCalibrationBuilderNoEcho(self.backend) cal_qc = PassManager(pass_).run(rzx_qc) rzx_qc_duration = schedule(cal_qc, self.backend).duration # Check that the calibrations contain the correct instructions # and pulses on the correct channels. # pylint: disable=no-member rzx_qc_instructions = cal_qc.calibrations["rzx"][((1, 0), (theta / 2, ))].instructions self.assertEqual(rzx_qc_instructions[0][1].channel, DriveChannel(0)) self.assertTrue(isinstance(rzx_qc_instructions[0][1], Play)) self.assertTrue( isinstance(rzx_qc_instructions[0][1].pulse, GaussianSquare)) self.assertEqual(rzx_qc_instructions[1][1].channel, DriveChannel(1)) self.assertTrue(isinstance(rzx_qc_instructions[1][1], Delay)) self.assertEqual(rzx_qc_instructions[2][1].channel, ControlChannel(1)) self.assertTrue(isinstance(rzx_qc_instructions[2][1], Play)) self.assertTrue( isinstance(rzx_qc_instructions[2][1].pulse, GaussianSquare)) # Calculate the duration of one scaled Gaussian square pulse from the CX gate. cx_sched = self.inst_map.get("cx", qubits=(1, 0)) crs = [] 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)) pulse_ = crs[0][1].pulse amp = pulse_.amp width = pulse_.width sigma = pulse_.sigma n_sigmas = (pulse_.duration - width) / sigma sample_mult = 16 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) duration = ceil((width + n_sigmas * sigma) / sample_mult) * sample_mult # Check whether the durations of the RZX pulse and # the scaled CR pulse from the CX gate match. self.assertEqual(rzx_qc_duration, duration)
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_multiple_instructions_with_different_parameters(self): """Test adding many instruction with different parameter binding.""" backend = FakeAthens() backend.defaults().instruction_schedule_map.add("my_gate", (0, ), self.my_gate_q0, arguments=["P0"]) qc = circuit.QuantumCircuit(1) qc.append(circuit.Gate("my_gate", 1, [1.0]), [0]) qc.append(circuit.Gate("my_gate", 1, [2.0]), [0]) qc.append(circuit.Gate("my_gate", 1, [3.0]), [0]) transpiled_qc = transpile(qc, backend, basis_gates=["my_gate"], initial_layout=[0]) my_gate_q0_1_0 = self.my_gate_q0.assign_parameters( {self.sched_param: 1.0}, inplace=False) my_gate_q0_2_0 = self.my_gate_q0.assign_parameters( {self.sched_param: 2.0}, inplace=False) my_gate_q0_3_0 = self.my_gate_q0.assign_parameters( {self.sched_param: 3.0}, inplace=False) ref_calibration = { "my_gate": { ((0, ), (1.0, )): my_gate_q0_1_0, ((0, ), (2.0, )): my_gate_q0_2_0, ((0, ), (3.0, )): my_gate_q0_3_0, } } self.assertDictEqual(transpiled_qc.calibrations, ref_calibration)
def test_u2(self): """Test u2 gate.""" with pulse.build(self.backend) as schedule: pulse.u2(np.pi, 0, 0) reference_qc = circuit.QuantumCircuit(1) reference_qc.append(circuit.library.U2Gate(np.pi, 0), [0]) reference = compiler.schedule(reference_qc, self.backend) self.assertEqual(schedule, reference)
def test_u3(self): """Test u3 gate.""" with pulse.build(self.backend) as schedule: pulse.u3(np.pi, 0, np.pi/2, 0) reference_qc = circuit.QuantumCircuit(1) reference_qc.u3(np.pi, 0, np.pi/2, 0) reference = compiler.schedule(reference_qc, self.backend) self.assertEqual(schedule, reference)
def test_u3(self): """Test u3 gate.""" with pulse.build(self.backend) as schedule: pulse.u3(np.pi / 8, np.pi / 16, np.pi / 4, 0) reference_qc = circuit.QuantumCircuit(1) reference_qc.append(circuit.library.U3Gate(np.pi / 8, np.pi / 16, np.pi / 4), [0]) reference = compiler.schedule(reference_qc, self.backend) self.assertScheduleEqual(schedule, reference)
def test_lazy_evaluation_with_transpiler(self): """Test that the two cx gates are optimizied away by the transpiler.""" with pulse.build(self.backend) as schedule: pulse.cx(0, 1) pulse.cx(0, 1) reference_qc = circuit.QuantumCircuit(2) reference = compiler.schedule(reference_qc, self.backend) self.assertEqual(schedule, reference)
def test_cx(self): """Test cx gate.""" with pulse.build(self.backend) as schedule: pulse.cx(0, 1) reference_qc = circuit.QuantumCircuit(2) reference_qc.cx(0, 1) reference = compiler.schedule(reference_qc, self.backend) self.assertEqual(schedule, reference)
def test_x(self): """Test x gate.""" with pulse.build(self.backend) as schedule: pulse.x(0) reference_qc = circuit.QuantumCircuit(1) reference_qc.x(0) reference_qc = compiler.transpile(reference_qc, self.backend) reference = compiler.schedule(reference_qc, self.backend) self.assertEqual(schedule, reference)
def test_u1(self): """Test u1 gate.""" with pulse.build(self.backend) as schedule: with pulse.transpiler_settings(layout_method="trivial"): pulse.u1(np.pi / 2, 0) reference_qc = circuit.QuantumCircuit(1) reference_qc.append(circuit.library.U1Gate(np.pi / 2), [0]) reference = compiler.schedule(reference_qc, self.backend) self.assertScheduleEqual(schedule, reference)
def test_subroutine_not_transpiled(self): """Test called circuit is frozen as a subroutine.""" subprogram = circuit.QuantumCircuit(1) subprogram.x(0) transpiler_settings = {"optimization_level": 2} with pulse.build(self.backend, default_transpiler_settings=transpiler_settings) as schedule: pulse.call(subprogram) pulse.call(subprogram) self.assertNotEqual(len(target_qobj_transform(schedule).instructions), 0)
def test_transpile_with_different_qubit(self): """Test transpile with qubit without custom gate.""" backend = FakeAthens() backend.defaults().instruction_schedule_map.add("sx", (0,), self.custom_sx_q0) qc = circuit.QuantumCircuit(1) qc.sx(0) qc.measure_all() transpiled_qc = transpile(qc, backend, initial_layout=[3]) self.assertDictEqual(transpiled_qc.calibrations, {})
def test_call_circuit_with_cregs(self): """Test calling of circuit wiht classical registers.""" qc = circuit.QuantumCircuit(2, 2) qc.h(0) qc.cx(0, 1) qc.measure([0, 1], [0, 1]) with pulse.build(self.backend) as schedule: pulse.call(qc) reference_qc = compiler.transpile(qc, self.backend) reference = compiler.schedule(reference_qc, self.backend) self.assertEqual(schedule, reference)
def test_measure(self): """Test pulse measurement macro against circuit measurement and ensure agreement.""" with pulse.build(self.backend) as schedule: with pulse.align_sequential(): pulse.x(0) pulse.measure(0) reference_qc = circuit.QuantumCircuit(1, 1) reference_qc.x(0) reference_qc.measure(0, 0) reference_qc = compiler.transpile(reference_qc, self.backend) reference = compiler.schedule(reference_qc, self.backend) self.assertEqual(schedule, reference)
def test_transpile_with_bare_backend(self): """Test transpile without custom calibrations.""" backend = FakeAthens() qc = circuit.QuantumCircuit(2) qc.sx(0) qc.x(0) qc.rz(0, 0) qc.sx(1) qc.measure_all() transpiled_qc = transpile(qc, backend, initial_layout=[0, 1]) ref_calibration = {} self.assertDictEqual(transpiled_qc.calibrations, ref_calibration)
def test_call_circuit(self): """Test calling circuit instruction.""" inst_map = self.inst_map reference = inst_map.get('u1', (0,), 0.0) u1_qc = circuit.QuantumCircuit(2) u1_qc.u1(0.0, 0) transpiler_settings = {'optimization_level': 0} with pulse.build(self.backend, default_transpiler_settings=transpiler_settings ) as schedule: with pulse.align_right(): builder.call_circuit(u1_qc) self.assertEqual(schedule, reference)
def test_scheduler_settings(self): """Test the circuit scheduler settings context.""" inst_map = pulse.InstructionScheduleMap() d0 = pulse.DriveChannel(0) test_x_sched = pulse.Schedule() test_x_sched += instructions.Delay(10, d0) inst_map.add('x', (0,), test_x_sched) x_qc = circuit.QuantumCircuit(2) x_qc.x(0) with pulse.build(backend=self.backend) as schedule: with pulse.transpiler_settings(basis_gates=['x']): with pulse.circuit_scheduler_settings(inst_map=inst_map): builder.call_circuit(x_qc) self.assertEqual(schedule, test_x_sched)
def test_call_circuit(self): """Test calling circuit instruction.""" inst_map = self.inst_map reference = inst_map.get("u1", (0,), 0.0) ref_sched = pulse.Schedule() ref_sched += pulse.instructions.Call(reference) u1_qc = circuit.QuantumCircuit(2) u1_qc.append(circuit.library.U1Gate(0.0), [0]) transpiler_settings = {"optimization_level": 0} with pulse.build(self.backend, default_transpiler_settings=transpiler_settings) as schedule: with pulse.align_right(): builder.call(u1_qc) self.assertScheduleEqual(schedule, ref_sched)
def test_transpiler_settings(self): """Test the transpiler settings context. Tests that two cx gates are optimized away with higher optimization level. """ twice_cx_qc = circuit.QuantumCircuit(2) twice_cx_qc.cx(0, 1) twice_cx_qc.cx(0, 1) with pulse.build(self.backend) as schedule: with pulse.transpiler_settings(optimization_level=0): builder.call_circuit(twice_cx_qc) self.assertNotEqual(len(schedule.instructions), 0) with pulse.build(self.backend) as schedule: with pulse.transpiler_settings(optimization_level=3): builder.call_circuit(twice_cx_qc) self.assertEqual(len(schedule.instructions), 0)
def test_transpile_with_custom_basis_gate(self): """Test transpile with custom calibrations.""" backend = FakeAthens() backend.defaults().instruction_schedule_map.add("sx", (0,), self.custom_sx_q0) backend.defaults().instruction_schedule_map.add("sx", (1,), self.custom_sx_q1) qc = circuit.QuantumCircuit(2) qc.sx(0) qc.x(0) qc.rz(0, 0) qc.sx(1) qc.measure_all() transpiled_qc = transpile(qc, backend, initial_layout=[0, 1]) ref_calibration = { "sx": { ((0,), ()): self.custom_sx_q0, ((1,), ()): self.custom_sx_q1, } } self.assertDictEqual(transpiled_qc.calibrations, ref_calibration)
def test_transpile_with_multiple_circuits(self): """Test transpile with multiple circuits with custom gate.""" backend = FakeAthens() backend.defaults().instruction_schedule_map.add( "my_gate", (0,), self.my_gate_q0, arguments=["P0"] ) params = [0.0, 1.0, 2.0, 3.0] circs = [] for param in params: qc = circuit.QuantumCircuit(1) qc.append(circuit.Gate("my_gate", 1, [param]), [0]) circs.append(qc) transpiled_qcs = transpile(circs, backend, basis_gates=["my_gate"], initial_layout=[0]) for param, transpiled_qc in zip(params, transpiled_qcs): my_gate_q0_x = self.my_gate_q0.assign_parameters( {self.sched_param: param}, inplace=False ) ref_calibration = {"my_gate": {((0,), (param,)): my_gate_q0_x}} self.assertDictEqual(transpiled_qc.calibrations, ref_calibration)
def test_complex_build(self): """Test a general program build with nested contexts, circuits and macros.""" d0 = pulse.DriveChannel(0) d1 = pulse.DriveChannel(1) d2 = pulse.DriveChannel(2) delay_dur = 19 short_dur = 31 long_dur = 101 with pulse.build(self.backend) as schedule: with pulse.align_sequential(): pulse.delay(delay_dur, d0) pulse.u2(0, pi/2, 1) with pulse.align_right(): pulse.play(library.Constant(short_dur, 0.1), d1) pulse.play(library.Constant(long_dur, 0.1), d2) pulse.u2(0, pi/2, 1) with pulse.align_left(): pulse.u2(0, pi/2, 0) pulse.u2(0, pi/2, 1) pulse.u2(0, pi/2, 0) pulse.measure(0) # prepare and schedule circuits that will be used. single_u2_qc = circuit.QuantumCircuit(2) single_u2_qc.u2(0, pi/2, 1) single_u2_qc = compiler.transpile(single_u2_qc, self.backend) single_u2_sched = compiler.schedule(single_u2_qc, self.backend) # sequential context sequential_reference = pulse.Schedule() sequential_reference += instructions.Delay(delay_dur, d0) sequential_reference.insert(delay_dur, single_u2_sched, inplace=True) # align right align_right_reference = pulse.Schedule() align_right_reference += pulse.Play( library.Constant(long_dur, 0.1), d2) align_right_reference.insert(long_dur-single_u2_sched.duration, single_u2_sched, inplace=True) align_right_reference.insert( long_dur-single_u2_sched.duration-short_dur, pulse.Play(library.Constant(short_dur, 0.1), d1), inplace=True) # align left triple_u2_qc = circuit.QuantumCircuit(2) triple_u2_qc.u2(0, pi/2, 0) triple_u2_qc.u2(0, pi/2, 1) triple_u2_qc.u2(0, pi/2, 0) triple_u2_qc = compiler.transpile(triple_u2_qc, self.backend) align_left_reference = compiler.schedule( triple_u2_qc, self.backend, method='alap') # measurement measure_reference = macros.measure(qubits=[0], inst_map=self.inst_map, meas_map=self.configuration.meas_map) reference = pulse.Schedule() reference += sequential_reference # Insert so that the long pulse on d2 occurs as early as possible # without an overval on d1. insert_time = (reference.ch_stop_time(d1) - align_right_reference.ch_start_time(d1)) reference.insert(insert_time, align_right_reference, inplace=True) reference.insert(reference.ch_stop_time(d0, d1), align_left_reference, inplace=True) reference += measure_reference self.assertEqual(schedule, reference)
if __name__ == "__main__": compilation_text = "" I = ls.PauliOperator.I X = ls.PauliOperator.X Y = ls.PauliOperator.Y Z = ls.PauliOperator.Z # Construct in parallel a quiskit circuit to print and an equivalent pauli circuit to execute # The construtction of the pauli rotation circuit get's kick started with gates from the other circuit, # so it is initialized below crz = qkcirc.ClassicalRegister(1) crx = qkcirc.ClassicalRegister(1) qreg = qkcirc.QuantumRegister(3) qiskit_circ = qkcirc.QuantumCircuit(qreg, crx, crz) # Entangle a Bell pair. 1 is Alice's 2 is Bob's qiskit_circ.h(1) qiskit_circ.cx(1, 2) qiskit_circ.barrier() # Create a non trivial state in q0, the one Alice wants to send to Bob. qiskit_circ.h(0) qiskit_circ.t(0) qiskit_circ.h(0) qiskit_circ.barrier() # Alice's part of the teleportation qiskit_circ.cx(0, 1) qiskit_circ.h(0)