def assert_has_consistent_trace_distance_bound(val: Any) -> None: u = protocols.unitary(val, default=None) val_from_trace = protocols.trace_distance_bound(val) assert 0.0 <= val_from_trace <= 1.0 if u is not None: class Unitary: def _unitary_(self): return u val_from_unitary = protocols.trace_distance_bound(Unitary()) assert val_from_trace >= val_from_unitary or np.isclose( val_from_trace, val_from_unitary)
def single_qubit_matrix_to_phased_x_z(mat: np.ndarray, atol: float = 0 ) -> List[ops.SingleQubitGate]: """Implements a single-qubit operation with a PhasedX and Z gate. If one of the gates isn't needed, it will be omitted. Args: mat: The 2x2 unitary matrix of the operation to implement. atol: A limit on the amount of error introduced by the construction. Returns: A list of gates that, when applied in order, perform the desired operation. """ xy_turn, xy_phase_turn, total_z_turn = ( _deconstruct_single_qubit_matrix_into_gate_turns(mat)) # Build the intended operation out of non-negligible XY and Z rotations. result = [ ops.PhasedXPowGate(exponent=2 * xy_turn, phase_exponent=2 * xy_phase_turn), ops.Z**(2 * total_z_turn) ] result = [g for g in result if protocols.trace_distance_bound(g) > atol] # Special case: XY half-turns can absorb Z rotations. if len(result) == 2 and abs(xy_turn) >= 0.5 - atol: return [ ops.PhasedXPowGate(phase_exponent=2 * xy_phase_turn + total_z_turn) ] return result
def single_qubit_matrix_to_phxz(mat: np.ndarray, atol: float = 0) -> Optional[ops.PhasedXZGate]: """Implements a single-qubit operation with a PhasedXZ gate. Under the hood, this uses deconstruct_single_qubit_matrix_into_angles which converts the given matrix to a series of three rotations around the Z, Y, Z axes. This is then converted to a phased X rotation followed by a Z, in the form of a single PhasedXZ gate. Args: mat: The 2x2 unitary matrix of the operation to implement. atol: A limit on the amount of error introduced by the construction. Returns: A PhasedXZ gate that implements the given matrix, or None if it is close to identity (trace distance <= atol). """ xy_turn, xy_phase_turn, total_z_turn = _deconstruct_single_qubit_matrix_into_gate_turns(mat) # Build the intended operation out of non-negligible XY and Z rotations. g = ops.PhasedXZGate( axis_phase_exponent=2 * xy_phase_turn, x_exponent=2 * xy_turn, z_exponent=2 * total_z_turn ) if protocols.trace_distance_bound(g) <= atol: return None # Special case: XY half-turns can absorb Z rotations. if math.isclose(abs(xy_turn), 0.5, abs_tol=atol): g = ops.PhasedXZGate( axis_phase_exponent=2 * xy_phase_turn + total_z_turn, x_exponent=1, z_exponent=0 ) return g
def assert_has_consistent_trace_distance_bound(val: Any) -> None: # pylint: disable=unused-variable __tracebackhide__ = True # pylint: enable=unused-variable u = protocols.unitary(val, default=None) val_from_trace = protocols.trace_distance_bound(val) assert 0.0 <= val_from_trace <= 1.0 if u is not None: class Unitary: def _unitary_(self): return u val_from_unitary = protocols.trace_distance_bound(Unitary()) assert val_from_trace >= val_from_unitary or np.isclose(val_from_trace, val_from_unitary)
def optimize_circuit(self, circuit: _circuit.Circuit) -> None: deletions: List[Tuple[int, ops.Operation]] = [] for moment_index, moment in enumerate(circuit): for op in moment.operations: if op is not None and protocols.trace_distance_bound(op) <= self.tolerance: deletions.append((moment_index, op)) circuit.batch_remove(deletions)
def single_qubit_matrix_to_native_gates(mat: np.ndarray, tolerance: float = 0 ) -> List[ops.SingleQubitGate]: """Implements a single-qubit operation with few native gates. Args: mat: The 2x2 unitary matrix of the operation to implement. tolerance: A limit on the amount of error introduced by the construction. Returns: A list of gates that, when applied in order, perform the desired operation. """ xy_turn, xy_phase_turn, total_z_turn = ( _deconstruct_single_qubit_matrix_into_gate_turns(mat)) # Build the intended operation out of non-negligible XY and Z rotations. result = [ ExpWGate(half_turns=2 * xy_turn, axis_half_turns=2 * xy_phase_turn), ops.RotZGate(half_turns=2 * total_z_turn) ] result = [ g for g in result if protocols.trace_distance_bound(g) > tolerance ] # Special case: XY half-turns can absorb Z rotations. if len(result) == 2 and abs(xy_turn) >= 0.5 - tolerance: return [ExpWGate(axis_half_turns=2 * xy_phase_turn + total_z_turn)] return result
def _trace_distance_bound_(self) -> Optional[float]: if protocols.is_parameterized(self.sub_gate): return None angle = self._num_copies * np.arcsin(protocols.trace_distance_bound(self.sub_gate)) if angle >= np.pi * 0.5: return 1.0 return np.sin(angle)
def _trace_distance_bound_(self) -> float: return protocols.trace_distance_bound(self.sub_operation)
def _trace_distance_bound_(self) -> float: result = protocols.trace_distance_bound(self.sub_gate) if not self._is_parameterized_(): result *= float(self.probability) return result
def _trace_distance_bound_(self) -> float: return protocols.trace_distance_bound( ops.RotZGate(half_turns=self.half_turns))
def _trace_distance_bound_(self): """See `cirq.SupportsTraceDistanceBound`.""" return protocols.trace_distance_bound(cirq.X**self._exponent)
def _trace_distance_bound_(self) -> Optional[float]: angle = (len(self.qubits) * np.arcsin(protocols.trace_distance_bound(self._gate))) if angle >= np.pi * 0.5: return 1.0 return np.sin(angle)
def _trace_distance_bound_(self): return protocols.trace_distance_bound(self.sub_gate)
def map_func(op: 'cirq.Operation', _: int) -> 'cirq.OP_TREE': return ( op if protocols.is_measurement(op) or protocols.trace_distance_bound(op) > atol else [] )
def _trace_distance_bound_(self) -> float: return protocols.trace_distance_bound( pauli_gates.Z**self.exponent_relative)
def _trace_distance_bound_(self) -> float: return protocols.trace_distance_bound(ops.Z**self.half_turns)
def _trace_distance_bound_(self) -> float: if len(self.qubits) == 0: return 0.0 return protocols.trace_distance_bound( pauli_gates.Z**self.exponent_relative)
def _trace_distance_bound_(self) -> float: return protocols.trace_distance_bound(self.gate)