def assert_commutes_magic_method_consistent_with_unitaries( *vals: Sequence[Any], atol: Union[int, float] = 1e-8 ) -> None: if any(isinstance(val, ops.Operation) for val in vals): raise TypeError('`_commutes_` need not be consistent with unitaries for `Operation`.') unitaries = [protocols.unitary(val, None) for val in vals] pairs = itertools.permutations(zip(vals, unitaries), 2) for (left_val, left_unitary), (right_val, right_unitary) in pairs: if left_unitary is None or right_unitary is None: continue commutes = protocols.commutes(left_val, right_val, atol=atol, default=None) if commutes is None: continue assert commutes == protocols.commutes(left_unitary, right_unitary)
def _commutes_( self, other: Any, *, atol: Union[int, float] = 1e-8) -> Union[bool, NotImplementedType, None]: return protocols.commutes(self.sub_operation, other, atol=atol)
def _commutes_( self, other: Any, *, atol: Union[int, float] = 1e-8 ) -> Union[bool, NotImplementedType]: """Determines whether Moment commutes with the Operation. Args: other: An Operation object. Other types are not implemented yet. In case a different type is specified, NotImplemented is returned. atol: Absolute error tolerance. If all entries in v1@v2 - v2@v1 have a magnitude less than this tolerance, v1 and v2 can be reported as commuting. Defaults to 1e-8. Returns: True: The Moment and Operation commute OR they don't have shared quibits. False: The two values do not commute. NotImplemented: In case we don't know how to check this, e.g. the parameter type is not supported yet. """ if not isinstance(other, ops.Operation): return NotImplemented other_qubits = set(other.qubits) for op in self.operations: if not other_qubits.intersection(set(op.qubits)): continue commutes = protocols.commutes(op, other, atol=atol, default=NotImplemented) if not commutes or commutes is NotImplemented: return commutes return True
def _commutes_(self, other: Any, atol: float) -> Union[None, NotImplementedType, bool]: if not isinstance(other, Gate): return NotImplemented if protocols.qid_shape(self) != protocols.qid_shape(other): return None qs = line_qubit.LineQid.for_qid_shape(protocols.qid_shape(self)) return protocols.commutes(self(*qs), other(*qs))
def _pass_pauli_interaction_gate_over( pauli_map: Dict[raw_types.Qid, pauli_gates.Pauli], gate: pauli_interaction_gate.PauliInteractionGate, qubit0: 'cirq.Qid', qubit1: 'cirq.Qid', after_to_before: bool = False) -> bool: def merge_and_kickback(qubit: 'cirq.Qid', pauli_left: Optional[pauli_gates.Pauli], pauli_right: Optional[pauli_gates.Pauli], inv: bool) -> int: assert pauli_left is not None or pauli_right is not None if pauli_left is None or pauli_right is None: pauli_map[qubit] = cast(pauli_gates.Pauli, pauli_left or pauli_right) return 0 if pauli_left == pauli_right: del pauli_map[qubit] return 0 pauli_map[qubit] = pauli_left.third(pauli_right) if (pauli_left < pauli_right) ^ after_to_before: return int(inv) * 2 + 1 return int(inv) * 2 - 1 quarter_kickback = 0 if (qubit0 in pauli_map and not protocols.commutes(pauli_map[qubit0], gate.pauli0)): quarter_kickback += merge_and_kickback(qubit1, gate.pauli1, pauli_map.get(qubit1), gate.invert1) if (qubit1 in pauli_map and not protocols.commutes(pauli_map[qubit1], gate.pauli1)): quarter_kickback += merge_and_kickback(qubit0, pauli_map.get(qubit0), gate.pauli0, gate.invert0) assert quarter_kickback % 2 == 0, ( 'Impossible condition. ' 'quarter_kickback is either incremented twice or never.') return quarter_kickback % 4 == 2
def _commutes_( self, other: Any, *, atol: Union[int, float] = 1e-8) -> Union[bool, NotImplementedType, None]: if not isinstance(other, PauliString): return NotImplemented return sum(not protocols.commutes(p0, p1) for p0, p1 in self.zip_paulis(other)) % 2 == 0
def _commutes_( self, other: Any, *, atol: Union[int, float] = 1e-8) -> Union[bool, NotImplementedType, None]: if not isinstance(other, Gate): return NotImplemented if protocols.qid_shape(self) != protocols.qid_shape(other): return None # HACK: break cycle from cirq.devices import line_qubit qs = line_qubit.LineQid.for_qid_shape(protocols.qid_shape(self)) return protocols.commutes(self(*qs), other(*qs))
def _sorted_best_string_placements( possible_nodes: Iterable[Any], output_ops: Sequence[ops.Operation], key: Callable[[Any], ops.PauliStringPhasor] = lambda node: node.val, ) -> List[Tuple[ops.PauliStringPhasor, int, circuitdag.Unique[ops.PauliStringPhasor]]]: sort_key = lambda placement: (-len(placement[0].pauli_string), placement[1] ) node_maxes = [] for possible_node in possible_nodes: string_op = key(possible_node) # Try moving the Pauli string through, stop at measurements node_max = (string_op, 0, possible_node) for i, out_op in enumerate(output_ops): if not set(out_op.qubits) & set(string_op.qubits): # Skip if operations don't share qubits continue if isinstance(out_op, ops.PauliStringPhasor) and protocols.commutes( out_op.pauli_string, string_op.pauli_string): # Pass through another Pauli string if they commute continue if not (isinstance(out_op, ops.GateOperation) and isinstance( out_op.gate, (ops.SingleQubitCliffordGate, ops.PauliInteractionGate, ops.CZPowGate), )): # This is as far through as this Pauli string can move break string_op = string_op.pass_operations_over([out_op], after_to_before=True) curr = (string_op, i + 1, possible_node) if sort_key(curr) > sort_key(node_max): node_max = curr node_maxes.append(node_max) return sorted(node_maxes, key=sort_key, reverse=True)
def pauli_string_reorder_pred(op1: ops.Operation, op2: ops.Operation) -> bool: ps1 = cast(ops.PauliStringGateOperation, op1).pauli_string ps2 = cast(ops.PauliStringGateOperation, op2).pauli_string return protocols.commutes(ps1, ps2)
def _all_pauli_strings_commute(pauli_sum: 'cirq.PauliSum') -> bool: for x in pauli_sum: for y in pauli_sum: if not protocols.commutes(x, y): return False return True