Exemplo n.º 1
0
    def _decompose_(self, qubits):
        qubits = list(qubits)

        controls = qubits[:self.reg_size]
        target = qubits[self.reg_size]
        ancilla = qubits[self.reg_size + 1:]

        if len(controls) == 2:
            yield ops.CCX(controls[0], controls[1], target)
        elif len(controls) == 1:
            yield ops.CNOT(controls[0], target)
        else:
            # Build the list
            depth = int(np.ceil(np.log2(len(controls))) - 1)
            new_bits = controls
            curr_ancil = 0
            store_gates = []
            for layer in range(depth):
                bits = new_bits
                new_bits = []
                for i in range(len(bits) // 2):
                    g = ops.CCX(bits[2 * i], bits[2 * i + 1],
                                ancilla[curr_ancil])
                    yield g
                    store_gates.append(g)
                    new_bits.append(ancilla[curr_ancil])
                    curr_ancil = curr_ancil + 1
                if len(bits) % 2 == 1:
                    new_bits.append(bits[-1])
            yield ops.CCX(new_bits[0], new_bits[1], target)
            # Get the ancilla back
            yield from cirq.inverse(store_gates)
Exemplo n.º 2
0
    def _decompose_(self, qubits):
        qubits = list(qubits)

        controls = qubits[:self.reg_size - 1]
        target = qubits[self.reg_size - 1]
        bbits = qubits[self.reg_size:]

        if len(controls) == 2:
            yield ops.CCX(controls[0], controls[1], target)
        elif len(controls) == 1:
            yield ops.CNOT(controls[0], target)
        else:
            # Build the list
            bits = []
            bits.append(controls[0])
            for i in range(1, len(controls) - 1):
                bits.append(controls[i])
                bits.append(bbits[i - 1])
            bits.append(controls[-1])
            bits.append(target)

            for i in range(len(bits) - 1, 0, -2):
                yield ops.CCX(bits[i - 2], bits[i - 1], bits[i])

            for i in range(4, len(bits) - 2, 2):
                yield ops.CCX(bits[i - 2], bits[i - 1], bits[i])

            for i in range(len(bits) - 1, 0, -2):
                yield ops.CCX(bits[i - 2], bits[i - 1], bits[i])

            for i in range(4, len(bits) - 2, 2):
                yield ops.CCX(bits[i - 2], bits[i - 1], bits[i])
Exemplo n.º 3
0
    def _decompose_(self, qubits):
        qubits = list(qubits)

        assert len(qubits) == 2 * self.register_size

        A = qubits[:self.register_size]
        B = qubits[self.register_size:]

        for i in range(1, self.register_size):
            yield ops.CNOT(A[i], B[i])

        for i in reversed(range(1, self.register_size - 1)):
            yield ops.CNOT(A[i], A[i + 1])

        for i in range(self.register_size - 1):
            yield ops.CCX(A[i], B[i], A[i + 1])

        for i in reversed(range(1, self.register_size)):
            yield ops.CNOT(A[i], B[i])
            yield ops.CCX(A[i - 1], B[i - 1], A[i])

        for i in range(1, self.register_size - 1):
            yield ops.CNOT(A[i], A[i + 1])

        for i in range(self.register_size):
            yield ops.CNOT(A[i], B[i])
    def _linear_increment_n_bb(self, qubits):
        # Expecting qubits = [x1, A, x2, B, x3, C, ..., Z] i.e. alternating bb with ob = output bit
        for i in range(1, len(qubits) - 2, 2):
            yield ops.CNOT(qubits[0], qubits[i])
            yield ops.X(qubits[i + 1])
        yield ops.X(qubits[-1])

        for i in range(2, len(qubits) - 1, 2):
            yield ops.CNOT(qubits[i - 2], qubits[i - 1])
            yield ops.CCX(qubits[i], qubits[i - 1], qubits[i - 2])
            yield ops.CCX(qubits[i - 2], qubits[i - 1], qubits[i])
        yield ops.CNOT(qubits[-2], qubits[-1])

        for i in reversed(range(2, len(qubits) - 1, 2)):
            yield ops.CCX(qubits[i - 2], qubits[i - 1], qubits[i])
            yield ops.CCX(qubits[i], qubits[i - 1], qubits[i - 2])
            yield ops.CNOT(qubits[i], qubits[i - 1])

        for i in range(2, len(qubits) - 1, 2):
            yield ops.X(qubits[i])

        for i in range(2, len(qubits) - 1, 2):
            yield ops.CNOT(qubits[i - 2], qubits[i - 1])
            yield ops.CCX(qubits[i], qubits[i - 1], qubits[i - 2])
            yield ops.CCX(qubits[i - 2], qubits[i - 1], qubits[i])
        yield ops.CNOT(qubits[-2], qubits[-1])

        for i in reversed(range(2, len(qubits) - 1, 2)):
            yield ops.CCX(qubits[i - 2], qubits[i - 1], qubits[i])
            yield ops.CCX(qubits[i], qubits[i - 1], qubits[i - 2])
            yield ops.CNOT(qubits[i], qubits[i - 1])

        for i in range(1, len(qubits) - 2, 2):
            yield ops.CNOT(qubits[0], qubits[i])
Exemplo n.º 5
0
	def _decompose_half(self, qubits):
		if len(qubits) % 2 != 0:
			# Expecting list of qubits of type [A, B, x1, C, x2, D, x3, ..., Z, T] where xi are borrowed bits
			for i in range(len(qubits) - 1, 0, -2):
				yield ops.CCX(qubits[i-2], qubits[i-1], qubits[i])

			for i in range(4, len(qubits) - 2, 2):
				yield ops.CCX(qubits[i-2], qubits[i-1], qubits[i])

			for i in range(len(qubits) - 1, 0, -2):
				yield ops.CCX(qubits[i-2], qubits[i-1], qubits[i])

			for i in range(4, len(qubits) - 2, 2):
				yield ops.CCX(qubits[i-2], qubits[i-1], qubits[i])
		else:
			# Expecting list of qubits of type [A, x1, B, x2, ..., x_n-2, Z, T]
			for i in range(len(qubits) - 1, 1, -2):
				yield ops.CCX(qubits[i-2], qubits[i-1], qubits[i])
			# Handle the top CNOT separately
			yield ops.CNOT(qubits[0], qubits[1])
			for i in range(3, len(qubits) - 2, 2):
				yield ops.CCX(qubits[i-2], qubits[i-1], qubits[i])

			for i in range(len(qubits) - 1, 1, -2):
				yield ops.CCX(qubits[i-2], qubits[i-1], qubits[i])
			# Handle the top CNOT separately
			yield ops.CNOT(qubits[0], qubits[1])
			for i in range(3, len(qubits) - 2, 2):
				yield ops.CCX(qubits[i-2], qubits[i-1], qubits[i])
Exemplo n.º 6
0
	def default_decompose(self, qubits):
		# Qubits [q0, q1, ..., qn-1, qn] where qn-1 is target, qn is a borrowed bit
		qbits = list(qubits)
		if len(qbits) == 4:
			yield ops.CCX(qbits[0], qbits[1], qbits[2])
		elif len(qbits) == 3:
			yield ops.CNOT(qbits[0], qbits[1])
		elif len(qbits) == 5:
			yield ops.CCX(qbits[0], qbits[1], qbits[-1])
			yield ops.CCX(qbits[2], qbits[-1], qbits[3])
			yield ops.CCX(qbits[0], qbits[1], qbits[-1])
			yield ops.CCX(qbits[2], qbits[-1], qbits[3])
		else:
			yield self._decompose(qbits)
Exemplo n.º 7
0
 def backward(groups):
     for g in groups[1:-1]:
         if len(g) == 3:
             yield ops.CCX(*g)
         elif len(g) == 2:
             yield ops.CNOT(*g)
         else:
             half_borrowed_gate = CnUHalfBorrowedGate(register_size=len(g))
             yield half_borrowed_gate(*g, *find_dirty(groups, g))
 def _decompose_(self, qubits):
     qubits = list(qubits)
     if len(qubits) == 2:
         yield ops.CNOT(*qubits)
     elif len(qubits) == 1:
         yield ops.X(*qubits)
     elif len(qubits) == 3:
         yield ops.CCX(*qubits)
     else:
         yield self._startdecompose(qubits)
    def _maj(reg):
        """
			applies the MAJ operator to a three bit register

			------X--@----
			---X--|--@----
			---@--@--X----

		"""
        yield ops.CNOT(reg[2], reg[1])
        yield ops.CNOT(reg[2], reg[0])
        yield ops.CCX(reg[0], reg[1], reg[2])
    def _uma_parallel(reg):
        """
			applies the UMA operator which maximizes parallism

			------@---@----X-----
			--X---X---@--X-|--X--
			----------X----@--@--

		"""
        yield ops.X(reg[1])
        yield ops.CNOT(reg[0], reg[1])
        yield ops.CCX(reg[0], reg[1], reg[2])
        yield ops.X(reg[1])
        yield ops.CNOT(reg[2], reg[0])
        yield ops.CNOT(reg[2], reg[1])
    def _decompose_(self, qubits):
        qubits = list(qubits)

        assert len(
            qubits
        ) > self.control_size, f'MultiControlGate cannot be applied to fewer than {self.control_size + 1} bits'

        if len(qubits) == self.control_size + 1:
            cnx_inplace = CnXLinearGate(reg_size=len(qubits))
            yield cnx_inplace(*qubits)
        else:
            controls = qubits[:self.control_size]
            target = qubits[self.control_size]
            ancilla = qubits[(self.control_size + 1):(self.control_size +
                                                      self.ancilla_size + 1)]
            dirty = qubits[(self.control_size + self.ancilla_size + 1):]
            n = len(controls)
            m = len(ancilla)
            self._multi_control(n, m)
            base_controls, base_target, base_ancilla, base_dirty = yield from self._prep_gates(
                qubits, n, m)

            if len(base_controls) == 2:
                yield ops.CCX(base_controls[0], base_controls[1], target)
            elif len(base_controls) == 1:
                yield ops.CNOT(base_controls[0], target)
            else:
                if len(base_ancilla) == 0:
                    dirty_gate = CnUHalfBorrowedGate(len(base_controls) + 1)
                    dirt = base_dirty + base_ancilla
                    dirty_qubit_list = base_controls + [target] + dirt[:(
                        len(base_controls) - 2)]
                    apply_dirty = dirty_gate.on(*dirty_qubit_list)
                    yield apply_dirty

            yield (cirq.inverse(self._prep_gates(qubits, n, m)))
Exemplo n.º 12
0
    def _decompose_(self, qubits):

        def find_dirty(groups, g):
            d = []
            for f in groups:
                for e in f:
                    if e not in g and e not in d:
                        d.append(e)
                        if len(d) == len(g) - 3:
                            return d
            return d

        assert len(qubits) >= self.n + 1, f'Invalid application of a {self.n} control gate to {len(qubits)}'


        qubits = list(qubits)
        controls = qubits[:self.n]
        target = qubits[self.n]
        ancilla = qubits[self.n+1:]

        m = len(ancilla)
        assert m > 0, f'If 0 ancilla are provided, please use a cnx_inplace gate instead.'

        if len(controls) == 2:
            yield ops.CCX(controls[0], controls[1], target)
        elif len(controls) == 1:
            yield ops.CNOT(controls[0], target)
        else:
            if len(ancilla) > self.n - 2:
                half_borrowed_gate = CnUHalfBorrowedGate(register_size=self.n+1)
                yield half_borrowed_gate(*controls, target, *ancilla[:self.n - 2])
            else:
                # Group the controls into m + 1 groups, do as many toffoli's as possible then start filling until can't be done
                groups = [[] for _ in range(m + 1)]

                #for i in range(1, m):
                #    groups[i].append(ancilla[i-1])

                groups[0].append(controls[0])
                for i in range(m + 1):
                    groups[i].append(controls[i+1])

                i = m+2
                which_group = -1
                while i < len(controls):
                    if which_group == 0:
                        groups[0].append(controls[i])
                        i += 1
                        which_group = -1
                    else:
                        g = groups[-1]
                        free = sum([len(gg) if gg != g else 0 for gg in groups]) + len(ancilla) - 1
                        while len(g) + 1 < free + 2:
                            g.append(controls[i])
                            i += 1
                            if i >= len(controls):
                                break
                        if i >= len(controls):
                            break
                        which_group = 0

                for i in range(m + 1):
                    if i != 0:
                        groups[i].insert(0, groups[i-1][-1])
                    if i < m:
                        groups[i].append(ancilla.pop(0))
                    else:
                        groups[i].append(target)

                def forward(groups):
                    for g in reversed(groups):
                        if len(g) == 3:
                            yield ops.CCX(*g)
                        elif len(g) == 2:
                            yield ops.CNOT(*g)
                        else:
                            half_borrowed_gate = CnUHalfBorrowedGate(register_size=len(g))
                            yield half_borrowed_gate(*g, *find_dirty(groups, g))

                def backward(groups):
                    for g in groups[1:-1]:
                        if len(g) == 3:
                            yield ops.CCX(*g)
                        elif len(g) == 2:
                            yield ops.CNOT(*g)
                        else:
                            half_borrowed_gate = CnUHalfBorrowedGate(register_size=len(g))
                            yield half_borrowed_gate(*g, *find_dirty(groups, g))

                yield forward(groups)
                yield backward(groups)
                yield forward(groups)
                yield backward(groups)