Source code for qiskit.assembler.assemble_circuits

# -*- coding: utf-8 -*-

# This code is part of Qiskit.
#
# (C) Copyright IBM 2017, 2019.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""Assemble function for converting a list of circuits into a qobj."""
from qiskit.qobj import (QasmQobj, QobjExperimentHeader,
                         QasmQobjInstruction, QasmQobjExperimentConfig, QasmQobjExperiment,
                         QasmQobjConfig)
from qiskit.tools.parallel import parallel_map


def _assemble_circuit(circuit):
    # header stuff
    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)
    # 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)

    # 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)


[docs]def assemble_circuits(circuits, run_config, qobj_id, qobj_header): """Assembles a list of circuits into a qobj that can be run on the backend. Args: circuits (list[QuantumCircuit]): circuit(s) to assemble qobj_id (int): identifier for the generated qobj qobj_header (QobjHeader): header to pass to the results run_config (RunConfig): configuration of the runtime environment Returns: QasmQobj: the qobj to be run on the backends """ qobj_config = QasmQobjConfig() if run_config: qobj_config = QasmQobjConfig(**run_config.to_dict()) qubit_sizes = [] memory_slot_sizes = [] for circ in circuits: num_qubits = 0 memory_slots = 0 for qreg in circ.qregs: num_qubits += qreg.size for creg in circ.cregs: memory_slots += creg.size qubit_sizes.append(num_qubits) memory_slot_sizes.append(memory_slots) qobj_config.memory_slots = max(memory_slot_sizes) qobj_config.n_qubits = max(qubit_sizes) experiments = parallel_map(_assemble_circuit, circuits) return QasmQobj(qobj_id=qobj_id, config=qobj_config, experiments=experiments, header=qobj_header)