def duplicate_instruction(inst): """Create a fresh instruction from an input instruction.""" if issubclass(inst.__class__, Instruction) and inst.__class__ not in [ Instruction, Gate]: if inst.name == 'barrier': new_inst = inst.__class__(inst.num_qubits) elif inst.name == 'initialize': params = getattr(inst, 'params', []) new_inst = inst.__class__(params) elif inst.name == 'snapshot': label = inst.params[0] snap_type = inst.params[1] new_inst = inst.__class__(inst.num_qubits, inst.num_clbits, label, snap_type) else: params = getattr(inst, 'params', []) new_inst = inst.__class__(*params) else: if isinstance(inst, Gate): new_inst = Gate(inst.name, inst.num_qubits, inst.params) else: new_inst = Instruction(name=inst.name, num_qubits=inst.num_qubits, num_clbits=inst.num_clbits, params=inst.params) new_inst.definition = inst.definition return new_inst
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_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 _create_op(self, name, params): if name in self.standard_extension: op = self.standard_extension[name](*params) elif name in self.gates: op = Gate(name=name, num_qubits=self.gates[name]['n_bits'], params=params) if not self.gates[name]['opaque']: # call a custom gate (otherwise, opaque) op.definition = self._gate_rules_to_qiskit_circuit(self.gates[name], params=params) else: raise QiskitError("unknown operation for ast node name %s" % name) return op
def controlled_rotation_generic(): A = Gate('A', 1, []) B = Gate('B', 1, []) C = Gate('C', 1, []) alpha = 1 # arbitrarily define alpha to allow drawing of circuit qc = QuantumCircuit(2) qc.append(C, [1]) qc.cz(0, 1) qc.append(B, [1]) qc.cz(0, 1) qc.append(A, [1]) qc.p(alpha, 0) print(qc.draw())
def inverse(self): """Return the inverse. Note that the resulting Gate object has an empty ``params`` property. """ inverse_gate = Gate( name=self.name + "_dg", num_qubits=self.num_qubits, params=[]) # removing the params because arrays are deprecated definition = QuantumCircuit(*self.definition.qregs) for inst in reversed(self._definition): definition._append( inst.replace(operation=inst.operation.inverse())) inverse_gate.definition = definition return inverse_gate
def inverse(self): """Return the inverse. Note that the resulting Gate object has an empty ``params`` property. """ inverse_gate = Gate( name=self.name + "_dg", num_qubits=self.num_qubits, params=[] ) # removing the params because arrays are deprecated inverse_gate.definition = QuantumCircuit(*self.definition.qregs) inverse_gate.definition._data = [ (inst.inverse(), qargs, []) for inst, qargs, _ in reversed(self._definition) ] return inverse_gate
def test_can_append_to_quantum_circuit(self): """Test that we can add various objects with Operation interface to a Quantum Circuit.""" qc = QuantumCircuit(6, 1) qc.append(XGate(), [2]) qc.append(Barrier(3), [1, 2, 4]) qc.append(CXGate(), [0, 1]) qc.append(Measure(), [1], [0]) qc.append(Reset(), [0]) qc.cx(3, 4) qc.append(Gate("some_gate", 3, []), [1, 2, 3]) qc.append(Initialize([0.5, 0.5, 0.5, 0.5]), [4, 5]) qc.append(Isometry(np.eye(4, 4), 0, 0), [3, 4]) qc.append(Pauli("II"), [0, 1]) # Appending Clifford circ1 = QuantumCircuit(2) circ1.h(1) circ1.cx(0, 1) qc.append(Clifford(circ1), [0, 1]) # Appending CNOTDihedral circ2 = QuantumCircuit(2) circ2.t(0) circ2.x(0) circ2.t(1) qc.append(CNOTDihedral(circ2), [2, 3]) # If we got to here, we have successfully appended everything to qc self.assertIsInstance(qc, QuantumCircuit)
def __init__( self, qubit: int, calibrations: Calibrations, schedule_name: str, backend: Optional[Backend] = None, cal_parameter_name: Optional[str] = "β", auto_update: bool = True, ): r"""see class :class:`FineDrag` for details. Note that this class implicitly assumes that the target angle of the gate is :math:`\pi` as seen from the default experiment options. Args: qubit: The qubit for which to run the fine drag calibration. calibrations: The calibrations instance with the schedules. schedule_name: The name of the schedule to calibrate. backend: Optional, the backend to run the experiment on. cal_parameter_name: The name of the parameter in the schedule to update. auto_update: Whether or not to automatically update the calibrations. By default this variable is set to True. """ super().__init__( calibrations, qubit, Gate(name=schedule_name, num_qubits=1, params=[]), schedule_name=schedule_name, backend=backend, cal_parameter_name=cal_parameter_name, auto_update=auto_update, ) self.set_transpile_options(basis_gates=["sx", schedule_name, "rz"])
def test_opaque_gate(self): """ Test parse an opaque gate See https://github.com/Qiskit/qiskit-terra/issues/1566. """ qasm_string = ( "\n".join( [ "OPENQASM 2.0;", 'include "qelib1.inc";', "opaque my_gate(theta,phi,lambda) a,b;", "qreg q[3];", "my_gate(1,2,3) q[1],q[2];", ] ) + "\n" ) circuit = QuantumCircuit.from_qasm_str(qasm_string) qr = QuantumRegister(3, "q") expected = QuantumCircuit(qr) expected.append(Gate(name="my_gate", num_qubits=2, params=[1, 2, 3]), [qr[1], qr[2]]) self.assertEqual(circuit, expected)
def setUpClass(cls): super().setUpClass() class_list = Gate.__subclasses__() + ControlledGate.__subclasses__() exclude = { "ControlledGate", "DiagonalGate", "UCGate", "MCGupDiag", "MCU1Gate", "UnitaryGate", "HamiltonianGate", "MCPhaseGate", "UCPauliRotGate", "SingleQubitUnitary", "MCXGate", "VariadicZeroParamGate", "ClassicalFunction", "ClassicalElement", "StatePreparation", "LinearFunction", } cls._gate_classes = [] for aclass in class_list: if aclass.__name__ not in exclude: cls._gate_classes.append(aclass)
def _create_dag_op(self, name, params, qargs): """ Create a DAG node out of a parsed AST op node. Args: name (str): operation name to apply to the dag. params (list): op parameters qargs (list(Qubit)): qubits to attach to Raises: QiskitError: if encountering a non-basis opaque gate """ if name in self.standard_extension: op = self.standard_extension[name](*params) elif name in self.gates: if self.gates[name]['opaque']: # call an opaque gate op = Gate(name=name, num_qubits=self.gates[name]['n_bits'], params=params) else: # call a custom gate raise QiskitError( 'Custom non-opaque gates are not supported by as_to_dag module' ) else: raise QiskitError("unknown operation for ast node name %s" % name) self.dag.apply_operation_back(op, qargs, [], condition=self.condition)
def __init__( self, qubit: int, calibrations: Calibrations, schedule_name: str, backend: Optional[Backend] = None, cal_parameter_name: Optional[str] = "amp", auto_update: bool = True, ): """see class :class:`FineAmplitude` for details. Args: qubit: The qubit for which to run the fine amplitude calibration. calibrations: The calibrations instance with the schedules. schedule_name: The name of the schedule to calibrate. backend: Optional, the backend to run the experiment on. cal_parameter_name: The name of the parameter in the schedule to update. auto_update: Whether or not to automatically update the calibrations. By default this variable is set to True. """ super().__init__( calibrations, qubit, Gate(name=schedule_name, num_qubits=1, params=[]), schedule_name=schedule_name, backend=backend, cal_parameter_name=cal_parameter_name, auto_update=auto_update, ) self.set_transpile_options(inst_map=calibrations.default_inst_map)
def test_single_circuit_delay_calibrations(self): """Test that disassembler parses delay instruction back to delay gate.""" qc = QuantumCircuit(2) qc.append(Gate("test", 1, []), [0]) test_sched = pulse.Delay(64, pulse.DriveChannel(0)) + pulse.Delay( 160, pulse.DriveChannel(0) ) qc.add_calibration("test", [0], test_sched) qobj = assemble(qc, FakeOpenPulse2Q()) output_circuits, _, _ = disassemble(qobj) self.assertEqual(len(qc.calibrations), len(output_circuits[0].calibrations)) self.assertEqual(qc.calibrations.keys(), output_circuits[0].calibrations.keys()) self.assertTrue( all( qc_cal.keys() == out_qc_cal.keys() for qc_cal, out_qc_cal in zip( qc.calibrations.values(), output_circuits[0].calibrations.values() ) ) ) self.assertEqual( qc.calibrations["test"][((0,), ())], output_circuits[0].calibrations["test"][((0,), ())] )
def cz_gate(self, q1, q2, theta: float, phase_delta: float = 0., amp_increase: float = 0.): """ Creates a CZ and inserts the schedule into the instruction schedule map of the backend to which the builder is tied. Args: q1: first qubit. q2: second qubit. theta: Rotation angle of the CZ gate. phase_delta: Multiplies the CR90_u pulses samples by np.exp(1.0j*phase_delta). amp_increase: Multiplies the CR90_u samples by (1. + amp_increase). """ cz_name = self.name(theta, phase_delta=phase_delta, amp_increase=amp_increase) if not self._inst_map.has(cz_name, (q1, q2)): cz_schedule = self.build_cz_schedule(q1, q2, theta, phase_delta=phase_delta, amp_increase=amp_increase) self._inst_map.add(cz_name, (q1, q2), cz_schedule) self._inst_map.add(cz_name, (q2, q1), cz_schedule) if cz_name not in self._config.basis_gates: self._config.basis_gates.append(cz_name) return Gate(cz_name, 2, [])
def test_append_opaque_wrong_dimension(self): """test appending opaque gate to wrong dimension wires. """ qr = QuantumRegister(2) circ = QuantumCircuit(qr) opaque_gate = Gate(name='crz_2', num_qubits=2, params=[0.5]) self.assertRaises(QiskitError, circ.append, opaque_gate, [qr[0]])
def test_experiment_config(self): """Test converting to and from config works""" exp = FineDrag(0, Gate("Drag", num_qubits=1, params=[])) config = exp.config() loaded_exp = FineDrag.from_config(config) self.assertNotEqual(exp, loaded_exp) self.assertEqual(config, loaded_exp.config())
def circuits(self) -> List[QuantumCircuit]: """Create the circuits for the Drag calibration. Returns: circuits: The circuits that will run the Drag calibration. Raises: QiskitError: if the number of different repetition series is not three. """ schedule = self.experiment_options.schedule beta = next(iter(schedule.parameters)) # Note: if the pulse has a reserved name, e.g. x, which does not have parameters # then we cannot directly call the gate x and attach a schedule to it. Doing so # would results in QObj errors. drag_gate = Gate(name="Drag(" + schedule.name + ")", num_qubits=1, params=[beta]) reps = self.experiment_options.reps if len(reps) != 3: raise QiskitError( f"{self.__class__.__name__} uses exactly three repetitions. " f"Received {reps} with length {len(reps)} != 3.") circuits = [] for idx, rep in enumerate(reps): circuit = self._pre_circuit() for _ in range(rep): circuit.append(drag_gate, (0, )) circuit.rz(np.pi, 0) circuit.append(drag_gate, (0, )) circuit.rz(np.pi, 0) circuit.measure_active() circuit.add_calibration("Drag(" + schedule.name + ")", self.physical_qubits, schedule, params=[beta]) for beta_val in self.experiment_options.betas: beta_val = np.round(beta_val, decimals=6) assigned_circuit = circuit.assign_parameters({beta: beta_val}, inplace=False) assigned_circuit.metadata = { "experiment_type": self._type, "qubits": self.physical_qubits, "xval": beta_val, "series": idx, } circuits.append(assigned_circuit) return circuits
def _template_circuit(self, amp_param) -> QuantumCircuit: """Return the template quantum circuit.""" circuit = QuantumCircuit(1) circuit.x(0) circuit.append(Gate(name=self.__rabi_gate_name__, num_qubits=1, params=[amp_param]), (0,)) circuit.measure_active() return circuit
def multiplexer_multi_controlled_x(num_control): # Multi-controlled X gate multiplexer identity = np.array(np.array([[1, 0], [0, 1]], dtype=complex)) x_gate = np.array(np.array([[0, 1], [1, 0]], dtype=complex)) num_qubits = num_control + 1 multiplexer = Gate('multiplexer', num_qubits, (2**num_control - 1) * [identity] + [x_gate]) return multiplexer
def _create_op(self, name, params): if name in self.standard_extension: op = self.standard_extension[name](*params) elif name in self.gates: if self.gates[name]['opaque']: # call an opaque gate op = Gate(name=name, num_qubits=self.gates[name]['n_bits'], params=params) else: # call a custom gate op = Instruction(name=name, num_qubits=self.gates[name]['n_bits'], num_clbits=0, params=params) op.definition = self._gate_definition_to_qiskit_definition(self.gates[name], params=params) else: raise QiskitError("unknown operation for ast node name %s" % name) return op
def test_opaque_gate(self): """test opaque gate functionality""" q = QuantumRegister(4) c = ClassicalRegister(4) circ = QuantumCircuit(q, c, name='circ') opaque_gate = Gate(name='crz_2', num_qubits=2, params=[0.5]) circ.append(opaque_gate, [q[2], q[0]]) self.assertEqual(circ.data[0][0].name, 'crz_2') self.assertEqual(circ.decompose(), circ)
def test_end_to_end(self): """A simple test to check if the experiment will run and fit data.""" drag = FineDrag(0, Gate("Drag", num_qubits=1, params=[])) drag.set_experiment_options(schedule=self.schedule) drag.set_transpile_options(basis_gates=["rz", "Drag", "sx"]) exp_data = drag.run(FineDragTestBackend()) self.assertEqual(exp_data.analysis_results(0).quality, "good")
def test_circuits(self): """Test the circuits of the experiment.""" drag = FineDrag(0, Gate("Drag", num_qubits=1, params=[])) drag.set_experiment_options(schedule=self.schedule) drag.backend = FakeArmonk() for circuit in drag.circuits()[1:]: for idx, name in enumerate(["Drag", "rz", "Drag", "rz"]): self.assertEqual(circuit.data[idx][0].name, name)
def test_parametric_input(self): """Test that scheduling works with parametric pulses as input.""" qr = QuantumRegister(1) qc = QuantumCircuit(qr) qc.append(Gate("gauss", 1, []), qargs=[qr[0]]) custom_gauss = Schedule(Play(Gaussian(duration=25, sigma=4, amp=0.5j), DriveChannel(0))) self.inst_map.add("gauss", [0], custom_gauss) sched = schedule(qc, self.backend, inst_map=self.inst_map) self.assertEqual(sched.instructions[0], custom_gauss.instructions[0])
def setUpClass(cls): class_list = Gate.__subclasses__() + ControlledGate.__subclasses__() exclude = {'ControlledGate', 'DiagonalGate', 'UCGate', 'MCGupDiag', 'MCU1Gate', 'UnitaryGate', 'HamiltonianGate', 'MCPhaseGate', 'UCPauliRotGate', 'SingleQubitUnitary', 'MCXGate', 'VariadicZeroParamGate'} cls._gate_classes = [] for aclass in class_list: if aclass.__name__ not in exclude: cls._gate_classes.append(aclass)
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_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 setup(self, unique_pulses, channels): self.parametric_sched = build_parametric_pulse_schedule( unique_pulses, channels) qr = QuantumRegister(1) self.qc = QuantumCircuit(qr) self.qc.append(Gate('my_pulse', 1, []), qargs=[qr[0]]) self.backend = FakeOpenPulse2Q() self.inst_map = self.backend.defaults().instruction_schedule_map self.add_inst_map = self.inst_map self.add_inst_map.add('my_pulse', [0], self.parametric_sched)
def test_4_args_custom_gate_trivial_expansion(self): """test 'expansion' of 4 args in custom gate. See https://github.com/Qiskit/qiskit-terra/issues/2508""" qr = QuantumRegister(4) circ = QuantumCircuit(qr) circ.append(Gate("mcx", 4, []), [qr[0], qr[1], qr[2], qr[3]]) self.assertEqual(len(circ.data), 1) self.assertEqual(circ.data[0].operation.name, "mcx") self.assertEqual(len(circ.data[0].qubits), 4)