示例#1
0
def _decompose_CnU(cmd):  # pylint: disable=invalid-name
    """
    Decompose a multi-controlled gate U with n control qubits into a single- controlled U.

    It uses (n-1) work qubits and 2 * (n-1) Toffoli gates for general U and (n-2) work qubits and 2n - 3 Toffoli gates
    if U is an X-gate.
    """
    eng = cmd.engine
    qubits = cmd.qubits
    ctrl_qureg = cmd.control_qubits
    gate = cmd.gate
    n_controls = get_control_count(cmd)

    # specialized for X-gate
    if gate == XGate() and n_controls > 2:
        n_controls -= 1
    ancilla_qureg = eng.allocate_qureg(n_controls - 1)

    with Compute(eng):
        Toffoli | (ctrl_qureg[0], ctrl_qureg[1], ancilla_qureg[0])
        for ctrl_index in range(2, n_controls):
            Toffoli | (
                ctrl_qureg[ctrl_index],
                ancilla_qureg[ctrl_index - 2],
                ancilla_qureg[ctrl_index - 1],
            )
    ctrls = [ancilla_qureg[-1]]

    # specialized for X-gate
    if gate == XGate() and get_control_count(cmd) > 2:
        ctrls += [ctrl_qureg[-1]]
    with Control(eng, ctrls):
        gate | qubits

    Uncompute(eng)
示例#2
0
    def logical_circuit(self, eng, register, pauli_op):
        r"""
        Apply the circuit for the logical operator.

        The Y-logical operator does not have phase information, in order words it is exactly Y = XZ.

        Parameters
        ----------
        eng : BasicEngine

        register : list

        pauli_op : str
            String of the format "Xi", "Yi", "Zi", where i is a integer from 0 to k-1. E.g.
            'X0' will apply the 0th logical X-operator. There are a total of k logical X operators
            and k logical Z operators.

        Notes
        -----
        - The engine will be flushed at the end.

        Examples
        --------
        >> eng = ProjectQ engine...
        >> register = List of qubits in the engine.
        Apply the logical X operator on the first qubit.
        >> code.logical_circuit(eng, register, "X0")
        Apply the logical Z operator on the second qubit.
        >> code.logical_circuit(eng, register, "Z1"0

        """
        assert len(pauli_op) == 2, "'pauli_op' should be length two."
        assert pauli_op[0] in [
            'X', 'Y', 'Z'
        ], "First character of 'pauli_op' should be X, Y or Z."
        assert 0 <= int(
            pauli_op[1]
        ) < self.k, "Second character should be integer from 0 to k-1."

        if pauli_op[0] == 'X':
            logical_x_ith = self.logical_x[int(pauli_op[1])]
            pauli_str = StabilizerCode.binary_rep_to_pauli_str(logical_x_ith)
        elif pauli_op[0] == "Z":
            logical_z_ith = self.logical_z[int(pauli_op[1])]
            pauli_str = StabilizerCode.binary_rep_to_pauli_str(logical_z_ith)
        elif pauli_op[0] == 'Y':
            # The pauli Y is just ZX, which in binary representation is below.
            logical_y_ith = (self.logical_z[int(pauli_op[1])] +
                             self.logical_x[int(pauli_op[1])]) % 2
            pauli_str = StabilizerCode.binary_rep_to_pauli_str(logical_y_ith)

        for i, pauli_op in enumerate(pauli_str):
            if pauli_op == "X":
                XGate() | register[i]
            elif pauli_op == "Y":
                QubitOperator('Y' + str(i), -1.j) | register
            elif pauli_op == "Z":
                ZGate() | register[i]
        eng.flush()
示例#3
0
    def apply_stabilizer_circuit(self, eng, register, stabilizer):
        r"""
        Apply the stabilizer circuit to a ProjectQ Engine.

        Example: Applying "XYI" does X to first qubit register[0], and Y to second qubit
        register[1].

        Parameters
        ----------
        eng : BasicEngine
            The ProjectQ engine.
        register : list
            Holds the qubits.
        stabilizer : str or np.ndarray
            Either a pauli string representing one stabilier element or the binary representation
            of the one stabilizer element.

        Notes
        -----
        - Engine is flushed after.

        Examples
        --------
        >> eng = Project Q engine
        >> register = Qubits of Register
        >> apply_stabilizer_circuit(eng, register, "XXY")

        """
        if isinstance(stabilizer, (list, np.ndarray)):
            # Convert to Pauli String.
            pauli_str = StabilizerCode.binary_rep_to_pauli_str(stabilizer)

        for i, pauli_op in enumerate(pauli_str):
            print(pauli_op)
            if pauli_op == "X":
                XGate() | register[i]
            elif pauli_op == "Z":
                ZGate() | register[i]
            elif pauli_op == "Y":
                # ZGate() | register[i]
                # XGate() | register[i]
                # YGate() | register[i]
                QubitOperator('Y' + str(i), 1.) | register
        eng.flush()
