def test_opaque_instruction_with_label(self):
     """Test that custom opaque instruction is correctly serialized with a label"""
     custom_gate = Instruction("black_box", 1, 0, [])
     custom_gate.label = "My Special Black Box Instruction"
     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([x[0].label for x in qc.data], [x[0].label for x in new_circ.data])
Exemplo n.º 2
0
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
Exemplo n.º 3
0
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
Exemplo n.º 4
0
 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())
Exemplo n.º 5
0
    def to_instruction(self):
        """Convert to a Kraus or UnitaryGate circuit instruction.

        If the channel is unitary it will be added as a unitary gate,
        otherwise it will be added as a kraus simulator instruction.

        Returns:
            qiskit.circuit.Instruction: A kraus instruction for the channel.

        Raises:
            QiskitError: if input data is not an N-qubit CPTP quantum channel.
        """
        from qiskit.circuit.instruction import Instruction
        # Check if input is an N-qubit CPTP channel.
        num_qubits = int(np.log2(self._input_dim))
        if self._input_dim != self._output_dim or 2**num_qubits != self._input_dim:
            raise QiskitError(
                'Cannot convert QuantumChannel to Instruction: channel is not an N-qubit channel.'
            )
        if not self.is_cptp():
            raise QiskitError(
                'Cannot convert QuantumChannel to Instruction: channel is not CPTP.'
            )
        # Next we convert to the Kraus representation. Since channel is CPTP we know
        # that there is only a single set of Kraus operators
        kraus, _ = _to_kraus(self._channel_rep, self._data, *self.dim)
        # If we only have a single Kraus operator then the channel is
        # a unitary channel so can be converted to a UnitaryGate. We do this by
        # converting to an Operator and using its to_instruction method
        if len(kraus) == 1:
            return Operator(kraus[0]).to_instruction()
        return Instruction('kraus', num_qubits, 0, kraus)
 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])
Exemplo n.º 7
0
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)
Exemplo n.º 8
0
 def test_empty_tuple_param(self):
     """Test qpy with an instruction that contains an empty tuple."""
     inst = Instruction("empty_tuple_test", 1, 0, [tuple()])
     qc = QuantumCircuit(1)
     qc.append(inst, [0])
     qpy_file = io.BytesIO()
     dump(qc, qpy_file)
     qpy_file.seek(0)
     new_circuit = load(qpy_file)[0]
     self.assertEqual(qc, new_circuit)
Exemplo n.º 9
0
 def test_nested_tuple_param(self):
     """Test qpy with an instruction that contains nested tuples."""
     inst = Instruction("tuple_test", 1, 0, [((((0, 1), (0, 1)), 2, 3), ("A", "B", "C"))])
     qc = QuantumCircuit(1)
     qc.append(inst, [0])
     qpy_file = io.BytesIO()
     dump(qc, qpy_file)
     qpy_file.seek(0)
     new_circuit = load(qpy_file)[0]
     self.assertEqual(qc, new_circuit)
Exemplo n.º 10
0
 def test_opaque_instruction(self):
     """Test that custom opaque instruction is correctly serialized"""
     custom_gate = Instruction("black_box", 1, 0, [])
     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)
Exemplo n.º 11
0
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)
Exemplo n.º 12
0
 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_rules_to_qiskit_circuit(self.gates[name],
                                                                params=params)
     else:
         raise QiskitError("unknown operation for ast node name %s" % name)
     return op
    def test_custom_instruction_with_noop_definition(self):
        """Test that a custom instruction whose definition contains no elements is serialized with a
        proper definition.

        Regression test of gh-7429."""
        empty = QuantumCircuit(1, name="empty").to_instruction()
        opaque = Instruction("opaque", 1, 0, [])
        qc = QuantumCircuit(2)
        qc.append(empty, [0], [])
        qc.append(opaque, [1], [])

        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(len(new_circ), 2)
        self.assertIsInstance(new_circ.data[0][0].definition, QuantumCircuit)
        self.assertIs(new_circ.data[1][0].definition, None)
