Esempio n. 1
0
    def expval(self, observable, shot_range=None, bin_size=None):
        """Returns the expectation value of a Hamiltonian observable. When the observable is a
         ``SparseHamiltonian`` object, the expectation value is computed directly for the full
         Hamiltonian, which leads to faster execution.

        Args:
            observable (~.Observable): a PennyLane observable
            shot_range (tuple[int]): 2-tuple of integers specifying the range of samples
                to use. If not specified, all samples are used.
            bin_size (int): Divides the shot range into bins of size ``bin_size``, and
                returns the measurement statistic separately over each bin. If not
                provided, the entire shot range is treated as a single bin.

        Returns:
            float: returns the expectation value of the observable
        """
        if observable.name == "SparseHamiltonian":
            if self.shots is not None:
                raise DeviceError(
                    "SparseHamiltonian must be used with shots=None")

        if observable.name == "SparseHamiltonian" and self.shots is None:

            ev = coo_matrix.dot(
                coo_matrix(self._conj(self.state)),
                coo_matrix.dot(
                    observable.matrix,
                    coo_matrix(self.state.reshape(len(self.state), 1))),
            )

            return np.real(ev.toarray()[0])

        return super().expval(observable,
                              shot_range=shot_range,
                              bin_size=bin_size)
Esempio n. 2
0
def moments_cheb(A, N=10, num_samples=100, kind=1):
    m = A.shape[0]

    Z = np.random.randn(m, num_samples)
    c = np.zeros((N, 1))

    c[0] = m
    c[1] = sum(A.diagonal())
    P0 = Z
    P1 = coo_matrix.dot(A, Z) * kind

    for n in range(2, N):
        Pn = 2 * coo_matrix.dot(A, P1) - P0
        for j in range(1, num_samples):
            c[n] = c[n] + np.dot(Z[:, j], Pn[:, j])
        c[n] = c[n] / num_samples
        P0 = P1
        P1 = Pn
    return c
Esempio n. 3
0
def moments_cheb(A,N=10,num_samples=100,kind=1):
    m = A.shape[0]

    Z = np.random.randn(m,num_samples)
    c = np.zeros((N,1))

    c[0] = m
    c[1] = sum(A.diagonal())
    P0 = Z
    P1 = coo_matrix.dot(A,Z) * kind

    for n in range(2,N):
        Pn = 2 * coo_matrix.dot(A,P1) - P0
        for j in range(1,num_samples):
            c[n] = c[n] + np.dot(Z[:,j] , Pn[:,j])
        c[n] = c[n] / num_samples
        P0 = P1
        P1 = Pn
    return c
Esempio n. 4
0
def filter_laplacian(mesh, lamb=0.5, iterations=10, laplacian_operator=None):
    """

    Smooth a mesh in-place using laplacian smoothing.

    Articles
    "Improved Laplacian Smoothing of Noisy Surface Meshes"
    J. Vollmer, R. Mencl, and H. Muller

    Parameters
    ------------
    mesh : trimesh.Trimesh
      Mesh to be smoothed in place
    lamb : float
      Diffusion speed constant
      If 0.0, no diffusion
      If 1.0, full diffusion
    iterations : int
      Number of passes to run filter
    laplacian_operator : None or scipy.sparse.coo.coo_matrix
      Sparse matrix laplacian operator
      Will be autogenerated if None
    """
    # if the laplacian operator was not passed create it here
    if laplacian_operator is None:
        laplacian_operator = laplacian_calculation(mesh)

    # get mesh vertices as vanilla numpy array
    vertices = mesh.vertices.copy().view(np.ndarray)

    # Number of passes
    for _index in range(iterations):
        dot = coo_matrix.dot(laplacian_operator, vertices) - vertices
        vertices += lamb * dot

    # assign modified vertices back to mesh
    mesh.vertices = vertices
    return mesh
Esempio n. 5
0
    def expval(self, observable, shot_range=None, bin_size=None):
        """Returns the expectation value of a Hamiltonian observable. When the observable is a
         ``SparseHamiltonian`` object, the expectation value is computed directly for the full
         Hamiltonian, which leads to faster execution.

        Args:
            observable (~.Observable): a PennyLane observable
            shot_range (tuple[int]): 2-tuple of integers specifying the range of samples
                to use. If not specified, all samples are used.
            bin_size (int): Divides the shot range into bins of size ``bin_size``, and
                returns the measurement statistic separately over each bin. If not
                provided, the entire shot range is treated as a single bin.

        Returns:
            float: returns the expectation value of the observable
        """
        # intercept other Hamiltonians
        # TODO: Ideally, this logic should not live in the Device, but be moved
        # to a component that can be re-used by devices as needed.
        if observable.name in ("Hamiltonian", "SparseHamiltonian"):
            assert self.shots is None, f"{observable.name} must be used with shots=None"

            backprop_mode = (not isinstance(self.state, np.ndarray) or any(
                not isinstance(d, (float, np.ndarray))
                for d in observable.data)) and observable.name == "Hamiltonian"

            if backprop_mode:
                # We must compute the expectation value assuming that the Hamiltonian
                # coefficients *and* the quantum states are tensor objects.

                # Compute  <psi| H |psi> via sum_i coeff_i * <psi| PauliWord |psi> using a sparse
                # representation of the Pauliword
                res = qml.math.cast(qml.math.convert_like(
                    0.0, observable.data),
                                    dtype=complex)
                interface = qml.math.get_interface(self.state)

                # Note: it is important that we use the Hamiltonian's data and not the coeffs attribute.
                # This is because the .data attribute may be 'unwrapped' as required by the interfaces,
                # whereas the .coeff attribute will always be the same input dtype that the user provided.
                for op, coeff in zip(observable.ops, observable.data):

                    # extract a scipy.sparse.coo_matrix representation of this Pauli word
                    coo = qml.operation.Tensor(op).sparse_matrix(
                        wires=self.wires)
                    Hmat = qml.math.cast(
                        qml.math.convert_like(coo.data, self.state),
                        self.C_DTYPE)

                    product = (
                        qml.math.gather(qml.math.conj(self.state), coo.row) *
                        Hmat * qml.math.gather(self.state, coo.col))
                    c = qml.math.convert_like(coeff, product)

                    if interface == "tensorflow":
                        c = qml.math.cast(c, "complex128")

                    res = qml.math.convert_like(res, product) + qml.math.sum(
                        c * product)

            else:
                # Coefficients and the state are not trainable, we can be more
                # efficient in how we compute the Hamiltonian sparse matrix.

                if observable.name == "Hamiltonian":
                    Hmat = qml.utils.sparse_hamiltonian(observable,
                                                        wires=self.wires)
                elif observable.name == "SparseHamiltonian":
                    Hmat = observable.matrix

                state = qml.math.toarray(self.state)
                res = coo_matrix.dot(
                    coo_matrix(qml.math.conj(state)),
                    coo_matrix.dot(
                        Hmat, coo_matrix(state.reshape(len(self.state), 1))),
                ).toarray()[0]

            if observable.name == "Hamiltonian":
                res = qml.math.squeeze(res)

            return qml.math.real(res)

        return super().expval(observable,
                              shot_range=shot_range,
                              bin_size=bin_size)