def teleportation(psi):
    qr = QuantumRegister(3)
    crz = ClassicalRegister(1)
    crx = ClassicalRegister(1)
    qc = QuantumCircuit(qr, crz, crx)
    init_gate = Initialize(psi)
    qc.append(init_gate, [alice])
    qc.barrier()

    create_bell_pair(qc, common, bob)
    qc.barrier()
    create_alice(qc, alice, common)
    qc.barrier()
    measure_and_send(qc, alice, common)
    qc.barrier()
    create_bob(qc, bob, crz, crx)
    print(qc.draw())

    result = execute(qc, Aer.get_backend('statevector_simulator')).result()
    print(result.get_statevector())

    reverse_init_gate = init_gate.gates_to_uncompute()
    qc.append(reverse_init_gate, [bob])
    print(qc.draw())

    cr_result = ClassicalRegister(1)
    qc.add_register(cr_result)
    qc.measure(bob, 2)
    print(qc.draw())

    result = execute(qc, Aer.get_backend('qasm_simulator')).result()
    print(result.get_counts())
Ejemplo n.º 2
0
    def __init__(
        self,
        num_qubits: Union[int, List[int]],
        mu: Optional[Union[float, List[float]]] = None,
        sigma: Optional[Union[float, List[float]]] = None,
        bounds: Optional[Union[Tuple[float, float],
                               List[Tuple[float, float]]]] = None,
        upto_diag: bool = False,
        name: str = "P(X)",
    ) -> None:
        r"""
        Args:
            num_qubits: The number of qubits used to discretize the random variable. For a 1d
                random variable, ``num_qubits`` is an integer, for multiple dimensions a list
                of integers indicating the number of qubits to use in each dimension.
            mu: The parameter :math:`\mu`, which is the expected value of the distribution.
                Can be either a float for a 1d random variable or a list of floats for a higher
                dimensional random variable. Defaults to 0.
            sigma: The parameter :math:`\sigma^2` or :math:`\Sigma`, which is the variance or
                covariance matrix. Default to the identity matrix of appropriate size.
            bounds: The truncation bounds of the distribution as tuples. For multiple dimensions,
                ``bounds`` is a list of tuples ``[(low0, high0), (low1, high1), ...]``.
                If ``None``, the bounds are set to ``(-1, 1)`` for each dimension.
            upto_diag: If True, load the square root of the probabilities up to multiplication
                with a diagonal for a more efficient circuit.
            name: The name of the circuit.
        """
        _check_dimensions_match(num_qubits, mu, sigma, bounds)
        _check_bounds_valid(bounds)

        # set default arguments
        dim = 1 if isinstance(num_qubits, int) else len(num_qubits)
        if mu is None:
            mu = 0 if dim == 1 else [0] * dim

        if sigma is None:
            sigma = 1 if dim == 1 else np.eye(dim)

        if bounds is None:
            bounds = (-1, 1) if dim == 1 else [(-1, 1)] * dim

        if isinstance(num_qubits, int):  # univariate case
            super().__init__(num_qubits, name=name)

            x = np.linspace(bounds[0], bounds[1],
                            num=2**num_qubits)  # type: Any
        else:  # multivariate case
            super().__init__(sum(num_qubits), name=name)

            # compute the evaluation points using numpy.meshgrid
            # indexing 'ij' yields the "column-based" indexing
            meshgrid = np.meshgrid(
                *[
                    np.linspace(bound[0], bound[1],
                                num=2**num_qubits[i])  # type: ignore
                    for i, bound in enumerate(bounds)
                ],
                indexing="ij",
            )
            # flatten into a list of points
            x = list(zip(*[grid.flatten() for grid in meshgrid]))

        from scipy.stats import multivariate_normal

        # compute the normalized, truncated probabilities
        probabilities = multivariate_normal.pdf(x, mu, sigma)
        normalized_probabilities = probabilities / np.sum(probabilities)

        # store the values, probabilities and bounds to make them user accessible
        self._values = x
        self._probabilities = normalized_probabilities
        self._bounds = bounds

        # use default the isometry (or initialize w/o resets) algorithm to construct the circuit
        # pylint: disable=no-member
        if upto_diag:
            self.isometry(np.sqrt(normalized_probabilities), self.qubits, None)
        else:
            from qiskit.extensions import Initialize  # pylint: disable=cyclic-import

            initialize = Initialize(np.sqrt(normalized_probabilities))
            circuit = initialize.gates_to_uncompute().inverse()
            self.compose(circuit, inplace=True)
teleportation_circuit.draw(output='mpl')

# In[22]:

teleportation_circuit.draw()

# In[23]:

#STEP 5
#GOBACK TO BEFORE STEP 1

# In[24]:

#Step 6 How do we check?

