def _collapse_ancillas_Z(self, rho, ancillas_pos, projections):
        # Measure the ancillas in the X basis in parallel in each node.
        # NOTE: All ancillas are collapsed in parallel, Hadamard operations
        # are used to measure on X basis
        self.check["measurement"] += 1

        time = self.time_lookup["measurement"]
        self.check["time"] += time
        self.check["time1"] += time
        # Apply environmental error
        rho = errs.env_error_all(rho, 0, self.a1, time)

        N_ancillas = len(ancillas_pos)
        if N_ancillas == 1:
            N = len(rho.dims[0])
            p_success = ops.p_measurement_single_Zbasis(
                rho, projections[0], N, ancillas_pos[0])
        else:
            p_success = 1

        # Collapse the qubits in parrallel
        # Sort list to be able to reduce dimension and keep track of positions
        ancillas_pos = sorted(ancillas_pos)
        for i in range(N_ancillas):
            pos = ancillas_pos[i] - i
            rho = self._collapse_single(rho, pos, projections[i], "Z")
        return p_success, rho
    def _collapse_ancillas_X(self, rho, ancillas_pos, projections):
        # Measure the ancillas in the X basis in parallel in each node.
        # NOTE: All ancillas are collapsed in parallel, Hadamard operations
        # are used to measure on X basis
        self.check["measurement"] += 1

        time = self.time_lookup["measurement"]
        self.check["time"] += time
        self.check["time1"] += time
        # Apply environmental error
        rho = errs.env_error_all(rho, 0, self.a1, time)

        N_ancillas = len(ancillas_pos)
        N = len(rho.dims[0])

        # Apply error due to the needed rotation, use I instead of real H gate
        identity = qt.qeye([2] * N)
        rho = self._apply_single_qubit_gates(rho, [identity, identity],
                                             ancillas_pos)

        # Collapse the qubits in parrallel
        # Sort list to be able to reduce dimension and keep track of positions
        ancillas_pos = sorted(ancillas_pos)
        for i in range(N_ancillas):
            pos = ancillas_pos[i] - i
            rho = self._collapse_single(rho, pos, projections[i], "X")

        return 1, rho
    def _collapse_ancillas_EPL(self, rho, ancillas_pos):
        # For the special EPL case
        # Measure the ancillas in the Z basis in parallel in each node.
        # NOTE: All ancillas are collapsed in parallel, Hadamard operations
        # are used to measure on X basis
        self.check["measurement"] += 1

        time = self.time_lookup["measurement"]
        self.check["time"] += time
        self.check["time1"] += time
        # Apply environmental error
        rho = errs.env_error_all(rho, 0, self.a1, time)

        N_ancillas = len(ancillas_pos)
        if N_ancillas != 2:
            raise ValueError("EPL ancillas collapse: Bad number of ancillas")
        p_success = ps.epl(rho, N=4, ancillas_pos=ancillas_pos)
        projections = [1, 1]

        # Collapse the qubits in parrallel
        # Sort list to be able to reduce dimension and keep track of positions
        ancillas_pos = sorted(ancillas_pos)
        for i in range(N_ancillas):
            pos = ancillas_pos[i] - i
            rho = self._collapse_single(rho, pos, projections[i], "Z")
        return p_success, rho
    def _append_noisy_plus(self, rho):
        # Append noisy |+> state to the total state rho
        # Generate noisy plus
        time, plus = self.generate_noisy_plus()

        # Apply environmental error
        rho = errs.env_error_all(rho, 0, self.a1, time)
        # Noisy plus tate is attached at the end of the complete state
        rho = qt.tensor(rho, plus)
        return rho