示例#4
0
    def decoding_circuit(self,
                         eng,
                         register,
                         add_ancilla_bits=False,
                         deallocate_nqubits=False):
        r"""
        Construct the decoding circuit to map the n-qubit to its k-qubit state.

        Specifically, suppose |D>_k is the unencoded k-qubit state and |D>_n is the encoded n-qubit
        state. The decoding circuit turns the n-qubit state |D>_n \otimes |0,...,0> tensored with
        k, ancilla qubits to the state |0,..,0> \otimes |D>_k.

        Parameters
        ----------
        eng : BasicEngine
            ProjectQ engine.
        register : list
            List containing the qubits/register for the ProjectQ engine "eng".
        add_ancilla_bits : bool
            If True, it will add extra, ancilla k-qubit. If it is false, it is assumed that it was
            already added and included in 'eng' and 'register'.
        deallocate_nqubits : bool
            If True, at the end of decoding it will discard and delete the 'register' and will only
            have the k, ancilla qubits.

        Returns
        -------
        list :
            If deallocate_nqubits is false, it returns the original 'register' plus the ancilla
            register appended towards the end.
            If deallocate_nqubits is True.
                If add_ancilla_bits is True, it returns the ancilla register that was created.
                If add_ancilla_bits is False, it assumes the register has the ancilla bits and
                returns that.

        Notes
        -----
        - To construct the most optimal decoding circuit. The standard form for the stabilizer
                code needs to be constructed alongside the logical X operators.
        - The engine is flushed at the end.
        - Let r be the rank of the standard form for the stabilizer code. This decoding scheme is
            more efficient when 2k(r + 1) < nr then just reversing the encoding circuit.

        References
        ----------
        - See Gaitan book "Quantum Error-Correction and Fault Tolerant Quantum Computing."

        """
        if add_ancilla_bits:
            register_ancilla = eng.allocate_qureg(self.k)
        else:
            register_ancilla = register[self.n:]
        logical_x = self.logical_x
        logical_z = self.logical_z

        # Turn |D>|0,...,0> to |D>|D>.
        for i_ancilla in range(0, self.k):
            logical_z_ith = logical_z[i_ancilla]
            for j_qubit, binary_val in enumerate(logical_z_ith[self.n:]):
                if binary_val == 1:
                    CNOT | (register[j_qubit], register_ancilla[i_ancilla])

        # Turn |D>|D> to |0,...,0>|D>
        for i_ancilla in range(0, self.k):
            logical_x_ith = logical_x[i_ancilla]

            with Control(eng, register_ancilla[i_ancilla]):
                pauli_str = StabilizerCode.binary_rep_to_pauli_str(
                    logical_x_ith)
                for j_qubit, pauli_op in enumerate(pauli_str):
                    if pauli_op == "X":
                        XGate() | register[j_qubit]
                    elif pauli_op == "Y":
                        QubitOperator('Y' + str(j_qubit), -1.j) | register
                    elif pauli_op == "Z":
                        ZGate() | register[j_qubit]

        eng.flush()
        if deallocate_nqubits:
            if add_ancilla_bits:
                All(Measure) | register
                del register
            else:
                All(Measure) | register[:self.n]
                register_ancilla = register[self.n:]
                del register[:self.n]
            return register_ancilla
        return register + register_ancilla
