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)
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
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
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
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)