def test_opaque_gate_with_label(self):
     """Test that custom opaque gate is correctly serialized with a label"""
     custom_gate = Gate("black_box", 1, [])
     custom_gate.label = "My Special Black Box"
     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])
예제 #2
0
    def test_compose_calibrations(self):
        """Test that compose carries over the calibrations."""
        dag_cal = QuantumCircuit(1)
        dag_cal.append(Gate('', 1, []), qargs=[0])
        dag_cal.add_calibration(Gate('', 1, []), [0], Schedule())

        empty_dag = circuit_to_dag(QuantumCircuit(1))
        calibrated_dag = circuit_to_dag(dag_cal)
        composed_dag = empty_dag.compose(calibrated_dag, inplace=False)

        cal = {'': {((0, ), ()): Schedule(name="sched0")}}
        self.assertEqual(composed_dag.calibrations, cal)
        self.assertEqual(calibrated_dag.calibrations, cal)
예제 #3
0
    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
예제 #4
0
    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
예제 #5
0
    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
예제 #6
0
    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_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())
예제 #8
0
    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
예제 #9
0
 def test_opaque_gate(self):
     """Test that custom opaque gate is correctly serialized"""
     custom_gate = Gate("black_box", 1, [])
     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)
    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])
예제 #11
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
예제 #12
0
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
예제 #13
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)
예제 #14
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)
    def test_custom_gate_with_noop_definition(self):
        """Test that a custom gate whose definition contains no elements is serialized with a
        proper definition.

        Regression test of gh-7429."""
        empty = QuantumCircuit(1, name="empty").to_gate()
        opaque = Gate("opaque", 1, [])
        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)
예제 #16
0
def generate_calibrated_circuits():
    """Test for QPY serialization with calibrations."""
    from qiskit.pulse import builder, Constant, DriveChannel

    circuits = []

    # custom gate
    mygate = Gate("mygate", 1, [])
    qc = QuantumCircuit(1)
    qc.append(mygate, [0])
    with builder.build() as caldef:
        builder.play(Constant(100, 0.1), DriveChannel(0))
    qc.add_calibration(mygate, (0, ), caldef)
    circuits.append(qc)
    # override instruction
    qc = QuantumCircuit(1)
    qc.x(0)
    with builder.build() as caldef:
        builder.play(Constant(100, 0.1), DriveChannel(0))
    qc.add_calibration("x", (0, ), caldef)
    circuits.append(qc)

    return circuits