Exemple #5
0
    def append_circuit(self, rho=None):
        """
        Appended circuit, and depolarize accordingly.
        Must be self contained event

        Parameters
        -----------
        rho : (densmat) density matrix involved in the circuit, can be None depending
              on the circuit block
        """
        check, rho_app = self._run()
        time0 = check["time0"]
        rho = errs.env_error_all(rho, self.a0,
                                 self.a1, time0)
        time1 = check["time1"]
        rho = errs.env_error_all(rho, 0,
                                 self.a1, time1)

        rho = qt.tensor(rho, rho_app)
        return 1, check, rho
 def _swap_pair(self, rho, pair):
     # Apply the noise due to SWAP on two states
     # NOTE: use only two CNOTs to perform a SWAP
     self.check["two_qubit_gate"] += 3
     time = self.time_lookup["two_qubit_gate"] * 3
     self.check["time"] += time
     self.check["time1"] += time
     rho = self._swap_noise(rho, pair[0])
     rho = self._swap_noise(rho, pair[1])
     rho = errs.env_error_all(rho, 0, self.a1, time)
     return rho
    def _append_bell_pair(self, rho):
        # Append single click Bell pair state to the total state rho
        # Generate raw Bell pair to the state.
        time, bell = self._generate_bell_single_click()
        self.check["time"] += time
        self.check["time0"] += time
        # Apply environmental error
        rho = errs.env_error_all(rho, self.a0, self.a1, time)

        # Bell state is attached at the end of the complete state
        rho = qt.tensor(rho, bell)
        return rho
    def add_bell_pair(self, rho):
        """Append a single click Bell pair to the state.

        Parameters
        ----------
        rho : (densmat) density matrix in which the bell pair appends.
        """
        self._reset_check()
        time, bell = self._generate_bell_single_click()
        # Apply environmental error
        rho = errs.env_error_all(rho, self.a0, self.a1, time)
        self.check["time"] += time
        self.check["time1"] += time
        # Bell state is attached at the end of the complete state
        rho = qt.tensor(rho, bell)
        return 1, self.check, rho
    def _apply_single_qubit_gates(self, rho, gates, operation_qubits):
        # Apply single qubit gates on the entire state rho
        N = len(rho.dims[0])
        # NOTE: Number of gates is 1 because gates are applied in parallel
        # in the nodes
        self.check["single_qubit_gate"] += 1
        time = self.time_lookup["single_qubit_gate"]
        self.check["time"] += time
        self.check["time1"] += time
        # Apply environmental error
        rho = errs.env_error_all(rho, 0, self.a1, time)

        for i in range(len(gates)):
            rho = errs.single_qubit_gate(rho, gates[i], self.ps, N,
                                         operation_qubits[i])
        return rho
    def _apply_two_qubit_gates(self, rho, controls, targets, sigma):
        # Apply one local two qubit Control type of gates in parallel
        # on each node.
        N = len(rho.dims[0])
        # NOTE: Number of gates is 1 because gates are applied in parallel
        self.check["two_qubit_gate"] += 1
        time = self.time_lookup["two_qubit_gate"]
        self.check["time"] += time
        self.check["time1"] += time
        # Apply environmental error
        rho = errs.env_error_all(rho, 0, self.a1, time)

        gates = self._get_two_qubit_gates(N, controls, targets, sigma)
        for i in range(len(gates)):
            rho = errs.two_qubit_gate(rho, gates[i], self.pg, N, controls[i],
                                      targets[i])
        return rho
    def _measure_random_ancillas_Z(self, rho, ancillas_pos):
        # NOTE: All ancillas are collapsed in parallel
        self.check["measurement"] += 1

        time = self.time_lookup["measurement"]
        self.check["time"] += time
        self.check["time1"] += time
        # Apply environmental error
        rho = errs.env_error_all(rho, 0, self.a1, time)

        # Collapse the qubits in parrallel
        # Sort list to be able to reduce dimension and keep track of positions
        ancillas_pos = sorted(ancillas_pos)
        measurements = []
        for i in range(len(ancillas_pos)):
            pos = ancillas_pos[i] - i
            m, rho = self._measure_random_single(rho, pos, "Z")
            measurements += [m]
        return measurements, rho
    def _append_epl(self, rho):
        # Append a Bell pair generated using the EPL protocol to the
        # total state rho
        # Copy a backup of the check dictS
        check_backup = self.check.copy()
        # Get EPl and number of attempts
        p_success, _, rho_epl = self.start_epl()
        attempts = self._success_number_of_attempts(p_success) + 1

        # Multiply check elements
        for k in self.check:
            self.check[k] *= (attempts)
        time = self.check["time0"]
        self.check += check_backup

        # Dephase the rest of the state and join them
        rho = errs.env_error_all(rho, self.a0, self.a1, time)
        rho = qt.tensor(rho, rho_epl)
        return rho
