def _parse_custom_instruction(custom_instructions, gate_name, params): (type_str, num_qubits, num_clbits, definition) = custom_instructions[gate_name] if type_str == "i": inst_obj = Instruction(gate_name, num_qubits, num_clbits, params) if definition: inst_obj.definition = definition elif type_str == "g": inst_obj = Gate(gate_name, num_qubits, params) inst_obj.definition = definition else: raise ValueError("Invalid custom instruction type '%s'" % type_str) return inst_obj
def _parse_custom_operation(custom_operations, gate_name, params, version, vectors, registers): if version >= 5: ( type_str, num_qubits, num_clbits, definition, num_ctrl_qubits, ctrl_state, base_gate_raw, ) = custom_operations[gate_name] else: type_str, num_qubits, num_clbits, definition = custom_operations[ gate_name] type_key = type_keys.CircuitInstruction(type_str) if type_key == type_keys.CircuitInstruction.INSTRUCTION: inst_obj = Instruction(gate_name, num_qubits, num_clbits, params) if definition is not None: inst_obj.definition = definition return inst_obj if type_key == type_keys.CircuitInstruction.GATE: inst_obj = Gate(gate_name, num_qubits, params) inst_obj.definition = definition return inst_obj if version >= 5 and type_key == type_keys.CircuitInstruction.CONTROLLED_GATE: with io.BytesIO(base_gate_raw) as base_gate_obj: base_gate = _read_instruction(base_gate_obj, None, registers, custom_operations, version, vectors) if ctrl_state < 2**num_ctrl_qubits - 1: # If open controls, we need to discard the control suffix when setting the name. gate_name = gate_name.rsplit("_", 1)[0] inst_obj = ControlledGate( gate_name, num_qubits, params, num_ctrl_qubits=num_ctrl_qubits, ctrl_state=ctrl_state, base_gate=base_gate, ) inst_obj.definition = definition return inst_obj if type_key == type_keys.CircuitInstruction.PAULI_EVOL_GATE: return definition raise ValueError("Invalid custom instruction type '%s'" % type_str)
def _parse_custom_instruction(custom_instructions, gate_name, params): type_str, num_qubits, num_clbits, definition = custom_instructions[gate_name] type_key = common.CircuitInstructionTypeKey(type_str) if type_key == common.CircuitInstructionTypeKey.INSTRUCTION: inst_obj = Instruction(gate_name, num_qubits, num_clbits, params) if definition is not None: inst_obj.definition = definition return inst_obj if type_key == common.CircuitInstructionTypeKey.GATE: inst_obj = Gate(gate_name, num_qubits, params) inst_obj.definition = definition return inst_obj if type_key == common.CircuitInstructionTypeKey.PAULI_EVOL_GATE: return definition raise ValueError("Invalid custom instruction type '%s'" % type_str)
def circuit_to_instruction(circuit): """Build an ``Instruction`` object from a ``QuantumCircuit``. The instruction is anonymous (not tied to a named quantum register), and so can be inserted into another circuit. The instruction will have the same string name as the circuit. Args: circuit (QuantumCircuit): the input circuit. Return: Instruction: an instruction equivalent to the action of the input circuit. Upon decomposition, this instruction will yield the components comprising the original circuit. """ instruction = Instruction( name=circuit.name, num_qubits=sum([qreg.size for qreg in circuit.qregs]), num_clbits=sum([creg.size for creg in circuit.cregs]), params=[]) instruction.control = 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[0], QuantumRegister): ordered_regs = circuit.qregs else: ordered_regs = circuit.cregs reg_index = ordered_regs.index(bit[0]) return sum([reg.size for reg in ordered_regs[:reg_index]]) + bit[1] definition = circuit.data.copy() if instruction.num_qubits > 0: q = QuantumRegister(instruction.num_qubits, 'q') if instruction.num_clbits > 0: c = ClassicalRegister(instruction.num_clbits, 'c') definition = list( map( lambda x: (x[0], list(map(lambda y: (q, find_bit_position(y)), x[1])), list(map(lambda y: (c, find_bit_position(y)), x[2]))), definition)) instruction.definition = definition return instruction
def test_custom_instruction(self): """Test that custom instruction is correctly serialized""" custom_gate = Instruction("black_box", 1, 0, []) 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_instruction_with_label(self): """Test that custom instruction is correctly serialized with a label""" custom_gate = Instruction("black_box", 1, 0, []) 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 Instruction 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 circuit_to_instruction(circuit, parameter_map=None, equivalence_library=None): """Build an ``Instruction`` object from a ``QuantumCircuit``. The instruction is anonymous (not tied to a named quantum register), and so can be inserted into another circuit. The instruction 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 instruction. If None, existing circuit parameters will also parameterize the instruction. equivalence_library (EquivalenceLibrary): Optional equivalence library where the converted instruction will be registered. Raises: QiskitError: if parameter_map is not compatible with circuit Return: qiskit.circuit.Instruction: an instruction equivalent to the action of the input circuit. Upon decomposition, this instruction will yield the components comprising the original circuit. Example: .. jupyter-execute:: from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit from qiskit.converters import circuit_to_instruction %matplotlib inline q = QuantumRegister(3, 'q') c = ClassicalRegister(3, 'c') circ = QuantumCircuit(q, c) circ.h(q[0]) circ.cx(q[0], q[1]) circ.measure(q[0], c[0]) circ.rz(0.5, q[1]).c_if(c, 2) circuit_to_instruction(circ) """ 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)) instruction = Instruction( name=circuit.name, num_qubits=sum([qreg.size for qreg in circuit.qregs]), num_clbits=sum([creg.size for creg in circuit.cregs]), params=sorted(parameter_dict.values(), key=lambda p: p.name)) instruction.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) if equivalence_library is not None: equivalence_library.add_equivalence(instruction, target) definition = target.data if instruction.num_qubits > 0: q = QuantumRegister(instruction.num_qubits, 'q') if instruction.num_clbits > 0: c = ClassicalRegister(instruction.num_clbits, 'c') definition = list( map( lambda x: (x[0], list(map(lambda y: q[find_bit_position(y)], x[1])), list(map(lambda y: c[find_bit_position(y)], x[2]))), definition)) instruction.definition = definition return instruction
def circuit_to_instruction(circuit, parameter_map=None, equivalence_library=None, label=None): """Build an ``Instruction`` object from a ``QuantumCircuit``. The instruction is anonymous (not tied to a named quantum register), and so can be inserted into another circuit. The instruction 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 instruction. If None, existing circuit parameters will also parameterize the instruction. equivalence_library (EquivalenceLibrary): Optional equivalence library where the converted instruction will be registered. label (str): Optional instruction label. Raises: QiskitError: if parameter_map is not compatible with circuit Return: qiskit.circuit.Instruction: an instruction equivalent to the action of the input circuit. Upon decomposition, this instruction will yield the components comprising the original circuit. Example: .. jupyter-execute:: from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit from qiskit.converters import circuit_to_instruction %matplotlib inline q = QuantumRegister(3, 'q') c = ClassicalRegister(3, 'c') circ = QuantumCircuit(q, c) circ.h(q[0]) circ.cx(q[0], q[1]) circ.measure(q[0], c[0]) circ.rz(0.5, q[1]).c_if(c, 2) circuit_to_instruction(circ) """ # pylint: disable=cyclic-import from qiskit.circuit.quantumcircuit import QuantumCircuit 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) ) instruction = Instruction( name=circuit.name, num_qubits=sum(qreg.size for qreg in circuit.qregs), num_clbits=sum(creg.size for creg in circuit.cregs), params=[*parameter_dict.values()], label=label, ) instruction.condition = None target = circuit.assign_parameters(parameter_dict, inplace=False) if equivalence_library is not None: equivalence_library.add_equivalence(instruction, target) definition = target.data regs = [] if instruction.num_qubits > 0: q = QuantumRegister(instruction.num_qubits, "q") regs.append(q) if instruction.num_clbits > 0: c = ClassicalRegister(instruction.num_clbits, "c") regs.append(c) qubit_map = {bit: q[idx] for idx, bit in enumerate(circuit.qubits)} clbit_map = {bit: c[idx] for idx, bit in enumerate(circuit.clbits)} definition = [ (inst, [qubit_map[y] for y in qargs], [clbit_map[y] for y in cargs]) for inst, qargs, cargs in definition ] # fix condition for rule in definition: condition = rule[0].condition if condition: reg, val = condition if isinstance(reg, Clbit): idx = 0 for creg in circuit.cregs: if reg not in creg: idx += creg.size else: cond_reg = creg break rule[0].condition = (c[idx + list(cond_reg).index(reg)], val) elif reg.size == c.size: rule[0].condition = (c, val) else: raise QiskitError( "Cannot convert condition in circuit with " "multiple classical registers to instruction" ) qc = QuantumCircuit(*regs, name=instruction.name) for instr, qargs, cargs in definition: qc._append(instr, qargs, cargs) if circuit.global_phase: qc.global_phase = circuit.global_phase instruction.definition = qc return instruction
def circuit_to_instruction(circuit, parameter_map=None): """Build an ``Instruction`` object from a ``QuantumCircuit``. The instruction is anonymous (not tied to a named quantum register), and so can be inserted into another circuit. The instruction 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 instruction. If None, existing circuit parameters will also parameterize the instruction. Raises: QiskitError: if parameter_map is not compatible with circuit Return: Instruction: an instruction equivalent to the action of the input circuit. Upon decomposition, this instruction will yield the components comprising the original circuit. """ if parameter_map is None: parameter_map = {p: p for p in circuit.parameters} if parameter_map.keys() != circuit.parameters: raise QiskitError(('parameter_map should map all circuit parameters. ' 'Circuit parameters: {}, parameter_map: {}').format( circuit.parameters, parameter_map)) instruction = Instruction(name=circuit.name, num_qubits=sum([qreg.size for qreg in circuit.qregs]), num_clbits=sum([creg.size for creg in circuit.cregs]), params=sorted(parameter_map.values(), key=lambda p: p.name)) instruction.control = 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[0], QuantumRegister): ordered_regs = circuit.qregs else: ordered_regs = circuit.cregs reg_index = ordered_regs.index(bit[0]) return sum([reg.size for reg in ordered_regs[:reg_index]]) + bit[1] target = circuit.copy() target._substitute_parameters(parameter_map) definition = target.data if instruction.num_qubits > 0: q = QuantumRegister(instruction.num_qubits, 'q') if instruction.num_clbits > 0: c = ClassicalRegister(instruction.num_clbits, 'c') definition = list(map(lambda x: (x[0], list(map(lambda y: (q, find_bit_position(y)), x[1])), list(map(lambda y: (c, find_bit_position(y)), x[2]))), definition)) instruction.definition = definition return instruction