Exemplo n.º 14
0
    def _copy_mutable_properties(self, instruction: Instruction) -> Instruction:
        """Copy mutable properties from ourselves onto a non-placeholder instruction.

        The mutable properties are expected to be things like ``condition``, added onto a
        placeholder by the :meth:`c_if` method.  This mutates ``instruction``, and returns the same
        instance that was passed.  This is mostly intended to make writing concrete versions of
        :meth:`.concrete_instruction` easy.

        The complete list of mutations is:

        * ``condition``, added by :meth:`c_if`.

        Args:
            instruction: the concrete instruction instance to be mutated.

        Returns:
            The same instruction instance that was passed, but mutated to propagate the tracked
            changes to this class.
        """
        # In general the tuple creation should be a no-op, because ``tuple(t) is t`` for tuples.
        instruction.condition = None if self.condition is None else tuple(self.condition)
        return instruction
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
Exemplo n.º 16
0
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
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
Exemplo n.º 18
0
def _experiments_to_circuits(qobj):
    """Return a list of QuantumCircuit object(s) from a qobj.

    Args:
        qobj (Qobj): The Qobj object to convert to QuantumCircuits

    Returns:
        list: A list of QuantumCircuit objects from the qobj
    """
    if not qobj.experiments:
        return None

    circuits = []
    for exp in qobj.experiments:
        quantum_registers = [QuantumRegister(i[1], name=i[0]) for i in exp.header.qreg_sizes]
        classical_registers = [ClassicalRegister(i[1], name=i[0]) for i in exp.header.creg_sizes]
        circuit = QuantumCircuit(*quantum_registers, *classical_registers, name=exp.header.name)
        qreg_dict = collections.OrderedDict()
        creg_dict = collections.OrderedDict()
        for reg in quantum_registers:
            qreg_dict[reg.name] = reg
        for reg in classical_registers:
            creg_dict[reg.name] = reg
        conditional = {}
        for i in exp.instructions:
            name = i.name
            qubits = []
            params = getattr(i, "params", [])
            try:
                for qubit in i.qubits:
                    qubit_label = exp.header.qubit_labels[qubit]
                    qubits.append(qreg_dict[qubit_label[0]][qubit_label[1]])
            except Exception:  # pylint: disable=broad-except
                pass
            clbits = []
            try:
                for clbit in i.memory:
                    clbit_label = exp.header.clbit_labels[clbit]
                    clbits.append(creg_dict[clbit_label[0]][clbit_label[1]])
            except Exception:  # pylint: disable=broad-except
                pass
            if hasattr(circuit, name):
                instr_method = getattr(circuit, name)
                if i.name in ["snapshot"]:
                    _inst = instr_method(
                        i.label, snapshot_type=i.snapshot_type, qubits=qubits, params=params
                    )
                elif i.name == "initialize":
                    _inst = instr_method(params, qubits)
                elif i.name == "isometry":
                    _inst = instr_method(*params, qubits, clbits)
                elif i.name in ["mcx", "mcu1", "mcp"]:
                    _inst = instr_method(*params, qubits[:-1], qubits[-1], *clbits)
                else:
                    _inst = instr_method(*params, *qubits, *clbits)
            elif name == "bfunc":
                conditional["value"] = int(i.val, 16)
                full_bit_size = sum(creg_dict[x].size for x in creg_dict)
                mask_map = {}
                raw_map = {}
                raw = []

                for creg in creg_dict:
                    size = creg_dict[creg].size
                    reg_raw = [1] * size
                    if not raw:
                        raw = reg_raw
                    else:
                        for pos, val in enumerate(raw):
                            if val == 1:
                                raw[pos] = 0
                        raw = reg_raw + raw
                    mask = [0] * (full_bit_size - len(raw)) + raw
                    raw_map[creg] = mask
                    mask_map[int("".join(str(x) for x in mask), 2)] = creg
                creg = mask_map[int(i.mask, 16)]
                conditional["register"] = creg_dict[creg]
                val = int(i.val, 16)
                mask = raw_map[creg]
                for j in reversed(mask):
                    if j == 0:
                        val = val >> 1
                    else:
                        conditional["value"] = val
                        break
            else:
                _inst = temp_opaque_instruction = Instruction(
                    name=name, num_qubits=len(qubits), num_clbits=len(clbits), params=params
                )
                circuit.append(temp_opaque_instruction, qubits, clbits)
            if conditional and name != "bfunc":
                _inst.c_if(conditional["register"], conditional["value"])
                conditional = {}
        pulse_lib = qobj.config.pulse_library if hasattr(qobj.config, "pulse_library") else []
        parametric_pulses = (
            qobj.config.parametric_pulses if hasattr(qobj.config, "parametric_pulses") else []
        )
        # The dict update method did not work here; could investigate in the future
        if hasattr(qobj.config, "calibrations"):
            circuit.calibrations = dict(
                **circuit.calibrations, **_qobj_to_circuit_cals(qobj, pulse_lib, parametric_pulses)
            )
        if hasattr(exp.config, "calibrations"):
            circuit.calibrations = dict(
                **circuit.calibrations, **_qobj_to_circuit_cals(exp, pulse_lib, parametric_pulses)
            )
        circuits.append(circuit)
    return circuits
