def expectation_from_state_vector( self, state_vector: np.ndarray, qubit_map: Mapping[raw_types.Qid, int], *, atol: float = 1e-7, check_preconditions: bool = True, ) -> float: """Evaluate the expectation of this PauliSum given a state vector. See `PauliString.expectation_from_state_vector`. Args: state_vector: An array representing a valid state vector. qubit_map: A map from all qubits used in this PauliSum to the indices of the qubits that `state_vector` is defined over. atol: Absolute numerical tolerance. check_preconditions: Whether to check that `state_vector` represents a valid state vector. Returns: The expectation value of the input state. Raises: NotImplementedError: If any of the coefficients are imaginary, so that this is not Hermitian. TypeError: If the input state is not a complex type. ValueError: If the input vector is not the correct size or shape. """ if any(abs(p.coefficient.imag) > 0.0001 for p in self): raise NotImplementedError( "Cannot compute expectation value of a non-Hermitian " "PauliString <{}>. Coefficient must be real.".format(self)) # TODO: Avoid enforce specific complex type. This is necessary to # prevent an `apply_unitary` bug. # Github issue: https://github.com/quantumlib/Cirq/issues/2041 if state_vector.dtype.kind != 'c': raise TypeError( "Input state dtype must be np.complex64 or np.complex128") size = state_vector.size num_qubits = size.bit_length() - 1 _validate_qubit_mapping(qubit_map, self.qubits, num_qubits) if len(state_vector.shape) != 1 and state_vector.shape != ( 2, ) * num_qubits: raise ValueError("Input array does not represent a state vector " "with shape `(2 ** n,)` or `(2, ..., 2)`.") if check_preconditions: qis.validate_normalized_state_vector( state_vector=state_vector, qid_shape=(2, ) * num_qubits, dtype=state_vector.dtype, atol=atol, ) return sum( p._expectation_from_state_vector_no_validation( state_vector, qubit_map) for p in self)
def expectation_from_density_matrix( self, state: np.ndarray, qubit_map: Mapping[raw_types.Qid, int], *, atol: float = 1e-7, check_preconditions: bool = True, ) -> float: """Evaluate the expectation of this PauliSum given a density matrix. See `PauliString.expectation_from_density_matrix`. Args: state: An array representing a valid density matrix. qubit_map: A map from all qubits used in this PauliSum to the indices of the qubits that `state` is defined over. atol: Absolute numerical tolerance. check_preconditions: Whether to check that `state` represents a valid density matrix. Returns: The expectation value of the input state. Raises: NotImplementedError: If any of the coefficients are imaginary, so that this is not Hermitian. TypeError: If the input state is not a complex type. ValueError: If the input vector is not the correct size or shape. """ if any(abs(p.coefficient.imag) > 0.0001 for p in self): raise NotImplementedError( "Cannot compute expectation value of a non-Hermitian " "PauliString <{}>. Coefficient must be real.".format(self)) # FIXME: Avoid enforce specific complex type. This is necessary to # prevent an `apply_unitary` bug (Issue #2041). if state.dtype.kind != 'c': raise TypeError( "Input state dtype must be np.complex64 or np.complex128") size = state.size num_qubits = int(np.sqrt(size)).bit_length() - 1 _validate_qubit_mapping(qubit_map, self.qubits, num_qubits) dim = int(np.sqrt(size)) if state.shape != (dim, dim) and state.shape != (2, 2) * num_qubits: raise ValueError("Input array does not represent a density matrix " "with shape `(2 ** n, 2 ** n)` or `(2, ..., 2)`.") if check_preconditions: # Do not enforce reshaping if the state all axes are dimension 2. _ = qis.to_valid_density_matrix( density_matrix_rep=state.reshape(dim, dim), num_qubits=num_qubits, dtype=state.dtype, atol=atol, ) return sum( p._expectation_from_density_matrix_no_validation(state, qubit_map) for p in self)
def expectation_from_wavefunction( self, state: np.ndarray, qubit_map: Mapping[raw_types.Qid, int], *, atol: float = 1e-7, check_preconditions: bool = True) -> float: """Evaluate the expectation of this PauliSum given a wavefunction. See `PauliString.expectation_from_wavefunction`. Args: state: An array representing a valid wavefunction. qubit_map: A map from all qubits used in this PauliSum to the indices of the qubits that `state` is defined over. atol: Absolute numerical tolerance. check_preconditions: Whether to check that `state` represents a valid wavefunction. Returns: The expectation value of the input state. """ if any(abs(p.coefficient.imag) > 0.0001 for p in self): raise NotImplementedError( "Cannot compute expectation value of a non-Hermitian " "PauliString <{}>. Coefficient must be real.".format(self)) # FIXME: Avoid enforce specific complex type. This is necessary to # prevent an `apply_unitary` bug (Issue #2041). if state.dtype.kind != 'c': raise TypeError("Input state dtype must be np.complex64 or " "np.complex128") size = state.size num_qubits = size.bit_length() - 1 _validate_qubit_mapping(qubit_map, self.qubits, num_qubits) if len(state.shape) != 1 and state.shape != (2, ) * num_qubits: raise ValueError("Input array does not represent a wavefunction " "with shape `(2 ** n,)` or `(2, ..., 2)`.") if check_preconditions: # HACK: avoid circular import from cirq.sim.wave_function import validate_normalized_state validate_normalized_state(state=state, qid_shape=(2, ) * num_qubits, dtype=state.dtype, atol=atol) return sum( p._expectation_from_wavefunction_no_validation(state, qubit_map) for p in self)
def expectation_from_density_matrix(self, state: np.ndarray, qubit_map: Mapping[raw_types.Qid, int] ) -> float: """Evaluate the expectation of this PauliSum given a density matrix. See `PauliString.expectation_from_density_matrix`. Args: state: An array representing a valid density matrix. qubit_map: A map from all qubits used in this PauliSum to the indices of the qubits that `state` is defined over. Returns: The expectation value of the input state. """ if any(abs(p.coefficient.imag) > 0.0001 for p in self): raise NotImplementedError( "Cannot compute expectation value of a non-Hermitian " "PauliString <{}>. Coefficient must be real.".format(self)) # FIXME: Avoid enforce specific complex type. This is necessary to # prevent an `apply_unitary` bug (Issue #2041). if state.dtype.kind != 'c': raise TypeError("Input state dtype must be np.complex64 or " "np.complex128") size = state.size num_qubits = int(np.sqrt(size)).bit_length() - 1 _validate_qubit_mapping(qubit_map, self.qubits, num_qubits) dim = int(np.sqrt(size)) if state.shape != (dim, dim) and state.shape != (2, 2) * num_qubits: raise ValueError("Input array does not represent a density matrix " "with shape `(2 ** n, 2 ** n)` or `(2, ..., 2)`.") # HACK: avoid circular import from cirq.sim.density_matrix_utils import to_valid_density_matrix # Do not enforce reshaping if the state all axes are dimension 2. _ = to_valid_density_matrix(density_matrix_rep=state.reshape(dim, dim), num_qubits=num_qubits, dtype=state.dtype) return sum( p._expectation_from_density_matrix_no_validation(state, qubit_map) for p in self)