def _assemble_circuit( circuit: QuantumCircuit, run_config: RunConfig ) -> Tuple[QasmQobjExperiment, Optional[PulseLibrary]]: """Assemble one circuit. Args: circuit: circuit to assemble run_config: configuration of the runtime environment Returns: One experiment for the QasmQobj, and pulse library for pulse gates (which could be None) Raises: QiskitError: when the circuit has unit other than 'dt'. """ if circuit.unit != "dt": raise QiskitError( "Unable to assemble circuit with unit '{}', which must be 'dt'.". format(circuit.unit)) # header data num_qubits = 0 memory_slots = 0 qubit_labels = [] clbit_labels = [] qreg_sizes = [] creg_sizes = [] for qreg in circuit.qregs: qreg_sizes.append([qreg.name, qreg.size]) for j in range(qreg.size): qubit_labels.append([qreg.name, j]) num_qubits += qreg.size for creg in circuit.cregs: creg_sizes.append([creg.name, creg.size]) for j in range(creg.size): clbit_labels.append([creg.name, j]) memory_slots += creg.size qubit_indices = {qubit: idx for idx, qubit in enumerate(circuit.qubits)} clbit_indices = {clbit: idx for idx, clbit in enumerate(circuit.clbits)} # TODO: why do we need creq_sizes and qreg_sizes in header # TODO: we need to rethink memory_slots as they are tied to classical bit metadata = circuit.metadata if metadata is None: metadata = {} header = QobjExperimentHeader( qubit_labels=qubit_labels, n_qubits=num_qubits, qreg_sizes=qreg_sizes, clbit_labels=clbit_labels, memory_slots=memory_slots, creg_sizes=creg_sizes, name=circuit.name, global_phase=float(circuit.global_phase), metadata=metadata, ) # TODO: why do we need n_qubits and memory_slots in both the header and the config config = QasmQobjExperimentConfig(n_qubits=num_qubits, memory_slots=memory_slots) calibrations, pulse_library = _assemble_pulse_gates(circuit, run_config) if calibrations: config.calibrations = calibrations # Convert conditionals from QASM-style (creg ?= int) to qobj-style # (register_bit ?= 1), by assuming device has unlimited register slots # (supported only for simulators). Map all measures to a register matching # their clbit_index, create a new register slot for every conditional gate # and add a bfunc to map the creg=val mask onto the gating register bit. is_conditional_experiment = any(op.condition for (op, qargs, cargs) in circuit.data) max_conditional_idx = 0 instructions = [] for op_context in circuit.data: instruction = op_context[0].assemble() # Add register attributes to the instruction qargs = op_context[1] cargs = op_context[2] if qargs: instruction.qubits = [qubit_indices[qubit] for qubit in qargs] if cargs: instruction.memory = [clbit_indices[clbit] for clbit in cargs] # If the experiment has conditional instructions, assume every # measurement result may be needed for a conditional gate. if instruction.name == "measure" and is_conditional_experiment: instruction.register = [ clbit_indices[clbit] for clbit in cargs ] # To convert to a qobj-style conditional, insert a bfunc prior # to the conditional instruction to map the creg ?= val condition # onto a gating register bit. if hasattr(instruction, "_condition"): ctrl_reg, ctrl_val = instruction._condition mask = 0 val = 0 if isinstance(ctrl_reg, Clbit): mask = 1 << clbit_indices[ctrl_reg] val = (ctrl_val & 1) << clbit_indices[ctrl_reg] else: for clbit in clbit_indices: if clbit in ctrl_reg: mask |= 1 << clbit_indices[clbit] val |= ((ctrl_val >> list(ctrl_reg).index(clbit)) & 1) << clbit_indices[clbit] conditional_reg_idx = memory_slots + max_conditional_idx conversion_bfunc = QasmQobjInstruction( name="bfunc", mask="0x%X" % mask, relation="==", val="0x%X" % val, register=conditional_reg_idx, ) instructions.append(conversion_bfunc) instruction.conditional = conditional_reg_idx max_conditional_idx += 1 # Delete condition attribute now that we have replaced it with # the conditional and bfunc del instruction._condition instructions.append(instruction) return ( QasmQobjExperiment(instructions=instructions, header=header, config=config), pulse_library, )
def _assemble_circuit( circuit: QuantumCircuit, run_config: RunConfig ) -> Tuple[QasmQobjExperiment, Optional[PulseLibrary]]: """Assemble one circuit. Args: circuit: circuit to assemble run_config: configuration of the runtime environment Returns: One experiment for the QasmQobj, and pulse library for pulse gates (which could be None) """ # header data num_qubits = 0 memory_slots = 0 qubit_labels = [] clbit_labels = [] qreg_sizes = [] creg_sizes = [] for qreg in circuit.qregs: qreg_sizes.append([qreg.name, qreg.size]) for j in range(qreg.size): qubit_labels.append([qreg.name, j]) num_qubits += qreg.size for creg in circuit.cregs: creg_sizes.append([creg.name, creg.size]) for j in range(creg.size): clbit_labels.append([creg.name, j]) memory_slots += creg.size # TODO: why do we need creq_sizes and qreg_sizes in header # TODO: we need to rethink memory_slots as they are tied to classical bit header = QobjExperimentHeader(qubit_labels=qubit_labels, n_qubits=num_qubits, qreg_sizes=qreg_sizes, clbit_labels=clbit_labels, memory_slots=memory_slots, creg_sizes=creg_sizes, name=circuit.name, global_phase=circuit.global_phase) # TODO: why do we need n_qubits and memory_slots in both the header and the config config = QasmQobjExperimentConfig(n_qubits=num_qubits, memory_slots=memory_slots) calibrations, pulse_library = _assemble_pulse_gates(circuit, run_config) if calibrations: config.calibrations = calibrations # Convert conditionals from QASM-style (creg ?= int) to qobj-style # (register_bit ?= 1), by assuming device has unlimited register slots # (supported only for simulators). Map all measures to a register matching # their clbit_index, create a new register slot for every conditional gate # and add a bfunc to map the creg=val mask onto the gating register bit. is_conditional_experiment = any(op.condition for (op, qargs, cargs) in circuit.data) max_conditional_idx = 0 instructions = [] for op_context in circuit.data: instruction = op_context[0].assemble() # Add register attributes to the instruction qargs = op_context[1] cargs = op_context[2] if qargs: qubit_indices = [ qubit_labels.index([qubit.register.name, qubit.index]) for qubit in qargs ] instruction.qubits = qubit_indices if cargs: clbit_indices = [ clbit_labels.index([clbit.register.name, clbit.index]) for clbit in cargs ] instruction.memory = clbit_indices # If the experiment has conditional instructions, assume every # measurement result may be needed for a conditional gate. if instruction.name == "measure" and is_conditional_experiment: instruction.register = clbit_indices # To convert to a qobj-style conditional, insert a bfunc prior # to the conditional instruction to map the creg ?= val condition # onto a gating register bit. if hasattr(instruction, '_condition'): ctrl_reg, ctrl_val = instruction._condition mask = 0 val = 0 for clbit in clbit_labels: if clbit[0] == ctrl_reg.name: mask |= (1 << clbit_labels.index(clbit)) val |= (((ctrl_val >> clbit[1]) & 1) << clbit_labels.index(clbit)) conditional_reg_idx = memory_slots + max_conditional_idx conversion_bfunc = QasmQobjInstruction( name='bfunc', mask="0x%X" % mask, relation='==', val="0x%X" % val, register=conditional_reg_idx) instructions.append(conversion_bfunc) instruction.conditional = conditional_reg_idx max_conditional_idx += 1 # Delete condition attribute now that we have replaced it with # the conditional and bfuc del instruction._condition instructions.append(instruction) return (QasmQobjExperiment(instructions=instructions, header=header, config=config), pulse_library)