inverse_init_gate = init_gate.gates_to_uncompute()

teleportation_circuit.append(inverse_init_gate, [2])

cresult = ClassicalRegister(1)

teleportation_circuit.add_register(cresult)

teleportation_circuit.measure(2, 2)

teleportation_circuit.draw()

# In[25]:

teleportation_circuit.draw(output='mpl')
Ejemplo n.º 4
0
    def __init__(self,
                 num_qubits: Union[int, List[int]],
                 mu: Optional[Union[float, List[float]]] = None,
                 sigma: Optional[Union[float, List[float]]] = None,
                 bounds: Optional[Union[Tuple[float, float],
                                        List[Tuple[float, float]]]] = None,
                 upto_diag: bool = False,
                 name: str = 'P(X)') -> None:
        r"""
        Args:
            num_qubits: The number of qubits used to discretize the random variable. For a 1d
                random variable, ``num_qubits`` is an integer, for multiple dimensions a list
                of integers indicating the number of qubits to use in each dimension.
            mu: The parameter :math:`\mu` of the distribution.
                Can be either a float for a 1d random variable or a list of floats for a higher
                dimensional random variable.
            sigma: The parameter :math:`\sigma^2` or :math:`\Sigma`, which is the variance or
                covariance matrix.
            bounds: The truncation bounds of the distribution as tuples. For multiple dimensions,
                ``bounds`` is a list of tuples ``[(low0, high0), (low1, high1), ...]``.
                If ``None``, the bounds are set to ``(0, 1)`` for each dimension.
            upto_diag: If True, load the square root of the probabilities up to multiplication
                with a diagonal for a more efficient circuit.
            name: The name of the circuit.
        """
        _check_dimensions_match(num_qubits, mu, sigma, bounds)
        _check_bounds_valid(bounds)

        # set default arguments
        dim = 1 if isinstance(num_qubits, int) else len(num_qubits)
        if mu is None:
            mu = 0 if dim == 1 else [0] * dim

        if sigma is None:
            sigma = 1 if dim == 1 else np.eye(dim)

        if bounds is None:
            bounds = (0, 1) if dim == 1 else [(0, 1)] * dim

        if not isinstance(num_qubits, list):  # univariate case
            super().__init__(num_qubits, name=name)

            x = np.linspace(bounds[0], bounds[1],
                            num=2**num_qubits)  # evaluation points
        else:  # multivariate case
            super().__init__(sum(num_qubits), name=name)

            # compute the evaluation points using numpy's meshgrid
            # indexing 'ij' yields the "column-based" indexing
            meshgrid = np.meshgrid(*[
                np.linspace(bound[0], bound[1], num=2**num_qubits[i])
                for i, bound in enumerate(bounds)
            ],
                                   indexing='ij')
            # flatten into a list of points
            x = list(zip(*[grid.flatten() for grid in meshgrid]))

        # compute the normalized, truncated probabilities
        probabilities = []
        from scipy.stats import multivariate_normal

        for x_i in x:
            # pylint: disable=line-too-long
            # map probabilities from normal to log-normal reference:
            # https://stats.stackexchange.com/questions/214997/multivariate-log-normal-probabiltiy-density-function-pdf
            if np.min(x_i) > 0:
                det = 1 / np.prod(x_i)
                probability = multivariate_normal.pdf(np.log(x_i), mu,
                                                      sigma) * det
            else:
                probability = 0
            probabilities += [probability]
        normalized_probabilities = probabilities / np.sum(probabilities)

        # store as properties
        self._values = x
        self._probabilities = normalized_probabilities
        self._bounds = bounds

        # use default the isometry (or initialize w/o resets) algorithm to construct the circuit
        # pylint: disable=no-member
        if upto_diag:
            self.isometry(np.sqrt(normalized_probabilities), self.qubits, None)
        else:
            from qiskit.extensions import Initialize  # pylint: disable=cyclic-import
            initialize = Initialize(np.sqrt(normalized_probabilities))
            circuit = initialize.gates_to_uncompute().inverse()
            self.compose(circuit, inplace=True)
state.probabilities()
init_gate = Initialize(state.data)
qc.append(init_gate, [0])

create_ent_channel(qc, 1, 2)
bell_measurement(qc, 0, 1)
bob_transformation(qc, 2)
#qc.draw('mpl')

#thus the bob qubit will be transformed to state which alice want to sent.
#state of the alice's qubit get collapsed during the process
'''#checking the bobs state
backend=BasicAer.get_backend('statevector_simulator')
in_state=state
plot_bloch_multivector(in_state)'''

disentangler = init_gate.gates_to_uncompute()  #re
qc.append(disentangler, [2])
'''out_state=execute(qc,backend).result().get_statevector()
plot_bloch_multivector(out_state)'''

