def _strat_commutes_from_operation( v1: Any, v2: Any, *, atol: float, ) -> Union[bool, NotImplementedType, None]: if not isinstance(v1, ops.Operation) or not isinstance(v2, ops.Operation): return NotImplemented if set(v1.qubits).isdisjoint(v2.qubits): return True from cirq import circuits circuit12 = circuits.Circuit(v1, v2) circuit21 = circuits.Circuit(v2, v1) # Don't create gigantic matrices. if np.product(qid_shape_protocol.qid_shape(circuit12)) > 2**10: return NotImplemented # coverage: ignore m12 = unitary_protocol.unitary(circuit12, default=None) m21 = unitary_protocol.unitary(circuit21, default=None) if m12 is None: return NotImplemented return np.allclose(m12, m21, atol=atol)
def pauli_expansion( val: Any, *, default: Union[value.LinearDict[str], TDefault] = RaiseTypeErrorIfNotProvided, atol: float = 1e-9, ) -> Union[value.LinearDict[str], TDefault]: """Returns coefficients of the expansion of val in the Pauli basis. Args: val: The value whose Pauli expansion is to returned. default: Determines what happens when `val` does not have methods that allow Pauli expansion to be obtained (see below). If set, the value is returned in that case. Otherwise, TypeError is raised. atol: Ignore coefficients whose absolute value is smaller than this. Returns: If `val` has a _pauli_expansion_ method, then its result is returned. Otherwise, if `val` has a small unitary then that unitary is expanded in the Pauli basis and coefficients are returned. Otherwise, if default is set to None or other value then default is returned. Otherwise, TypeError is raised. Raises: TypeError: If `val` has none of the methods necessary to obtain its Pauli expansion and no default value has been provided. """ method = getattr(val, '_pauli_expansion_', None) expansion = NotImplemented if method is None else method() if expansion is not NotImplemented: return expansion.clean(atol=atol) # Don't attempt to derive the pauli expansion if this is a qudit gate if not all(d == 2 for d in qid_shape_protocol.qid_shape(val, default=())): if default is RaiseTypeErrorIfNotProvided: raise TypeError( f'No Pauli expansion for object {val} of type {type(val)}') return default matrix = unitary_protocol.unitary(val, default=None) if matrix is None: if default is RaiseTypeErrorIfNotProvided: raise TypeError( f'No Pauli expansion for object {val} of type {type(val)}') return default num_qubits = matrix.shape[0].bit_length() - 1 basis = operator_spaces.kron_bases(operator_spaces.PAULI_BASIS, repeat=num_qubits) expansion = operator_spaces.expand_matrix_in_orthogonal_basis( matrix, basis) return expansion.clean(atol=atol)
def _strat_distance_from_unitary(val: Any) -> Optional[float]: """Attempts to compute a value's trace_distance_bound from its unitary.""" u = unitary_protocol.unitary(val, default=None) if u is None: return NotImplemented if u.shape == (2, 2): squared = 1 - (0.5 * abs(u[0][0] + u[1][1]))**2 if squared <= 0: return 0.0 return squared**0.5 return trace_distance_from_angle_list(np.angle(np.linalg.eigvals(u)))