Ejemplo n.º 1
0
    def sample_bitstrings(self,
                          n_samples: int,
                          tol_factor: float = 1e8) -> np.ndarray:
        """
        Sample bitstrings from the distribution defined by the wavefunction.

        Qubit 0 is at ``out[:, 0]``.

        :param n_samples: The number of bitstrings to sample
        :param tol_factor: Tolerance to set imaginary probabilities to zero, relative to
            machine epsilon.
        :return: An array of shape (n_samples, n_qubits)
        """
        if self.rs is None:
            raise ValueError(
                "You have tried to perform a stochastic operation without setting the "
                "random state of the simulator. Might I suggest using a PyQVM object?"
            )

        # for np.real_if_close the actual tolerance is (machine_eps * tol_factor),
        # where `machine_epsilon = np.finfo(float).eps`. If we use tol_factor = 1e8, then the
        # overall tolerance is \approx 2.2e-8.
        probabilities = np.real_if_close(np.diagonal(self.density),
                                         tol=tol_factor)  # type: ignore
        # Next set negative probabilities to zero
        probabilities = np.array([0 if p < 0.0 else p for p in probabilities])
        # Ensure they sum to one
        probabilities = probabilities / np.sum(probabilities)
        possible_bitstrings = all_bitstrings(self.n_qubits)
        inds = self.rs.choice(2**self.n_qubits, n_samples, p=probabilities)
        bitstrings = possible_bitstrings[inds, :]
        bitstrings = np.flip(bitstrings,
                             axis=1)  # qubit ordering: 0 on the left.
        return bitstrings  # type: ignore
Ejemplo n.º 2
0
    def sample_bitstrings(self, n_samples: int) -> np.ndarray:
        """
        Sample bitstrings from the distribution defined by the wavefunction.

        Qubit 0 is at ``out[:, 0]``.

        :param n_samples: The number of bitstrings to sample
        :return: An array of shape (n_samples, n_qubits)
        """
        if self.rs is None:
            raise ValueError(
                "You have tried to perform a stochastic operation without setting the "
                "random state of the simulator. Might I suggest using a PyQVM object?"
            )
        probabilities = np.abs(self.wf)**2
        possible_bitstrings = all_bitstrings(self.n_qubits)
        inds = self.rs.choice(2**self.n_qubits, n_samples, p=probabilities)
        bitstrings = possible_bitstrings[inds, :]
        bitstrings = np.flip(bitstrings,
                             axis=1)  # qubit ordering: 0 on the left.
        return bitstrings  # type: ignore
Ejemplo n.º 3
0
    def sample_bitstrings(self, n_samples: int) -> np.ndarray:
        """
        Sample bitstrings from the distribution defined by the wavefunction.

        Qubit 0 is at ``out[:, 0]``.

        :param n_samples: The number of bitstrings to sample
        :return: An array of shape (n_samples, n_qubits)
        """
        if self.rs is None:
            raise ValueError(
                "You have tried to perform a stochastic operation without setting the "
                "random state of the simulator. Might I suggest using a PyQVM object?"
            )

        # note on reshape: it puts bitstrings in lexicographical order.
        # would you look at that .. _all_bitstrings returns things in lexicographical order!
        # reminder: qubit 0 is on the left in einsum simulator.
        probabilities = np.abs(self.wf.reshape(-1))**2
        possible_bitstrings = all_bitstrings(self.n_qubits)
        inds = self.rs.choice(2**self.n_qubits, n_samples, p=probabilities)
        return possible_bitstrings[inds, :]