def inverse(self): """Return the inverse. Note that the resulting gate 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 inverse(self): """Return the inverse. Note that the resulting gate 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. This does not re-compute the decomposition for the multiplexer with the inverse of the gates but simply inverts the existing decomposition. """ inverse_gate = Gate(name=self.name + '_dg', num_qubits=self.num_qubits, params=[]) # remove parameters since array is deprecated as parameter 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_custom_gate(self): """Test that custom gate is correctly serialized""" custom_gate = Gate("black_box", 1, []) custom_definition = QuantumCircuit(1) custom_definition.h(0) custom_definition.rz(1.5, 0) custom_definition.sdg(0) custom_gate.definition = custom_definition qc = QuantumCircuit(1) qc.append(custom_gate, [0]) qpy_file = io.BytesIO() dump(qc, qpy_file) qpy_file.seek(0) new_circ = load(qpy_file)[0] self.assertEqual(qc, new_circ) self.assertEqual(qc.decompose(), new_circ.decompose())
def test_custom_gate_with_label(self): """Test that custom gate is correctly serialized with a label""" custom_gate = Gate("black_box", 1, []) custom_definition = QuantumCircuit(1) custom_definition.h(0) custom_definition.rz(1.5, 0) custom_definition.sdg(0) custom_gate.definition = custom_definition custom_gate.label = "My special black box with a definition" qc = QuantumCircuit(1) qc.append(custom_gate, [0]) qpy_file = io.BytesIO() dump(qc, qpy_file) qpy_file.seek(0) new_circ = load(qpy_file)[0] self.assertEqual(qc, new_circ) self.assertEqual(qc.decompose(), new_circ.decompose()) self.assertEqual([x[0].label for x in qc.data], [x[0].label for x in new_circ.data])
def test_nested_controlled_gate(self): """Test a custom nested controlled gate.""" custom_gate = Gate("black_box", 1, []) custom_definition = QuantumCircuit(1) custom_definition.h(0) custom_definition.rz(1.5, 0) custom_definition.sdg(0) custom_gate.definition = custom_definition qc = QuantumCircuit(3) qc.append(custom_gate, [0]) controlled_gate = custom_gate.control(2) qc.append(controlled_gate, [0, 1, 2]) qpy_file = io.BytesIO() dump(qc, qpy_file) qpy_file.seek(0) new_circ = load(qpy_file)[0] self.assertEqual(qc, new_circ) self.assertEqual(qc.decompose(), new_circ.decompose())
def inverse(self): """Return the inverse. This does not re-compute the decomposition for the multiplexer with the inverse of the gates but simply inverts the existing decomposition. """ 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())) definition.global_phase = -self.definition.global_phase inverse_gate.definition = definition return inverse_gate
def generate_open_controlled_gates(): """Test QPY serialization with custom ControlledGates with open controls.""" circuits = [] qc = QuantumCircuit(3) controlled_gate = DCXGate().control(1, ctrl_state=0) qc.append(controlled_gate, [0, 1, 2]) circuits.append(qc) custom_gate = Gate("black_box", 1, []) custom_definition = QuantumCircuit(1) custom_definition.h(0) custom_definition.rz(1.5, 0) custom_definition.sdg(0) custom_gate.definition = custom_definition nested_qc = QuantumCircuit(3) nested_qc.append(custom_gate, [0]) controlled_gate = custom_gate.control(2, ctrl_state=1) nested_qc.append(controlled_gate, [0, 1, 2]) nested_qc.measure_all() circuits.append(nested_qc) return circuits
def circuit_to_gate(circuit, parameter_map=None): """Build a ``Gate`` object from a ``QuantumCircuit``. The gate is anonymous (not tied to a named quantum register), and so can be inserted into another circuit. The gate will have the same string name as the circuit. Args: circuit (QuantumCircuit): the input circuit. parameter_map (dict): For parameterized circuits, a mapping from parameters in the circuit to parameters to be used in the gate. If None, existing circuit parameters will also parameterize the Gate. Raises: QiskitError: if circuit is non-unitary or if parameter_map is not compatible with circuit Return: Gate: a Gate equivalent to the action of the input circuit. Upon decomposition, this gate will yield the components comprising the original circuit. """ if circuit.clbits: raise QiskitError('Circuit with classical bits cannot be converted ' 'to gate.') for inst, _, _ in circuit.data: if not isinstance(inst, Gate): raise QiskitError( ('One or more instructions cannot be converted to' ' a gate. "{}" is not a gate instruction').format(inst.name)) if parameter_map is None: parameter_dict = {p: p for p in circuit.parameters} else: parameter_dict = circuit._unroll_param_dict(parameter_map) if parameter_dict.keys() != circuit.parameters: raise QiskitError(('parameter_map should map all circuit parameters. ' 'Circuit parameters: {}, parameter_map: {}').format( circuit.parameters, parameter_dict)) gate = Gate(name=circuit.name, num_qubits=sum([qreg.size for qreg in circuit.qregs]), params=sorted(parameter_dict.values(), key=lambda p: p.name)) gate.condition = None def find_bit_position(bit): """find the index of a given bit (Register, int) within a flat ordered list of bits of the circuit """ if isinstance(bit, Qubit): ordered_regs = circuit.qregs else: ordered_regs = circuit.cregs reg_index = ordered_regs.index(bit.register) return sum([reg.size for reg in ordered_regs[:reg_index]]) + bit.index target = circuit.assign_parameters(parameter_dict, inplace=False) # pylint: disable=cyclic-import from qiskit.circuit.equivalence_library import SessionEquivalenceLibrary as sel # pylint: enable=cyclic-import sel.add_equivalence(gate, target) definition = target.data if gate.num_qubits > 0: q = QuantumRegister(gate.num_qubits, 'q') # The 3rd parameter in the output tuple) is hard coded to [] because # Gate objects do not have cregs set and we've verified that all # instructions are gates definition = list( map( lambda x: (x[0], list(map(lambda y: q[find_bit_position(y)], x[1])), []), definition)) gate.definition = definition return gate
def circuit_to_gate(circuit, parameter_map=None, equivalence_library=None, label=None): """Build a ``Gate`` object from a ``QuantumCircuit``. The gate is anonymous (not tied to a named quantum register), and so can be inserted into another circuit. The gate will have the same string name as the circuit. Args: circuit (QuantumCircuit): the input circuit. parameter_map (dict): For parameterized circuits, a mapping from parameters in the circuit to parameters to be used in the gate. If None, existing circuit parameters will also parameterize the Gate. equivalence_library (EquivalenceLibrary): Optional equivalence library where the converted gate will be registered. label (str): Optional gate label. Raises: QiskitError: if circuit is non-unitary or if parameter_map is not compatible with circuit Return: Gate: a Gate equivalent to the action of the input circuit. Upon decomposition, this gate will yield the components comprising the original circuit. """ # pylint: disable=cyclic-import from qiskit.circuit.quantumcircuit import QuantumCircuit if circuit.clbits: raise QiskitError("Circuit with classical bits cannot be converted " "to gate.") for inst, _, _ in circuit.data: if not isinstance(inst, Gate): raise QiskitError( ( "One or more instructions cannot be converted to" ' a gate. "{}" is not a gate instruction' ).format(inst.name) ) if parameter_map is None: parameter_dict = {p: p for p in circuit.parameters} else: parameter_dict = circuit._unroll_param_dict(parameter_map) if parameter_dict.keys() != circuit.parameters: raise QiskitError( ( "parameter_map should map all circuit parameters. " "Circuit parameters: {}, parameter_map: {}" ).format(circuit.parameters, parameter_dict) ) gate = Gate( name=circuit.name, num_qubits=sum([qreg.size for qreg in circuit.qregs]), params=[*parameter_dict.values()], label=label, ) gate.condition = None target = circuit.assign_parameters(parameter_dict, inplace=False) if equivalence_library is not None: equivalence_library.add_equivalence(gate, target) rules = target.data if gate.num_qubits > 0: q = QuantumRegister(gate.num_qubits, "q") qubit_map = {bit: q[idx] for idx, bit in enumerate(circuit.qubits)} # The 3rd parameter in the output tuple) is hard coded to [] because # Gate objects do not have cregs set and we've verified that all # instructions are gates rules = [(inst, [qubit_map[y] for y in qargs], []) for inst, qargs, _ in rules] qc = QuantumCircuit(q, name=gate.name, global_phase=target.global_phase) for instr, qargs, cargs in rules: qc._append(instr, qargs, cargs) gate.definition = qc return gate
def circuit_to_gate(circuit, parameter_map=None): """Build a ``Gate`` object from a ``QuantumCircuit``. The gate is anonymous (not tied to a named quantum register), and so can be inserted into another circuit. The gate will have the same string name as the circuit. Args: circuit (QuantumCircuit): the input circuit. parameter_map (dict): For parameterized circuits, a mapping from parameters in the circuit to parameters to be used in the gate. If None, existing circuit parameters will also parameterize the Gate. Raises: QiskitError: if circuit is non-unitary or if parameter_map is not compatible with circuit Return: Gate: a Gate equivalent to the action of the input circuit. Upon decomposition, this gate will yield the components comprising the original circuit. """ for inst, _, _ in circuit.data: if not isinstance(inst, Gate): raise QiskitError('One or more instructions in this instruction ' 'cannot be converted to a gate') if parameter_map is None: parameter_dict = {p: p for p in circuit.parameters} else: parameter_dict = circuit._unroll_param_dict(parameter_map) if parameter_dict.keys() != circuit.parameters: raise QiskitError(('parameter_map should map all circuit parameters. ' 'Circuit parameters: {}, parameter_map: {}').format( circuit.parameters, parameter_dict)) gate = Gate(name=circuit.name, num_qubits=sum([qreg.size for qreg in circuit.qregs]), params=sorted(parameter_dict.values(), key=lambda p: p.name)) gate.condition = None def find_bit_position(bit): """find the index of a given bit (Register, int) within a flat ordered list of bits of the circuit """ if isinstance(bit, Qubit): ordered_regs = circuit.qregs else: ordered_regs = circuit.cregs reg_index = ordered_regs.index(bit.register) return sum([reg.size for reg in ordered_regs[:reg_index]]) + bit.index target = circuit.copy() target._substitute_parameters(parameter_dict) definition = target.data if gate.num_qubits > 0: q = QuantumRegister(gate.num_qubits, 'q') definition = list( map( lambda x: (x[0], list(map(lambda y: q[find_bit_position(y)], x[1]))), definition)) gate.definition = definition return gate