示例#1
0
def test_fused_gate_construct_unitary(backend):
    gate = gates.FusedGate(0, 1)
    gate.add(gates.H(0))
    gate.add(gates.H(1))
    gate.add(gates.CZ(0, 1))
    hmatrix = np.array([[1, 1], [1, -1]]) / np.sqrt(2)
    czmatrix = np.diag([1, 1, 1, -1])
    target_matrix = czmatrix @ np.kron(hmatrix, hmatrix)
    K.assert_allclose(gate.matrix, target_matrix)
示例#2
0
 def unitary(self):
     """Creates the unitary matrix corresponding to all circuit gates.
     
     This is a ``(2 ** nqubits, 2 ** nqubits)`` matrix obtained by 
     multiplying all circuit gates.
     """
     from qibo import gates
     fgate = gates.FusedGate(*range(self.nqubits))
     for gate in self.queue:
         fgate.append(gate)
     return fgate.matrix
示例#3
0
def test_fused_gate_construct_unitary(backend, nqubits):
    gate = gates.FusedGate(0, 1)
    gate.append(gates.H(0))
    gate.append(gates.H(1))
    gate.append(gates.CZ(0, 1))
    hmatrix = np.array([[1, 1], [1, -1]]) / np.sqrt(2)
    czmatrix = np.diag([1, 1, 1, -1])
    target_matrix = czmatrix @ np.kron(hmatrix, hmatrix)
    if nqubits > 2:
        gate.append(gates.TOFFOLI(0, 1, 2))
        toffoli = np.eye(8)
        toffoli[-2:, -2:] = np.array([[0, 1], [1, 0]])
        target_matrix = toffoli @ np.kron(target_matrix, np.eye(2))
    K.assert_allclose(gate.matrix, target_matrix)
示例#4
0
def test_fused_gate_init(backend):
    gate = gates.FusedGate(0)
    gate = gates.FusedGate(0, 1)
    if K.op is not None:
        with pytest.raises(NotImplementedError):
            gate = gates.FusedGate(0, 1, 2)
示例#5
0
文件: circuit.py 项目: mlazzarin/qibo
    def fuse(self):
        """Creates an equivalent circuit with the gates fused up to two-qubits.

        Returns:
            A :class:`qibo.core.circuit.Circuit` object containing
            :class:`qibo.abstractions.gates.FusedGate` gates, each of which
            corresponds to a group of some original gates.
            For more details on the fusion algorithm we refer to the
            :ref:`Circuit fusion <circuit-fusion>` section.

        Example:
            ::

                from qibo import models, gates
                c = models.Circuit(2)
                c.add([gates.H(0), gates.H(1)])
                c.add(gates.CNOT(0, 1))
                c.add([gates.Y(0), gates.Y(1)])
                # create circuit with fused gates
                fused_c = c.fuse()
                # now ``fused_c`` contains a single ``FusedGate`` that is
                # equivalent to applying the five original gates
        """
        from qibo import gates
        from qibo.abstractions.circuit import _Queue
        from qibo.abstractions.abstract_gates import SpecialGate

        class FusedQueue(_Queue):
            """Helper queue implementation that checks if a gate already exists
            in queue to avoid re-appending it.
            """
            def __init__(self, *args, **kwargs):
                super().__init__(*args, **kwargs)
                self.set = set()

            def append(self, gate):
                """Appends a gate in queue only if it is not already in."""
                # Use a ``set`` instead of the original ``list`` to check if
                # the gate already exists in queue as lookup is typically
                # more efficient for sets
                # (although actual performance difference is probably negligible)
                if gate not in self.set:
                    self.set.add(gate)
                    super().append(gate)

        # new circuit queue that will hold the fused gates
        fused_queue = FusedQueue(self.nqubits)
        # dictionary that maps each qubit id (int) to the corresponding
        # active ``FusedGate`` that is part of
        fused_gates = collections.OrderedDict()
        # use ``OrderedDict`` so that the original gate order is not changed
        for gate in self.queue:
            qubits = gate.qubits
            if len(qubits) == 1:
                # add one-qubit gates to the active ``FusedGate`` of this qubit
                # or create a new one if it does not exist
                q = qubits[0]
                if q not in fused_gates:
                    fused_gates[q] = gates.FusedGate(q)
                fused_gates.get(q).add(gate)

            elif len(qubits) == 2:
                # fuse two-qubit gates
                q0, q1 = tuple(sorted(qubits))
                if (q0 in fused_gates and q1 in fused_gates
                        and fused_gates.get(q0) == fused_gates.get(q1)):
                    # if the target qubit pair is compatible with the active
                    # ``FusedGate`` of both qubits then add it to the ``FusedGate``
                    fused_gates.get(q0).add(gate)
                else:
                    # otherwise we need to create a new ``FusedGate`` and
                    # update the active gates of both target qubits
                    fgate = gates.FusedGate(q0, q1)
                    if q0 in fused_gates:
                        # first qubit has existing active gate
                        ogate = fused_gates.pop(q0)
                        if len(ogate.target_qubits) == 1:
                            # existing active gate is one-qubit so we just add
                            # it to the new ``FusedGate``
                            fgate.add(ogate)
                        else:
                            # existing active gate is two-qubit so we need to
                            # add it to the new queue
                            fused_queue.append(ogate)
                    if q1 in fused_gates:
                        # second qubit has existing active gate
                        ogate = fused_gates.pop(q1)
                        if len(ogate.target_qubits) == 1:
                            # existing active gate is one-qubit so we just add
                            # it to the new ``FusedGate``
                            fgate.add(ogate)
                        else:
                            # existing active gate is two-qubit so we need to
                            # add it to the new queue
                            fused_queue.append(ogate)
                    # add the two-qubit gate to the newly created ``FusedGate``
                    # and update the active ``FusedGate``s of both target qubits
                    fgate.add(gate)
                    fused_gates[q0], fused_gates[q1] = fgate, fgate

            elif isinstance(gate, SpecialGate):
                # ``SpecialGate``s act on all qubits (like a barrier) so we
                # so we need to temporarily stop the fusion, add all active
                # gates in the new queue and restart fusion after the barrier
                for g in fused_gates.values():
                    fused_queue.append(g)
                fused_gates = collections.OrderedDict()
                fused_queue.append(gate)

            else:
                # gate has more than two target qubits so it cannot be included
                # in the ``FusedGate``s which support up to two qubits.
                # Therefore we deactivate the ``FusedGate``s of all target qubits
                for q in qubits:
                    if q in fused_gates:
                        fused_queue.append(fused_gates.pop(q))
                fused_queue.append(gate)

        for gate in fused_gates.values():
            # add remaining active ``FusedGate``s in the new queue
            fused_queue.append(gate)

        queue = _Queue(self.nqubits)
        for gate in fused_queue:
            if isinstance(gate, gates.FusedGate) and len(gate.gates) == 1:
                # replace ``FusedGate``s that contain only one gate by this
                # gate for efficiency
                gate = gate.gates[0]
            queue.append(gate)

        # create a circuit and assign the new queue
        new_circuit = self._shallow_copy()
        new_circuit.queue = queue
        return new_circuit