예제 #17
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:
            right_name = "u1"
            right_parameters = (0, 0, 0)  # (theta, phi, lambda)

            for current_node in run:
                left_name = current_node.name
                if (current_node.condition is not None
                        or len(current_node.qargs) != 1
                        or left_name not in ["u1", "u2", "u3", "id"]):
                    raise MapperError("internal error")
                if left_name == "u1":
                    left_parameters = (0, 0, current_node.op.params[0])
                elif left_name == "u2":
                    left_parameters = (np.pi / 2, current_node.op.params[0],
                                       current_node.op.params[1])
                elif left_name == "u3":
                    left_parameters = tuple(current_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 the first node in the run with a dummy DAG which contains a dummy
            # qubit. The name is irrelevant, because substitute_node_with_dag will take care of
            # putting it in the right place.
            run_qarg = (QuantumRegister(1, 'q'), 0)
            new_op = Gate(name="", num_qubits=1, params=[])
            if right_name == "u1":
                new_op = U1Gate(right_parameters[2])
            if right_name == "u2":
                new_op = U2Gate(right_parameters[1], right_parameters[2])
            if right_name == "u3":
                new_op = U3Gate(*right_parameters)

            if right_name != 'nop':
                new_dag = DAGCircuit()
                new_dag.add_qreg(run_qarg[0])
                new_dag.apply_operation_back(new_op, [run_qarg], [])
                dag.substitute_node_with_dag(run[0], new_dag)

            # 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
예제 #18
0
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
예제 #19
0
    def run(self, dag):
        """Run the Optimize1qGates pass on `dag`.

        Args:
            dag (DAGCircuit): the DAG to be optimized.

        Returns:
            DAGCircuit: the optimized DAG.

        Raises:
            TranspilerError: if YZY and ZYZ angles do not give same rotation matrix.
        """
        use_u = 'u' in self.basis
        use_p = 'p' in self.basis
        runs = dag.collect_runs(["u1", "u2", "u3", "u", 'p'])
        runs = _split_runs_on_parameters(runs)
        for run in runs:
            if use_p:
                right_name = "p"
            else:
                right_name = "u1"
            right_parameters = (0, 0, 0)  # (theta, phi, lambda)
            right_global_phase = 0
            for current_node in run:
                left_name = current_node.name
                if (current_node.condition is not None
                        or len(current_node.qargs) != 1
                        or left_name not in ["p", "u1", "u2", "u3", 'u', "id"]):
                    raise TranspilerError("internal error")
                if left_name in ("u1", "p"):
                    left_parameters = (0, 0, current_node.op.params[0])
                elif left_name == "u2":
                    left_parameters = (np.pi / 2, current_node.op.params[0],
                                       current_node.op.params[1])
                elif left_name in ("u3", 'u'):
                    left_parameters = tuple(current_node.op.params)
                else:
                    if use_p:
                        left_name = "p"
                    else:
                        left_name = "u1"  # replace id with u1
                    left_parameters = (0, 0, 0)
                if (current_node.op.definition is not None and
                        current_node.op.definition.global_phase):
                    right_global_phase += current_node.op.definition.global_phase
                # 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 in (("u1", "u1"), ("p", "p")):
                    # u1(lambda1) * u1(lambda2) = u1(lambda1 + lambda2)
                    right_parameters = (0, 0, right_parameters[2] +
                                        left_parameters[2])
                elif name_tuple in (("u1", "u2"), ("p", "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 in (("u2", "u1"), ("u2", "p")):
                    # 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 in (("u1", "u3"), ("u1", "u"), ("p", "u3"), ("p", "u")):
                    # 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 in (("u3", "u1"), ('u', 'u1'), ("u3", "p"), ("u", "p")):
                    # u3(theta1, phi1, lambda1) * u1(lambda2) =
                    #     u3(theta1, phi1, lambda1 + lambda2)
                    if use_u:
                        right_name = 'u'
                    else:
                        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)
                    if use_u:
                        right_name = 'u'
                    else:
                        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.
                    if use_u:
                        right_name = 'u'
                    else:
                        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 abs(np.mod(right_parameters[0],
                              (2 * np.pi))) < self.eps and right_name != "u1" \
                        and right_name != "p":
                    if use_p:
                        right_name = "p"
                    else:
                        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" or 'u':
                    # theta = pi/2 + 2*k*pi
                    right_angle = right_parameters[0] - np.pi / 2
                    if abs(right_angle) < self.eps:
                        right_angle = 0
                    if abs(np.mod((right_angle),
                                  2 * np.pi)) < self.eps:
                        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
                    right_angle = right_parameters[0] + np.pi / 2
                    if abs(right_angle) < self.eps:
                        right_angle = 0
                    if abs(np.mod(right_angle,
                                  2 * np.pi)) < self.eps:
                        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 in ("u1", "p") and abs(
                        np.mod(right_parameters[2], 2 * np.pi)) < self.eps:
                    right_name = "nop"

            if right_name == "u2" and "u2" not in self.basis:
                if use_u:
                    right_name = 'u'
                else:
                    right_name = "u3"
            if right_name in ("u1", "p") and right_name not in self.basis:
                if use_u:
                    right_name = 'u'
                else:
                    right_name = "u3"

            new_op = Gate(name="", num_qubits=1, params=[])
            if right_name == "u1":
                new_op = U1Gate(right_parameters[2])
            if right_name == "p":
                new_op = PhaseGate(right_parameters[2])
            if right_name == "u2":
                new_op = U2Gate(right_parameters[1], right_parameters[2])
            if right_name == "u":
                if "u" in self.basis:
                    new_op = UGate(*right_parameters)
            if right_name == "u3":
                if "u3" in self.basis:
                    new_op = U3Gate(*right_parameters)
                else:
                    raise TranspilerError('It was not possible to use the basis %s' % self.basis)

            dag.global_phase += right_global_phase

            if right_name != 'nop':
                dag.substitute_node(run[0], new_op, inplace=True)

            # 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
예제 #20
0
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 convert_to_target(conf_dict: dict,
                      props_dict: dict = None,
                      defs_dict: dict = None) -> Target:
    """Uses configuration, properties and pulse defaults dicts
    to construct and return Target class.
    """
    name_mapping = {
        "id": IGate(),
        "sx": SXGate(),
        "x": XGate(),
        "cx": CXGate(),
        "rz": RZGate(Parameter("λ")),
        "reset": Reset(),
    }
    custom_gates = {}
    qubit_props = None
    if props_dict:
        qubit_props = qubit_props_from_props(props_dict)
    target = Target(qubit_properties=qubit_props)
    # Parse from properties if it exsits
    if props_dict is not None:
        # Parse instructions
        gates = {}
        for gate in props_dict["gates"]:
            name = gate["gate"]
            if name in name_mapping:
                if name not in gates:
                    gates[name] = {}
            elif name not in custom_gates:
                custom_gate = Gate(name, len(gate["qubits"]), [])
                custom_gates[name] = custom_gate
                gates[name] = {}

            qubits = tuple(gate["qubits"])
            gate_props = {}
            for param in gate["parameters"]:
                if param["name"] == "gate_error":
                    gate_props["error"] = param["value"]
                if param["name"] == "gate_length":
                    gate_props["duration"] = apply_prefix(
                        param["value"], param["unit"])
            gates[name][qubits] = InstructionProperties(**gate_props)
        for gate, props in gates.items():
            if gate in name_mapping:
                inst = name_mapping.get(gate)
            else:
                inst = custom_gates[gate]
            target.add_instruction(inst, props)
        # Create measurement instructions:
        measure_props = {}
        count = 0
        for qubit in props_dict["qubits"]:
            qubit_prop = {}
            for prop in qubit:
                if prop["name"] == "readout_length":
                    qubit_prop["duration"] = apply_prefix(
                        prop["value"], prop["unit"])
                if prop["name"] == "readout_error":
                    qubit_prop["error"] = prop["value"]
            measure_props[(count, )] = InstructionProperties(**qubit_prop)
            count += 1
        target.add_instruction(Measure(), measure_props)
    # Parse from configuration because properties doesn't exist
    else:
        for gate in conf_dict["gates"]:
            name = gate["name"]
            gate_props = {tuple(x): None for x in gate["coupling_map"]}
            if name in name_mapping:
                target.add_instruction(name_mapping[name], gate_props)
            else:
                custom_gate = Gate(name, len(gate["coupling_map"][0]), [])
                target.add_instruction(custom_gate, gate_props)
        measure_props = {(n, ): None for n in range(conf_dict["n_qubits"])}
        target.add_instruction(Measure(), measure_props)
    # parse global configuration properties
    dt = conf_dict.get("dt")
    if dt:
        target.dt = dt * 1e-9
    if "timing_constraints" in conf_dict:
        target.granularity = conf_dict["timing_constraints"].get("granularity")
        target.min_length = conf_dict["timing_constraints"].get("min_length")
        target.pulse_alignment = conf_dict["timing_constraints"].get(
            "pulse_alignment")
        target.aquire_alignment = conf_dict["timing_constraints"].get(
            "acquire_alignment")
    # If pulse defaults exists use that as the source of truth
    if defs_dict is not None:
        # TODO remove the usage of PulseDefaults as it will be deprecated in the future
        pulse_defs = PulseDefaults.from_dict(defs_dict)
        inst_map = pulse_defs.instruction_schedule_map
        for inst in inst_map.instructions:
            for qarg in inst_map.qubits_with_instruction(inst):
                sched = inst_map.get(inst, qarg)
                if inst in target:
                    try:
                        qarg = tuple(qarg)
                    except TypeError:
                        qarg = (qarg, )
                    if inst == "measure":
                        for qubit in qarg:
                            target[inst][(qubit, )].calibration = sched
                    else:
                        target[inst][qarg].calibration = sched
    target.add_instruction(Delay(Parameter("t")),
                           {(bit, ): None
                            for bit in range(target.num_qubits)})
    return target
 def _return_repeat(self, exponent: float) -> "Gate":
     return Gate(name=f"{self.name}*{exponent}",
                 num_qubits=self.num_qubits,
                 params=[])
예제 #23
0
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 convert_to_target(
    configuration: BackendConfiguration,
    properties: BackendProperties = None,
    defaults: PulseDefaults = None,
) -> Target:
    """Uses configuration, properties and pulse defaults
    to construct and return Target class.
    """
    name_mapping = {
        "id": IGate(),
        "sx": SXGate(),
        "x": XGate(),
        "cx": CXGate(),
        "rz": RZGate(Parameter("λ")),
        "reset": Reset(),
    }
    custom_gates = {}
    target = None
    # Parse from properties if it exsits
    if properties is not None:
        qubit_properties = qubit_props_list_from_props(properties=properties)
        target = Target(
            num_qubits=configuration.n_qubits, qubit_properties=qubit_properties
        )
        # Parse instructions
        gates: Dict[str, Any] = {}
        for gate in properties.gates:
            name = gate.gate
            if name in name_mapping:
                if name not in gates:
                    gates[name] = {}
            elif name not in custom_gates:
                custom_gate = Gate(name, len(gate.qubits), [])
                custom_gates[name] = custom_gate
                gates[name] = {}

            qubits = tuple(gate.qubits)
            gate_props = {}
            for param in gate.parameters:
                if param.name == "gate_error":
                    gate_props["error"] = param.value
                if param.name == "gate_length":
                    gate_props["duration"] = apply_prefix(param.value, param.unit)
            gates[name][qubits] = InstructionProperties(**gate_props)
        for gate, props in gates.items():
            if gate in name_mapping:
                inst = name_mapping.get(gate)
            else:
                inst = custom_gates[gate]
            target.add_instruction(inst, props)
        # Create measurement instructions:
        measure_props = {}
        for qubit, _ in enumerate(properties.qubits):
            measure_props[(qubit,)] = InstructionProperties(
                duration=properties.readout_length(qubit),
                error=properties.readout_error(qubit),
            )
        target.add_instruction(Measure(), measure_props)
    # Parse from configuration because properties doesn't exist
    else:
        target = Target(num_qubits=configuration.n_qubits)
        for gate in configuration.gates:
            name = gate.name
            gate_props = (
                {tuple(x): None for x in gate.coupling_map}  # type: ignore[misc]
                if hasattr(gate, "coupling_map")
                else {None: None}
            )
            gate_len = len(gate.coupling_map[0]) if hasattr(gate, "coupling_map") else 0
            if name in name_mapping:
                target.add_instruction(name_mapping[name], gate_props)
            else:
                custom_gate = Gate(name, gate_len, [])
                target.add_instruction(custom_gate, gate_props)
        target.add_instruction(Measure())
    # parse global configuration properties
    if hasattr(configuration, "dt"):
        target.dt = configuration.dt
    if hasattr(configuration, "timing_constraints"):
        target.granularity = configuration.timing_constraints.get("granularity")
        target.min_length = configuration.timing_constraints.get("min_length")
        target.pulse_alignment = configuration.timing_constraints.get("pulse_alignment")
        target.aquire_alignment = configuration.timing_constraints.get(
            "acquire_alignment"
        )
    # If a pulse defaults exists use that as the source of truth
    if defaults is not None:
        inst_map = defaults.instruction_schedule_map
        for inst in inst_map.instructions:
            for qarg in inst_map.qubits_with_instruction(inst):
                sched = inst_map.get(inst, qarg)
                if inst in target:
                    try:
                        qarg = tuple(qarg)
                    except TypeError:
                        qarg = (qarg,)
                    if inst == "measure":
                        for qubit in qarg:
                            target[inst][(qubit,)].calibration = sched
                    else:
                        target[inst][qarg].calibration = sched
    if "delay" not in target:
        target.add_instruction(
            Delay(Parameter("t")), {(bit,): None for bit in range(target.num_qubits)}
        )
    return target