Exemple #13
0
    def run_parallel(self, rho=None, parallel=2):
        """
        Run circuit three times in parallel, tensoring the resulting states,
        and dephasing the one that was generated first accordingly.
        Cicuits must be self contained events to be able to run in parallel.

        Parameters
        -----------
        rho : (densmat) density matrix involved in the circuit, can be None depending
              on the circuit block
        parallel : (int) number of executions in parallel of the circuit
        """
        # Get all the states, operations
        checks = []
        rhos = []
        times = []
        for i in range(parallel):
            c, r = self._run()
            checks += [c]
            rhos += [r]
            times += [c["time"]]

        # Get max time and find its index
        time_max = max(times)
        max_index = np.where(times == time_max)[0][0]

        # Get state and check of max
        rho = rhos[max_index]
        check = checks[max_index]

        # Remove the max from the lists
        del times[max_index]
        del check[max_index]
        del rhos[max_index]

        for i in range(parallel-1):
            rho_app = errs.env_error_all(rhos[i], 0, self.a1,
                                         np.abs(times[i] - time_max))
            rho = qt.tensor(rho, rho_app)

        return 1, check, rho
    def start_epl(self, rho=None):
        """
        Circuit that generates a Bell pair using the EPL protocol.

        NOTE: rho is not taken from arguments, only exists due to
        how 'circuit.py' is constructed.
        """
        self._reset_check()
        # Generate Bell pairs
        # First pair with swap
        time1, bell1 = self._generate_bell_single_click()
        bell1 = self._swap_pair(bell1, [0, 1])
        # Second pair
        time2, bell2 = self._generate_bell_single_click()
        self.check["time"] += time1 + time2
        self.check["time0"] += time1 + time2
        # Apply cutoff here

        # Dephase pair 1
        rho = errs.env_error_all(bell1, self.a0, self.a1, time2)

        # Join state
        rho = qt.tensor(rho, bell2)

        # NOTE: Decide which state collapses.
        # Apply two qubit gates
        controls = [0, 1]
        targets = [2, 3]
        rho = self._apply_two_qubit_gates(rho, controls, targets, "X")

        # Measure ancillas in Z basis
        projections = [1] * 2
        p_success, rho = self._collapse_ancillas_EPL(rho, targets)

        # Apply X to rotate state
        rho = self._apply_single_qubit_gates(rho, [qt.rx(np.pi, 2, 0)], [0])

        return p_success, self.check, rho
    def _swap_noise(self, rho, pos):
        # Apply the noise induced by the one way SWAP gate
        # NOTE: use only two CNOTs to perform a SWAP
        # Swap noise is only single qubit gate because one of the states
        # because a one way Swap gate is used
        ancilla = qt.basis(2, 0) * qt.basis(2, 0).dag()
        ancilla = errs.env_error_all(ancilla, self.a0, self.a1,
                                     self.check["time0"])
        rho = qt.tensor(rho, ancilla)
        N = len(rho.dims[0])

        # Define ideal gates
        CNOT1 = qt.cnot(N, N - 1, pos)
        CNOT2 = qt.cnot(N, pos, N - 1)

        # Apply 3 CNOTS to get a swap
        rho = errs.two_qubit_gate(rho, CNOT1, self.pg, N, pos, N - 1)
        rho = errs.two_qubit_gate(rho, CNOT2, self.pg, N, pos, N - 1)
        rho = errs.two_qubit_gate(rho, CNOT1, self.pg, N, pos, N - 1)

        # Measure the ancilla to reduce the dimension
        rho = errs.measure_single_Zbasis_forced(rho, self.pm, 0, N, pos)
        return rho