示例#5
0
    def encoding_circuit(self, eng, register, state):
        r"""
        Apply the encoding circuit to map the k-qubit "state" to its n-qubit state.

        Parameters
        ----------
        state : list
            list of k-items, where each item is either 0 to 1 corresponding to the quantum state
            |x_1, ... , x_k>, where x_i is either zero or one.

        Notes
        -----
        - To construct the most optimal encoding circuit. The standard form for the stabilizer
                code needs to be constructed alongside the logical X operators.

        References
        ----------
        - See Gaitan book "Quantum Error-Correction and Fault Tolerant Quantum Computing."

        """
        assert len(
            state
        ) == self.k, "State should be the number of unencoded qubits k."
        assert len(
            register
        ) == self.n, "Number of qubits should be number of encoded qubits n."

        logical_x = self.logical_x
        # Construct The last k qubits to become the specified attribute 'state'.
        for i, binary in enumerate(state):
            assert binary in [0, 1], "state should be all binary elements."
            if binary == 1:
                XGate() | register[self.n - self.k + i]
        eng.flush()

        # Construct Controlled Unitary operators To Model Logical X Operators, this is only needed
        # when the rank is less than n- k.
        if self.rank < self.numb_stab:
            for i in range(self.k - 1, -1, -1):  # Go Thorough each un-encoded.
                # Get the ith Controlled unitary operator
                controlled_op = logical_x[i, self.rank:self.n - self.k]
                with Control(eng, register[i - self.k]):
                    for j, binary in enumerate(controlled_op):
                        if binary == 1:
                            XGate() | register[self.rank + j]
                eng.flush()

        # Construct The application of stabilizer generators.
        # Go Through the first rank qubits, should be all initialized to zero, or go through
        # the first type 1 stabilizer generators.
        for i in range(0, self.rank):
            # Apply hadamard gate to every encoded qubit.
            HGate() | register[i]
            eng.flush()
            # Get pauli operator of normal stabilizer generator.
            pauli = self.binary_rep_to_pauli_str(self.normal_form[i])

            # Apply controlled operators with the ith-qubit being controlled.
            for j, pauli_op in enumerate(pauli):
                with Control(eng, register[i]):
                    if j != i:  # The ith qubit is controlled.
                        if pauli_op == 'X':
                            XGate() | register[j]
                        elif pauli_op == 'Y':
                            QubitOperator('Y' + str(j), -1.j) | register
                        elif pauli_op == 'Z':
                            #  Z Gate Acts trivially on |0000 \delta>
                            # if j < i:
                            ZGate() | register[j]
                eng.flush()
        eng.flush()
示例#6
0
    def single_syndrome_measurement(self, eng, register, stabilizer):
        r"""
        Get the syndrome measurement of stabilizer element.

        Note that if the length of register is n, then this allocates a new qubit, does the
        circuit, then deletes the allocated qubit. If length of register is n+1, then it uses the
        last qubit in the register as a measurement ancilla.

        Stabilizer element is recommended to be in standard normal form.

        Parameters
        ----------
        eng : ProjectQ Engine
            The quantum circuit engine.
        register : ProjectQ Qureg or list of Qubit
            Either a quantum register or a list of qubits.
        stabilizer : (np.ndarray(2n,) or string)
            Binary representation of the stabilizer element or pauli string.

        Returns
        -------
        int :
            The measurement corresponding to the stabilizer element. Zero means it commutes and
            negative one means it anti-commutes.

        References
        ----------
        - See Quantum Error Correction Book By Daniel Lidar Page 72.

        """
        numb_qubits = len(eng.active_qubits)

        # The additional qubit is for measurement purposes.
        if numb_qubits != self.n and numb_qubits != self.n + 1:
            raise TypeError(
                "Number of qubits allocated should match the number of encoded qubits n"
                " from (n,k) code or match n + 1, where last qubit is used as an "
                "ancilla.")

        # Allocate a new qubit for measurement, if it doesn't have it already.
        if numb_qubits == self.n:
            measure_qubit = eng.allocate_qubit()
        else:
            measure_qubit = register[-1]

        # Convert stabilizer element to pauli matrix and construct the circuit and measure it.
        pauli_str = stabilizer
        if isinstance(stabilizer, np.ndarray):
            pauli_str = self.binary_rep_to_pauli_str(np.array(stabilizer))
        print(pauli_str)
        H | measure_qubit
        eng.flush()
        with Control(eng, measure_qubit):
            for i, pauli_element in enumerate(pauli_str):
                if pauli_element == 'X':
                    XGate() | register[i]
                elif pauli_element == 'Y':
                    # ZGate() | register[i]
                    # XGate() | register[i]
                    QubitOperator('Y' + str(i), -1.j) | register
                elif pauli_element == 'Z':
                    ZGate() | register[i]
                elif pauli_element == "I":
                    pass
                else:
                    raise RuntimeError(
                        "Pauli strings contained an unknown character.")
            eng.flush()
        H | measure_qubit
        eng.flush()
        Measure | measure_qubit
        eng.flush()
        result = int(measure_qubit)
        if numb_qubits == self.n:
            del measure_qubit
        return result
示例#7
0
 def bit_flip(engine, register):
     rando = np.random.random()  # Get uniform random number from zero to one..
     if rando < prob_error:  # If it is less than probability of error.
         XGate() | register
     engine.flush()