Exemplo n.º 19
0
def _experiments_to_circuits(qobj):
    """Return a list of QuantumCircuit object(s) from a qobj

    Args:
        qobj (Qobj): The Qobj object to convert to QuantumCircuits

    Returns:
        list: A list of QuantumCircuit objects from the qobj
    """
    if qobj.experiments:
        circuits = []
        for x in qobj.experiments:
            quantum_registers = [
                QuantumRegister(i[1], name=i[0]) for i in x.header.qreg_sizes
            ]
            classical_registers = [
                ClassicalRegister(i[1], name=i[0]) for i in x.header.creg_sizes
            ]
            circuit = QuantumCircuit(*quantum_registers,
                                     *classical_registers,
                                     name=x.header.name)
            qreg_dict = {}
            creg_dict = {}
            for reg in quantum_registers:
                qreg_dict[reg.name] = reg
            for reg in classical_registers:
                creg_dict[reg.name] = reg
            for i in x.instructions:
                name = i.name
                if i.name == 'id':
                    name = 'iden'
                qubits = []
                params = getattr(i, 'params', [])
                try:
                    for qubit in i.qubits:
                        qubit_label = x.header.qubit_labels[qubit]
                        qubits.append(
                            qreg_dict[qubit_label[0]][qubit_label[1]])
                except Exception:  # pylint: disable=broad-except
                    pass
                clbits = []
                try:
                    for clbit in i.memory:
                        clbit_label = x.header.clbit_labels[clbit]
                        clbits.append(
                            creg_dict[clbit_label[0]][clbit_label[1]])
                except Exception:  # pylint: disable=broad-except
                    pass
                if hasattr(circuit, name):
                    instr_method = getattr(circuit, name)
                    if i.name in ['snapshot']:
                        instr_method(i.label,
                                     snapshot_type=i.snapshot_type,
                                     qubits=qubits,
                                     params=params)
                    elif i.name == 'initialize':
                        instr_method(params, qubits)
                    else:
                        instr_method(*params, *qubits, *clbits)
                else:
                    temp_opaque_instruction = Instruction(
                        name=name,
                        num_qubits=len(qubits),
                        num_clbits=len(clbits),
                        params=params)
                    circuit.append(temp_opaque_instruction, qubits, clbits)
            circuits.append(circuit)
        return circuits
    return None
