def test_scheduling_with_calibration(self): """Test if calibrated instruction can update node duration.""" qc = QuantumCircuit(2) qc.x(0) qc.cx(0, 1) qc.x(1) qc.cx(0, 1) xsched = Schedule(Play(Constant(300, 0.1), DriveChannel(0))) qc.add_calibration("x", (0, ), xsched) durations = InstructionDurations([("x", None, 160), ("cx", None, 600)]) pm = PassManager([ASAPScheduleAnalysis(durations), PadDelay()]) scheduled = pm.run(qc) expected = QuantumCircuit(2) expected.x(0) expected.delay(300, 1) expected.cx(0, 1) expected.x(1) expected.delay(160, 0) expected.cx(0, 1) expected.add_calibration("x", (0, ), xsched) self.assertEqual(expected, scheduled)
def test_calibrations_with_swap_and_reset(self): """Test calibrations annotations See https://github.com/Qiskit/qiskit-terra/issues/5920 """ circuit = QuantumCircuit(2, 2) circuit.swap(0, 1) circuit.reset(0) from qiskit import pulse with pulse.build(name="swap") as swap_q01: pulse.play(pulse.library.Gaussian(duration=128, amp=0.1, sigma=16), pulse.DriveChannel(1)) circuit.add_calibration("swap", [0, 1], swap_q01) with pulse.build(name="reset") as reset_q0: pulse.play(pulse.library.Gaussian(duration=128, amp=0.1, sigma=16), pulse.DriveChannel(1)) circuit.add_calibration("reset", [0], reset_q0) self.circuit_drawer(circuit, filename="calibrations_with_swap_and_reset.png")
def test_calibrations_with_control_gates(self): """Test calibrations annotations See https://github.com/Qiskit/qiskit-terra/issues/5920 """ circuit = QuantumCircuit(2, 2) circuit.cx(0, 1) circuit.ch(0, 1) from qiskit import pulse with pulse.build(name="cnot") as cx_q01: pulse.play(pulse.library.Gaussian(duration=128, amp=0.1, sigma=16), pulse.DriveChannel(1)) circuit.add_calibration("cx", [0, 1], cx_q01) with pulse.build(name="ch") as ch_q01: pulse.play(pulse.library.Gaussian(duration=128, amp=0.1, sigma=16), pulse.DriveChannel(1)) circuit.add_calibration("ch", [0, 1], ch_q01) self.circuit_drawer(circuit, filename="calibrations_with_control_gates.png")
def test_transpiled_custom_gates_calibration(self): """Test if transpiled calibrations is equal to custom gates circuit calibrations.""" custom_180 = Gate("mycustom", 1, [3.14]) custom_90 = Gate("mycustom", 1, [1.57]) circ = QuantumCircuit(2) circ.append(custom_180, [0]) circ.append(custom_90, [1]) with pulse.build() as q0_x180: pulse.play(pulse.library.Gaussian(20, 1.0, 3.0), pulse.DriveChannel(0)) with pulse.build() as q1_y90: pulse.play(pulse.library.Gaussian(20, -1.0, 3.0), pulse.DriveChannel(1)) # Add calibration circ.add_calibration(custom_180, [0], q0_x180) circ.add_calibration(custom_90, [1], q1_y90) backend = FakeAlmaden() # TODO: Remove L783-L784 in the next PR transpiled_circuit = transpile( circ, backend=backend, basis_gates=backend.configuration().basis_gates + list(circ.calibrations.keys()), ) self.assertEqual(transpiled_circuit.calibrations, circ.calibrations)
def test_calibrations_basis_gates(self): """Check if the calibrations for basis gates provided are added correctly.""" circ = QuantumCircuit(2) with pulse.build() as q0_x180: pulse.play(pulse.library.Gaussian(20, 1.0, 3.0), pulse.DriveChannel(0)) with pulse.build() as q1_y90: pulse.play(pulse.library.Gaussian(20, -1.0, 3.0), pulse.DriveChannel(1)) # Add calibration circ.add_calibration(RXGate(3.14), [0], q0_x180) circ.add_calibration(RYGate(1.57), [1], q1_y90) self.assertEqual(set(circ.calibrations.keys()), {"rx", "ry"}) self.assertEqual(set(circ.calibrations["rx"].keys()), {((0, ), (3.14, ))}) self.assertEqual(set(circ.calibrations["ry"].keys()), {((1, ), (1.57, ))}) self.assertEqual( circ.calibrations["rx"][((0, ), (3.14, ))].instructions, q0_x180.instructions) self.assertEqual( circ.calibrations["ry"][((1, ), (1.57, ))].instructions, q1_y90.instructions)
def test_copy_empty_like_circuit(self): """Test copy_empty_like method makes a clear copy.""" qr = QuantumRegister(2) cr = ClassicalRegister(2) qc = QuantumCircuit(qr, cr, global_phase=1.0, name="qc", metadata={"key": "value"}) qc.h(qr[0]) qc.measure(qr[0], cr[0]) qc.measure(qr[1], cr[1]) sched = Schedule(Play(Gaussian(160, 0.1, 40), DriveChannel(0))) qc.add_calibration("h", [0, 1], sched) copied = qc.copy_empty_like() qc.clear() self.assertEqual(qc, copied) self.assertEqual(qc.global_phase, copied.global_phase) self.assertEqual(qc.name, copied.name) self.assertEqual(qc.metadata, copied.metadata) self.assertEqual(qc.calibrations, copied.calibrations) copied = qc.copy_empty_like("copy") self.assertEqual(copied.name, "copy")
def test_transpiled_custom_gates_calibration(self): """Test if transpiled calibrations is equal to custom gates circuit calibrations.""" custom_180 = Gate("mycustom", 1, [3.14]) custom_90 = Gate("mycustom", 1, [1.57]) circ = QuantumCircuit(2) circ.append(custom_180, [0]) circ.append(custom_90, [1]) with pulse.build() as q0_x180: pulse.play(pulse.library.Gaussian(20, 1.0, 3.0), pulse.DriveChannel(0)) with pulse.build() as q1_y90: pulse.play(pulse.library.Gaussian(20, -1.0, 3.0), pulse.DriveChannel(1)) # Add calibration circ.add_calibration(custom_180, [0], q0_x180) circ.add_calibration(custom_90, [1], q1_y90) backend = FakeAlmaden() transpiled_circuit = transpile( circ, backend=backend, ) self.assertEqual(transpiled_circuit.calibrations, circ.calibrations) self.assertEqual(list(transpiled_circuit.count_ops().keys()), ['mycustom']) self.assertEqual(list(transpiled_circuit.count_ops().values()), [2])
def test_calibrations_with_rzz_and_rxx(self): """Test calibrations annotations See https://github.com/Qiskit/qiskit-terra/issues/5920 """ circuit = QuantumCircuit(2, 2) circuit.rzz(pi, 0, 1) circuit.rxx(pi, 0, 1) from qiskit import pulse with pulse.build(name="rzz") as rzz_q01: pulse.play( pulse.library.Gaussian(duration=128, amp=0.1, sigma=16), pulse.DriveChannel(1) ) circuit.add_calibration("rzz", [0, 1], rzz_q01) with pulse.build(name="rxx") as rxx_q01: pulse.play( pulse.library.Gaussian(duration=128, amp=0.1, sigma=16), pulse.DriveChannel(1) ) circuit.add_calibration("rxx", [0, 1], rxx_q01) self.circuit_drawer(circuit, filename="calibrations_with_rzz_and_rxx.png")
def circuits(self): sub_circuits = [] sub_qubits = [] sub_size = [] num_qubits = 0 # Generate data for combination for expr in self._experiments: # Add subcircuits circs = expr.circuits() sub_circuits.append(circs) sub_size.append(len(circs)) # Add sub qubits qubits = list(range(num_qubits, num_qubits + expr.num_qubits)) sub_qubits.append(qubits) num_qubits += expr.num_qubits # Generate empty joint circuits num_circuits = max(sub_size) joint_circuits = [] for circ_idx in range(num_circuits): # Create joint circuit circuit = QuantumCircuit(self.num_qubits, name=f"parallel_exp_{circ_idx}") circuit.metadata = { "experiment_type": self._type, "composite_index": [], "composite_metadata": [], "composite_qubits": [], "composite_clbits": [], } for exp_idx in range(self._num_experiments): if circ_idx < sub_size[exp_idx]: # Add subcircuits to joint circuit sub_circ = sub_circuits[exp_idx][circ_idx] num_clbits = circuit.num_clbits qubits = sub_qubits[exp_idx] clbits = list(range(num_clbits, num_clbits + sub_circ.num_clbits)) circuit.add_register(ClassicalRegister(sub_circ.num_clbits)) circuit.append(sub_circ, qubits, clbits) # Add subcircuit metadata circuit.metadata["composite_index"].append(exp_idx) circuit.metadata["composite_metadata"].append(sub_circ.metadata) circuit.metadata["composite_qubits"].append(qubits) circuit.metadata["composite_clbits"].append(clbits) # Add the calibrations for gate, cals in sub_circ.calibrations.items(): for key, sched in cals.items(): circuit.add_calibration( gate, qubits=key[0], schedule=sched, params=key[1] ) # Add joint circuit to returned list joint_circuits.append(circuit.decompose()) return joint_circuits
def test_scheduler_with_params_not_bound(self): """Test scheduler with parameters defined but not bound""" x = Parameter("amp") qc = QuantumCircuit(2) qc.append(Gate("pulse_gate", 1, [x]), [0]) with build() as expected_schedule: play(Gaussian(duration=160, amp=x, sigma=40), DriveChannel(0)) qc.add_calibration(gate="pulse_gate", qubits=[0], schedule=expected_schedule, params=[x]) sched = schedule(qc, self.backend) self.assertEqual(sched, transforms.target_qobj_transform(expected_schedule))
def test_scheduler_with_params_bound(self): """Test scheduler with parameters defined and bound""" x = Parameter("x") qc = QuantumCircuit(2) qc.append(Gate("pulse_gate", 1, [x]), [0]) expected_schedule = Schedule() qc.add_calibration(gate="pulse_gate", qubits=[0], schedule=expected_schedule, params=[x]) qc = qc.assign_parameters({x: 1}) sched = schedule(qc, self.backend) self.assertEqual(sched, expected_schedule)
def test_calibrations(self): """Test that calibrations are properly copied over.""" circuit_in = QuantumCircuit(1) circuit_in.add_calibration('h', [0], None) self.assertEqual(len(circuit_in.calibrations), 1) dag_dependency = circuit_to_dagdependency(circuit_in) self.assertEqual(len(dag_dependency.calibrations), 1) circuit_out = dagdependency_to_circuit(dag_dependency) self.assertEqual(len(circuit_out.calibrations), 1)
def test_calibrations_no_params(self): """Check calibrations if the no params is provided with just gate name.""" circ = QuantumCircuit(3) with pulse.build() as q0_x180: pulse.play(pulse.library.Gaussian(20, 1.0, 3.0), pulse.DriveChannel(0)) circ.add_calibration("h", [0], q0_x180) self.assertEqual(set(circ.calibrations.keys()), {"h"}) self.assertEqual(set(circ.calibrations["h"].keys()), {((0,), ())}) self.assertEqual(circ.calibrations["h"][((0,), ())].instructions, q0_x180.instructions)
def test_inst_durations_from_calibrations(self): """Test that circuit calibrations can be used instead of explicitly supplying inst_durations. """ qc = QuantumCircuit(2) qc.append(Gate('custom', 1, []), [0]) with pulse.build() as cal: pulse.play(pulse.library.Gaussian(20, 1.0, 3.0), pulse.DriveChannel(0)) qc.add_calibration('custom', [0], cal) out = transpile(qc, scheduling_method='alap') self.assertEqual(out.duration, cal.duration)
def test_calibrations_custom_gates(self): """Check if the calibrations for custom gates with params provided are added correctly.""" circ = QuantumCircuit(3) with pulse.build() as q0_x180: pulse.play(pulse.library.Gaussian(20, 1.0, 3.0), pulse.DriveChannel(0)) # Add calibrations with a custom gate 'rxt' circ.add_calibration('rxt', [0], q0_x180, params=[1.57, 3.14, 4.71]) self.assertEqual(set(circ.calibrations.keys()), {'rxt'}) self.assertEqual(set(circ.calibrations['rxt'].keys()), {((0,), (1.57, 3.14, 4.71))}) self.assertEqual(circ.calibrations['rxt'][((0,), (1.57, 3.14, 4.71))].instructions, q0_x180.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_valid_pulse_duration(self): """No error raises if valid calibration is provided.""" # this is valid duration pulse custom_gate = pulse.Schedule(name="custom_x_gate") custom_gate.insert( 0, pulse.Play(pulse.Constant(160, 0.1), pulse.DriveChannel(0)), inplace=True ) circuit = QuantumCircuit(1) circuit.x(0) circuit.add_calibration("x", qubits=(0,), schedule=custom_gate) # just not raise an error self.pulse_gate_validation_pass(circuit)
def test_pulse_gates(self): """Test scheduling calibrated pulse gates.""" q = QuantumRegister(2) qc = QuantumCircuit(q) qc.append(U2Gate(0, 0), [q[0]]) qc.barrier(q[0], q[1]) qc.append(U2Gate(0, 0), [q[1]]) qc.add_calibration('u2', [0], Schedule(Play(Gaussian(28, 0.2, 4), DriveChannel(0))), [0, 0]) qc.add_calibration('u2', [1], Schedule(Play(Gaussian(28, 0.2, 4), DriveChannel(1))), [0, 0]) sched = schedule(qc, self.backend) expected = Schedule( Play(Gaussian(28, 0.2, 4), DriveChannel(0)), (28, Schedule(Play(Gaussian(28, 0.2, 4), DriveChannel(1))))) self.assertEqual(sched.instructions, expected.instructions)
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_transpile_calibrated_custom_gate_on_diff_qubit(self): """Test if the custom, non calibrated gate raises QiskitError.""" custom_180 = Gate("mycustom", 1, [3.14]) circ = QuantumCircuit(2) circ.append(custom_180, [0]) with pulse.build() as q0_x180: pulse.play(pulse.library.Gaussian(20, 1.0, 3.0), pulse.DriveChannel(0)) # Add calibration circ.add_calibration(custom_180, [1], q0_x180) backend = FakeAlmaden() with self.assertRaises(QiskitError): transpile(circ, backend=backend)
def test_short_pulse_duration(self): """Kill pass manager if invalid pulse gate is found.""" # this is invalid duration pulse # this will cause backend error since this doesn't fit with waveform memory chunk. custom_gate = pulse.Schedule(name="custom_x_gate") custom_gate.insert( 0, pulse.Play(pulse.Constant(32, 0.1), pulse.DriveChannel(0)), inplace=True ) circuit = QuantumCircuit(1) circuit.x(0) circuit.add_calibration("x", qubits=(0,), schedule=custom_gate) with self.assertRaises(TranspilerError): self.pulse_gate_validation_pass(circuit)
def test_calibrations(self): """Test calibrations annotations See https://github.com/Qiskit/qiskit-terra/issues/5920 """ circuit = QuantumCircuit(2, 2) circuit.h(0) from qiskit import pulse with pulse.build(name="hadamard") as h_q0: pulse.play(pulse.library.Gaussian(duration=128, amp=0.1, sigma=16), pulse.DriveChannel(0)) circuit.add_calibration("h", [0], h_q0) self.circuit_drawer(circuit, filename="calibrations.png")
def test_valid_pulse_duration(self): """No error raises if valid calibration is provided.""" # this is valid duration pulse custom_gate = pulse.Schedule(name="custom_x_gate") custom_gate.insert(0, pulse.Play(pulse.Constant(160, 0.1), pulse.DriveChannel(0)), inplace=True) circuit = QuantumCircuit(1) circuit.x(0) circuit.add_calibration("x", qubits=(0, ), schedule=custom_gate) # just not raise an error pm = PassManager(ValidatePulseGates(granularity=16, min_length=64)) pm.run(circuit)
def test_transpiled_basis_gates_calibrations(self): """Test if the transpiled calibrations is equal to basis gates circuit calibrations.""" circ = QuantumCircuit(2) circ.h(0) with pulse.build() as q0_x180: pulse.play(pulse.library.Gaussian(20, 1.0, 3.0), pulse.DriveChannel(0)) # Add calibration circ.add_calibration("h", [0], q0_x180) backend = FakeAlmaden() transpiled_circuit = transpile( circ, backend=backend, ) self.assertEqual(transpiled_circuit.calibrations, circ.calibrations)
def test_invalid_pulse_duration(self): """Kill pass manager if invalid pulse gate is found.""" # this is invalid duration pulse # this will cause backend error since this doesn't fit with waveform memory chunk. custom_gate = pulse.Schedule(name="custom_x_gate") custom_gate.insert(0, pulse.Play(pulse.Constant(100, 0.1), pulse.DriveChannel(0)), inplace=True) circuit = QuantumCircuit(1) circuit.x(0) circuit.add_calibration("x", qubits=(0, ), schedule=custom_gate) pm = PassManager(ValidatePulseGates(granularity=16, min_length=64)) with self.assertRaises(TranspilerError): pm.run(circuit)
def test_transpile_subset_of_calibrated_gates(self): """Test transpiling a circuit with both basis gate (not-calibrated) and a calibrated gate on different qubits.""" x_180 = Gate('mycustom', 1, [3.14]) circ = QuantumCircuit(2) circ.h(0) circ.append(x_180, [0]) circ.h(1) with pulse.build() as q0_x180: pulse.play(pulse.library.Gaussian(20, 1.0, 3.0), pulse.DriveChannel(0)) circ.add_calibration(x_180, [0], q0_x180) circ.add_calibration('h', [1], q0_x180) # 'h' is calibrated on qubit 1 transpiled_circ = transpile(circ, FakeAlmaden()) self.assertEqual(set(transpiled_circ.count_ops().keys()), {'u2', 'mycustom', 'h'})
def test_parameterized_calibrations_transpile(self): """Check that gates can be matched to their calibrations before and after parameter assignment.""" tau = Parameter('tau') circ = QuantumCircuit(3, 3) circ.append(Gate('rxt', 1, [2*3.14*tau]), [0]) def q0_rxt(tau): with pulse.build() as q0_rxt: pulse.play(pulse.library.Gaussian(20, 0.4*tau, 3.0), pulse.DriveChannel(0)) return q0_rxt circ.add_calibration('rxt', [0], q0_rxt(tau), [2*3.14*tau]) transpiled_circ = transpile(circ, FakeAlmaden()) self.assertEqual(set(transpiled_circ.count_ops().keys()), {'rxt'}) circ = circ.assign_parameters({tau: 1}) transpiled_circ = transpile(circ, FakeAlmaden()) self.assertEqual(set(transpiled_circ.count_ops().keys()), {'rxt'})
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 test_short_pulse_duration_multiple_pulse(self): """Kill pass manager if invalid pulse gate is found.""" # this is invalid duration pulse # however total gate schedule length is 64, which accidentally satisfies the constraints # this should fail in the validation custom_gate = pulse.Schedule(name="custom_x_gate") custom_gate.insert( 0, pulse.Play(pulse.Constant(32, 0.1), pulse.DriveChannel(0)), inplace=True ) custom_gate.insert( 32, pulse.Play(pulse.Constant(32, 0.1), pulse.DriveChannel(0)), inplace=True ) circuit = QuantumCircuit(1) circuit.x(0) circuit.add_calibration("x", qubits=(0,), schedule=custom_gate) with self.assertRaises(TranspilerError): self.pulse_gate_validation_pass(circuit)
def test_transpile_calibrated_nonbasis_gate_on_diff_qubit(self): """Test if the non-basis gates are transpiled if they are on different qubit that is not calibrated.""" circ = QuantumCircuit(2) circ.h(0) circ.h(1) with pulse.build() as q0_x180: pulse.play(pulse.library.Gaussian(20, 1.0, 3.0), pulse.DriveChannel(0)) # Add calibration circ.add_calibration("h", [1], q0_x180) backend = FakeAlmaden() transpiled_circuit = transpile( circ, backend=backend, ) self.assertEqual(transpiled_circuit.calibrations, circ.calibrations) self.assertEqual(set(transpiled_circuit.count_ops().keys()), {'u2', 'h'})