#to check bob received corect state
qc.measure(qr[2], crx)
#qc.draw('mpl')

backend = BasicAer.get_backend('qasm_simulator')
counts = execute(qc, backend, shots=1024).result().get_counts()
plot_histogram(counts)

qc.draw('mpl')
Ejemplo n.º 6
0
    def __init__(self,
                 num_qubits: Union[int, List[int]],
                 cdfs: Union[Callable[[float], float], List[Callable[[float],
                                                                     float]]],
                 sigma: Optional[Union[float, List[float]]] = None,
                 bounds: Optional[Union[Tuple[float, float],
                                        List[Tuple[float, float]]]] = None,
                 pdfs: Optional[Union[Callable[[float], float],
                                      List[Callable[[float], float]]]] = None,
                 dx: Optional[float] = 1e-6,
                 upto_diag: bool = False,
                 name: str = 'P(X)') -> None:
        r"""
        Args:
            num_qubits: The number of qubits used to discretize the random variable. For a 1d
                random variable, ``num_qubits`` is an integer, for multiple dimensions a list
                of integers indicating the number of qubits to use in each dimension.
            cdfs: The cumulative marginal probability density functions for each dimension.
            sigma: The parameter :math:`\sigma^2` or :math:`\Sigma`, which is the correlation matrix. 
                Defaults to the identity matrix of appropriate size.
            bounds: The truncation bounds of the distribution as tuples. For multiple dimensions,
                ``bounds`` is a list of tuples ``[(low0, high0), (low1, high1), ...]``.
                If ``None``, the bounds are set to ``(-1, 1)`` for each dimension.
            pdfs: The marginal probability density functions for each dimension. 
                If ''None'', marginal pdf is calculated from the pdf by finite differences, but
                consider using automatic differentiation of cdf. 
            dx: The spacing, if finite differences is used to calculate the pdf.
            upto_diag: If True, load the square root of the probabilities up to multiplication
                with a diagonal for a more efficient circuit.
            name: The name of the circuit.
        """
        _check_dimensions_match(num_qubits, cdfs, pdfs, sigma, bounds)
        _check_bounds_valid(bounds)

        # set default arguments
        dim = 1 if isinstance(num_qubits, int) else len(num_qubits)

        mu = 0 if dim == 1 else [0] * dim

        if sigma is None:
            sigma = 1 if dim == 1 else np.eye(dim)

        if bounds is None:
            bounds = (-1, 1) if dim == 1 else [(-1, 1)] * dim

        if not isinstance(cdfs, list):
            cdfs = [cdfs]

        if pdfs is None:
            pdfs = [lambda x: derivative(cdf, x, dx=dx) for cdf in cdfs]

        if not isinstance(num_qubits, list):  # univariate case
            super().__init__(num_qubits, name=name)

            x = np.linspace(bounds[0], bounds[1], num=2**num_qubits)
        else:  # multivariate case
            super().__init__(sum(num_qubits), name=name)

            # compute the evaluation points using numpy's meshgrid
            # indexing 'ij' yields the "column-based" indexing
            meshgrid = np.meshgrid(*[
                np.linspace(bound[0], bound[1], num=2**num_qubits[i])
                for i, bound in enumerate(bounds)
            ],
                                   indexing='ij')
            # flatten into a list of points
            x = list(zip(*[grid.flatten() for grid in meshgrid]))

        from scipy.stats import multivariate_normal

        # compute the normalized, truncated probabilities
        probabilities = multivariate_normal.pdf(x, mu, sigma)

        xa = np.asarray(x, dtype=float)
        zeta = np.concatenate([
            norm.ppf(cdfs[i](xa[:, i])).reshape(xa.shape[0], 1)
            for i in range(dim)
        ], 1)
        probabilities = multivariate_normal.pdf(zeta, mu, sigma) * np.exp(
            0.5 * np.sum(np.square(zeta), axis=-1)) * np.sqrt((2 * np.pi)**dim)
        for i in range(xa.shape[1]):
            probabilities = probabilities * pdfs[i](xa[:, i])

        normalized_probabilities = probabilities / np.sum(probabilities)

        # store the values, probabilities and bounds to make them user accessible
        self._values = x
        self._probabilities = normalized_probabilities
        self._bounds = bounds

        # use default the isometry (or initialize w/o resets) algorithm to construct the circuit
        # pylint: disable=no-member
        if upto_diag:
            self.isometry(np.sqrt(normalized_probabilities), self.qubits, None)
        else:
            from qiskit.extensions import Initialize  # pylint: disable=cyclic-import
            initialize = Initialize(np.sqrt(normalized_probabilities))
            circuit = initialize.gates_to_uncompute().inverse()
            self.compose(circuit, inplace=True)