Exemplo n.º 20
0
    def run(self, dag):
        """Return a new circuit that has been optimized."""
        runs = dag.collect_runs(["u1", "u2", "u3", "id"])
        for run in runs:
            run_qarg = dag.node(run[0])["qargs"][0]
            right_name = "u1"
            right_parameters = (0, 0, 0)  # (theta, phi, lambda)

            for current_node in run:
                node = dag.node(current_node)
                left_name = node["name"]
                if (node["condition"] is not None or len(node["qargs"]) != 1
                        or node["qargs"][0] != run_qarg
                        or left_name not in ["u1", "u2", "u3", "id"]):
                    raise MapperError("internal error")
                if left_name == "u1":
                    left_parameters = (0, 0, node["op"].params[0])
                elif left_name == "u2":
                    left_parameters = (np.pi / 2, node["op"].params[0],
                                       node["op"].params[1])
                elif left_name == "u3":
                    left_parameters = tuple(node["op"].params)
                else:
                    left_name = "u1"  # replace id with u1
                    left_parameters = (0, 0, 0)
                # If there are any sympy objects coming from the gate convert
                # to numpy.
                left_parameters = tuple([float(x) for x in left_parameters])
                # Compose gates
                name_tuple = (left_name, right_name)
                if name_tuple == ("u1", "u1"):
                    # u1(lambda1) * u1(lambda2) = u1(lambda1 + lambda2)
                    right_parameters = (0, 0, right_parameters[2] +
                                        left_parameters[2])
                elif name_tuple == ("u1", "u2"):
                    # u1(lambda1) * u2(phi2, lambda2) = u2(phi2 + lambda1, lambda2)
                    right_parameters = (np.pi / 2, right_parameters[1] +
                                        left_parameters[2],
                                        right_parameters[2])
                elif name_tuple == ("u2", "u1"):
                    # u2(phi1, lambda1) * u1(lambda2) = u2(phi1, lambda1 + lambda2)
                    right_name = "u2"
                    right_parameters = (np.pi / 2, left_parameters[1],
                                        right_parameters[2] +
                                        left_parameters[2])
                elif name_tuple == ("u1", "u3"):
                    # u1(lambda1) * u3(theta2, phi2, lambda2) =
                    #     u3(theta2, phi2 + lambda1, lambda2)
                    right_parameters = (right_parameters[0],
                                        right_parameters[1] +
                                        left_parameters[2],
                                        right_parameters[2])
                elif name_tuple == ("u3", "u1"):
                    # u3(theta1, phi1, lambda1) * u1(lambda2) =
                    #     u3(theta1, phi1, lambda1 + lambda2)
                    right_name = "u3"
                    right_parameters = (left_parameters[0], left_parameters[1],
                                        right_parameters[2] +
                                        left_parameters[2])
                elif name_tuple == ("u2", "u2"):
                    # Using Ry(pi/2).Rz(2*lambda).Ry(pi/2) =
                    #    Rz(pi/2).Ry(pi-2*lambda).Rz(pi/2),
                    # u2(phi1, lambda1) * u2(phi2, lambda2) =
                    #    u3(pi - lambda1 - phi2, phi1 + pi/2, lambda2 + pi/2)
                    right_name = "u3"
                    right_parameters = (np.pi - left_parameters[2] -
                                        right_parameters[1],
                                        left_parameters[1] + np.pi / 2,
                                        right_parameters[2] + np.pi / 2)
                elif name_tuple[1] == "nop":
                    right_name = left_name
                    right_parameters = left_parameters
                else:
                    # For composing u3's or u2's with u3's, use
                    # u2(phi, lambda) = u3(pi/2, phi, lambda)
                    # together with the qiskit.mapper.compose_u3 method.
                    right_name = "u3"
                    # Evaluate the symbolic expressions for efficiency
                    right_parameters = Optimize1qGates.compose_u3(
                        left_parameters[0], left_parameters[1],
                        left_parameters[2], right_parameters[0],
                        right_parameters[1], right_parameters[2])
                    # Why evalf()? This program:
                    #   OPENQASM 2.0;
                    #   include "qelib1.inc";
                    #   qreg q[2];
                    #   creg c[2];
                    #   u3(0.518016983430947*pi,1.37051598592907*pi,1.36816383603222*pi) q[0];
                    #   u3(1.69867232277986*pi,0.371448347747471*pi,0.461117217930936*pi) q[0];
                    #   u3(0.294319836336836*pi,0.450325871124225*pi,1.46804720442555*pi) q[0];
                    #   measure q -> c;
                    # took >630 seconds (did not complete) to optimize without
                    # calling evalf() at all, 19 seconds to optimize calling
                    # evalf() AFTER compose_u3, and 1 second to optimize
                    # calling evalf() BEFORE compose_u3.
                # 1. Here down, when we simplify, we add f(theta) to lambda to
                # correct the global phase when f(theta) is 2*pi. This isn't
                # necessary but the other steps preserve the global phase, so
                # we continue in that manner.
                # 2. The final step will remove Z rotations by 2*pi.
                # 3. Note that is_zero is true only if the expression is exactly
                # zero. If the input expressions have already been evaluated
                # then these final simplifications will not occur.
                # TODO After we refactor, we should have separate passes for
                # exact and approximate rewriting.

                # Y rotation is 0 mod 2*pi, so the gate is a u1
                if np.mod(right_parameters[0], (2 * np.pi)) == 0 \
                        and right_name != "u1":
                    right_name = "u1"
                    right_parameters = (0, 0, right_parameters[1] +
                                        right_parameters[2] +
                                        right_parameters[0])
                # Y rotation is pi/2 or -pi/2 mod 2*pi, so the gate is a u2
                if right_name == "u3":
                    # theta = pi/2 + 2*k*pi
                    if np.mod((right_parameters[0] - np.pi / 2),
                              (2 * np.pi)) == 0:
                        right_name = "u2"
                        right_parameters = (np.pi / 2, right_parameters[1],
                                            right_parameters[2] +
                                            (right_parameters[0] - np.pi / 2))
                    # theta = -pi/2 + 2*k*pi
                    if np.mod((right_parameters[0] + np.pi / 2),
                              (2 * np.pi)) == 0:
                        right_name = "u2"
                        right_parameters = (np.pi / 2,
                                            right_parameters[1] + np.pi,
                                            right_parameters[2] - np.pi +
                                            (right_parameters[0] + np.pi / 2))
                # u1 and lambda is 0 mod 2*pi so gate is nop (up to a global phase)
                if right_name == "u1" and np.mod(right_parameters[2],
                                                 (2 * np.pi)) == 0:
                    right_name = "nop"

            # Replace the data of the first node in the run
            new_op = Instruction("", [], [], [])
            if right_name == "u1":
                new_op = U1Gate(right_parameters[2], run_qarg)
            if right_name == "u2":
                new_op = U2Gate(right_parameters[1], right_parameters[2],
                                run_qarg)
            if right_name == "u3":
                new_op = U3Gate(*right_parameters, run_qarg)
            dag.node(run[0])['name'] = right_name
            dag.node(run[0])['op'] = new_op

            # Delete the other nodes in the run
            for current_node in run[1:]:
                dag._remove_op_node(current_node)
            if right_name == "nop":
                dag._remove_op_node(run[0])
        return dag
Exemplo n.º 21
0
def _experiments_to_circuits(qobj):
    """Return a list of QuantumCircuit object(s) from a qobj.

    Args:
        qobj (Qobj): The Qobj object to convert to QuantumCircuits

    Returns:
        list: A list of QuantumCircuit objects from the qobj
    """
    if qobj.experiments:
        circuits = []
        for x in qobj.experiments:
            quantum_registers = [
                QuantumRegister(i[1], name=i[0]) for i in x.header.qreg_sizes
            ]
            classical_registers = [
                ClassicalRegister(i[1], name=i[0]) for i in x.header.creg_sizes
            ]
            circuit = QuantumCircuit(*quantum_registers,
                                     *classical_registers,
                                     name=x.header.name)
            qreg_dict = collections.OrderedDict()
            creg_dict = collections.OrderedDict()
            for reg in quantum_registers:
                qreg_dict[reg.name] = reg
            for reg in classical_registers:
                creg_dict[reg.name] = reg
            conditional = {}
            for i in x.instructions:
                name = i.name
                qubits = []
                params = getattr(i, 'params', [])
                try:
                    for qubit in i.qubits:
                        qubit_label = x.header.qubit_labels[qubit]
                        qubits.append(
                            qreg_dict[qubit_label[0]][qubit_label[1]])
                except Exception:  # pylint: disable=broad-except
                    pass
                clbits = []
                try:
                    for clbit in i.memory:
                        clbit_label = x.header.clbit_labels[clbit]
                        clbits.append(
                            creg_dict[clbit_label[0]][clbit_label[1]])
                except Exception:  # pylint: disable=broad-except
                    pass
                if hasattr(circuit, name):
                    instr_method = getattr(circuit, name)
                    if i.name in ['snapshot']:
                        _inst = instr_method(i.label,
                                             snapshot_type=i.snapshot_type,
                                             qubits=qubits,
                                             params=params)
                    elif i.name == 'initialize':
                        _inst = instr_method(params, qubits)
                    elif i.name == 'isometry':
                        _inst = instr_method(*params, qubits, clbits)
                    else:
                        _inst = instr_method(*params, *qubits, *clbits)
                elif name == 'bfunc':
                    conditional['value'] = int(i.val, 16)
                    full_bit_size = sum([creg_dict[x].size for x in creg_dict])
                    mask_map = {}
                    raw_map = {}
                    raw = []

                    for creg in creg_dict:
                        size = creg_dict[creg].size
                        reg_raw = [1] * size
                        if not raw:
                            raw = reg_raw
                        else:
                            for pos, val in enumerate(raw):
                                if val == 1:
                                    raw[pos] = 0
                            raw = reg_raw + raw
                        mask = [0] * (full_bit_size - len(raw)) + raw
                        raw_map[creg] = mask
                        mask_map[int("".join(str(x) for x in mask), 2)] = creg
                    creg = mask_map[int(i.mask, 16)]
                    conditional['register'] = creg_dict[creg]
                    val = int(i.val, 16)
                    mask = raw_map[creg]
                    for j in reversed(mask):
                        if j == 0:
                            val = val >> 1
                        else:
                            conditional['value'] = val
                            break
                else:
                    _inst = temp_opaque_instruction = Instruction(
                        name=name,
                        num_qubits=len(qubits),
                        num_clbits=len(clbits),
                        params=params)
                    circuit.append(temp_opaque_instruction, qubits, clbits)
                if conditional and name != 'bfunc':
                    _inst.c_if(conditional['register'], conditional['value'])
                    conditional = {}
            circuits.append(circuit)
        return circuits
    return None
Exemplo n.º 22
0
def optimize_1q_gates(circuit):
    """Simplify runs of single qubit gates in the QX basis.

    Return a new circuit that has been optimized.
    """
    from qiskit.transpiler.passes.mapping.unroller import Unroller
    qx_basis = ["u1", "u2", "u3", "cx", "id"]
    unrolled = Unroller(qx_basis).run(circuit)

    runs = unrolled.collect_runs(["u1", "u2", "u3", "id"])
    for run in runs:
        run_qarg = unrolled.multi_graph.node[run[0]]["qargs"][0]
        right_name = "u1"
        right_parameters = (N(0), N(0), N(0))  # (theta, phi, lambda)
        for current_node in run:
            nd = unrolled.multi_graph.node[current_node]
            left_name = nd["name"]
            if (nd["condition"] is not None or len(nd["qargs"]) != 1
                    or nd["qargs"][0] != run_qarg
                    or left_name not in ["u1", "u2", "u3", "id"]):
                raise MapperError("internal error")
            if left_name == "u1":
                left_parameters = (N(0), N(0), nd["op"].param[0])
            elif left_name == "u2":
                left_parameters = (sympy.pi / 2, nd["op"].param[0],
                                   nd["op"].param[1])
            elif left_name == "u3":
                left_parameters = tuple(nd["op"].param)
            else:
                left_name = "u1"  # replace id with u1
                left_parameters = (N(0), N(0), N(0))
            # Compose gates
            name_tuple = (left_name, right_name)
            if name_tuple == ("u1", "u1"):
                # u1(lambda1) * u1(lambda2) = u1(lambda1 + lambda2)
                right_parameters = (N(0), N(0),
                                    right_parameters[2] + left_parameters[2])
            elif name_tuple == ("u1", "u2"):
                # u1(lambda1) * u2(phi2, lambda2) = u2(phi2 + lambda1, lambda2)
                right_parameters = (sympy.pi / 2,
                                    right_parameters[1] + left_parameters[2],
                                    right_parameters[2])
            elif name_tuple == ("u2", "u1"):
                # u2(phi1, lambda1) * u1(lambda2) = u2(phi1, lambda1 + lambda2)
                right_name = "u2"
                right_parameters = (sympy.pi / 2, left_parameters[1],
                                    right_parameters[2] + left_parameters[2])
            elif name_tuple == ("u1", "u3"):
                # u1(lambda1) * u3(theta2, phi2, lambda2) =
                #     u3(theta2, phi2 + lambda1, lambda2)
                right_parameters = (right_parameters[0],
                                    right_parameters[1] + left_parameters[2],
                                    right_parameters[2])
            elif name_tuple == ("u3", "u1"):
                # u3(theta1, phi1, lambda1) * u1(lambda2) =
                #     u3(theta1, phi1, lambda1 + lambda2)
                right_name = "u3"
                right_parameters = (left_parameters[0], left_parameters[1],
                                    right_parameters[2] + left_parameters[2])
            elif name_tuple == ("u2", "u2"):
                # Using Ry(pi/2).Rz(2*lambda).Ry(pi/2) =
                #    Rz(pi/2).Ry(pi-2*lambda).Rz(pi/2),
                # u2(phi1, lambda1) * u2(phi2, lambda2) =
                #    u3(pi - lambda1 - phi2, phi1 + pi/2, lambda2 + pi/2)
                right_name = "u3"
                right_parameters = (sympy.pi - left_parameters[2] -
                                    right_parameters[1],
                                    left_parameters[1] + sympy.pi / 2,
                                    right_parameters[2] + sympy.pi / 2)
            elif name_tuple[1] == "nop":
                right_name = left_name
                right_parameters = left_parameters
            else:
                # For composing u3's or u2's with u3's, use
                # u2(phi, lambda) = u3(pi/2, phi, lambda)
                # together with the qiskit.mapper.compose_u3 method.
                right_name = "u3"
                # Evaluate the symbolic expressions for efficiency
                left_parameters = tuple(
                    map(lambda x: x.evalf(), list(left_parameters)))
                right_parameters = tuple(
                    map(lambda x: x.evalf(), list(right_parameters)))
                right_parameters = compose_u3(left_parameters[0],
                                              left_parameters[1],
                                              left_parameters[2],
                                              right_parameters[0],
                                              right_parameters[1],
                                              right_parameters[2])
                # Why evalf()? This program:
                #   OPENQASM 2.0;
                #   include "qelib1.inc";
                #   qreg q[2];
                #   creg c[2];
                #   u3(0.518016983430947*pi,1.37051598592907*pi,1.36816383603222*pi) q[0];
                #   u3(1.69867232277986*pi,0.371448347747471*pi,0.461117217930936*pi) q[0];
                #   u3(0.294319836336836*pi,0.450325871124225*pi,1.46804720442555*pi) q[0];
                #   measure q -> c;
                # took >630 seconds (did not complete) to optimize without
                # calling evalf() at all, 19 seconds to optimize calling
                # evalf() AFTER compose_u3, and 1 second to optimize
                # calling evalf() BEFORE compose_u3.
            # 1. Here down, when we simplify, we add f(theta) to lambda to
            # correct the global phase when f(theta) is 2*pi. This isn't
            # necessary but the other steps preserve the global phase, so
            # we continue in that manner.
            # 2. The final step will remove Z rotations by 2*pi.
            # 3. Note that is_zero is true only if the expression is exactly
            # zero. If the input expressions have already been evaluated
            # then these final simplifications will not occur.
            # TODO After we refactor, we should have separate passes for
            # exact and approximate rewriting.

            # Y rotation is 0 mod 2*pi, so the gate is a u1
            if (right_parameters[0] % (2 * sympy.pi)).is_zero \
                    and right_name != "u1":
                right_name = "u1"
                right_parameters = (0, 0, right_parameters[1] +
                                    right_parameters[2] + right_parameters[0])
            # Y rotation is pi/2 or -pi/2 mod 2*pi, so the gate is a u2
            if right_name == "u3":
                # theta = pi/2 + 2*k*pi
                if ((right_parameters[0] - sympy.pi / 2) %
                    (2 * sympy.pi)).is_zero:
                    right_name = "u2"
                    right_parameters = (sympy.pi / 2, right_parameters[1],
                                        right_parameters[2] +
                                        (right_parameters[0] - sympy.pi / 2))
                # theta = -pi/2 + 2*k*pi
                if ((right_parameters[0] + sympy.pi / 2) %
                    (2 * sympy.pi)).is_zero:
                    right_name = "u2"
                    right_parameters = (sympy.pi / 2,
                                        right_parameters[1] + sympy.pi,
                                        right_parameters[2] - sympy.pi +
                                        (right_parameters[0] + sympy.pi / 2))
            # u1 and lambda is 0 mod 2*pi so gate is nop (up to a global phase)
            if right_name == "u1" and (right_parameters[2] %
                                       (2 * sympy.pi)).is_zero:
                right_name = "nop"
            # Simplify the symbolic parameters
            right_parameters = tuple(
                map(sympy.simplify, list(right_parameters)))
        # Replace the data of the first node in the run
        new_op = Instruction("", [], [], [])
        if right_name == "u1":
            new_op = U1Gate(right_parameters[2], run_qarg)
        if right_name == "u2":
            new_op = U2Gate(right_parameters[1], right_parameters[2], run_qarg)
        if right_name == "u3":
            new_op = U3Gate(*right_parameters, run_qarg)

        nx.set_node_attributes(unrolled.multi_graph,
                               name='name',
                               values={run[0]: right_name})
        nx.set_node_attributes(unrolled.multi_graph,
                               name='op',
                               values={run[0]: new_op})
        # Delete the other nodes in the run
        for current_node in run[1:]:
            unrolled._remove_op_node(current_node)
        if right_name == "nop":
            unrolled._remove_op_node(run[0])
    return unrolled