def _fix_single_qubit_gates_around_kak_interaction( *, desired: 'cirq.KakDecomposition', operations: List['cirq.Operation'], qubits: Sequence['cirq.Qid'], ) -> Iterator['cirq.Operation']: """Adds single qubit operations to complete a desired interaction. Args: desired: The kak decomposition of the desired operation. qubits: The pair of qubits that is being operated on. operations: A list of operations that composes into the desired kak interaction coefficients, but may not have the desired before/after single qubit operations or the desired global phase. Returns: A list of operations whose kak decomposition approximately equals the desired kak decomposition. """ actual = linalg.kak_decomposition(circuits.Circuit(operations)) def dag(a: np.ndarray) -> np.ndarray: return np.transpose(np.conjugate(a)) for k in range(2): g = ops.MatrixGate( dag(actual.single_qubit_operations_before[k]) @ desired.single_qubit_operations_before[k]) yield g(qubits[k]) yield from operations for k in range(2): g = ops.MatrixGate(desired.single_qubit_operations_after[k] @ dag( actual.single_qubit_operations_after[k])) yield g(qubits[k]) yield ops.GlobalPhaseOperation(desired.global_phase / actual.global_phase)
def _decompose_(self, qubits): from cirq import ops a, b = qubits return [ ops.GlobalPhaseOperation(self.global_phase), ops.MatrixGate(self.single_qubit_operations_before[0]).on(a), ops.MatrixGate(self.single_qubit_operations_before[1]).on(b), np.exp(1j * ops.X(a) * ops.X(b) * self.interaction_coefficients[0]), np.exp(1j * ops.Y(a) * ops.Y(b) * self.interaction_coefficients[1]), np.exp(1j * ops.Z(a) * ops.Z(b) * self.interaction_coefficients[2]), ops.MatrixGate(self.single_qubit_operations_after[0]).on(a), ops.MatrixGate(self.single_qubit_operations_after[1]).on(b), ]
def cphase_to_sqrt_iswap(a, b, turns): """Implement a C-Phase gate using two sqrt ISWAP gates and single-qubit operations. The circuit is equivalent to cirq.CZPowGate(exponent=turns). Output unitary: [1 0 0 0], [0 1 0 0], [0 0 1 0], [0 0 0 e^{i turns pi}]. Args: a: the first qubit b: the second qubit turns: Exponent specifying the evolution time in number of rotations. """ theta = (turns % 2) * np.pi if 0 <= theta <= np.pi: sign = 1. theta_prime = theta elif np.pi < theta < 2 * np.pi: sign = -1. theta_prime = 2 * np.pi - theta if np.isclose(theta, np.pi): # If we are close to pi, just set values manually to avoid possible # numerical errors with arcsin of greater than 1.0 (Ahem, Windows). phi = np.pi / 2 xi = np.pi / 2 else: phi = np.arcsin(np.sqrt(2) * np.sin(theta_prime / 4)) xi = np.arctan(np.tan(phi) / np.sqrt(2)) yield ops.rz(sign * 0.5 * theta_prime).on(a) yield ops.rz(sign * 0.5 * theta_prime).on(b) yield ops.rx(xi).on(a) yield ops.X(b)**(-sign * 0.5) yield SQRT_ISWAP_INV(a, b) yield ops.rx(-2 * phi).on(a) yield SQRT_ISWAP(a, b) yield ops.rx(xi).on(a) yield ops.X(b)**(sign * 0.5) # Corrects global phase yield ops.GlobalPhaseOperation(np.exp(sign * theta_prime * 0.25j))
def decompose_cphase_into_two_fsim(cphase_gate: 'cirq.CZPowGate', *, fsim_gate: 'cirq.FSimGate', qubits: Optional[ Sequence['cirq.Qid']] = None, atol: float = 1e-8) -> 'cirq.OP_TREE': """Decomposes CZPowGate into two FSimGates. This function implements the decomposition described in section VII F I of https://arxiv.org/abs/1910.11333. The decomposition results in exactly two FSimGates and a few single-qubit rotations. It is feasible if and only if one of the following conditions is met: |sin(θ)| <= |sin(δ/4)| <= |sin(φ/2)| |sin(φ/2)| <= |sin(δ/4)| <= |sin(θ)| where: θ = fsim_gate.theta, φ = fsim_gate.phi, δ = -π * cphase_gate.exponent. Note that the gate parametrizations are non-injective. For the decomposition to be feasible it is sufficient that one of the parameter values which correspond to the provided gate satisfies the constraints. This function will find and use the appropriate value whenever it exists. The constraints above imply that certain FSimGates are not suitable for use in this decomposition regardless of the target CZPowGate. We reject such gates based on how close |sin(θ)| is to |sin(φ/2)|, see atol argument below. This implementation accounts for the global phase. Args: cphase_gate: The CZPowGate to synthesize. fsim_gate: The only two qubit gate that is permitted to appear in the output. qubits: The qubits to apply the resulting operations to. If not set, defaults `cirq.LineQubit.range(2)`. atol: Tolerance used to determine whether fsim_gate is valid. The gate is invalid if the squares of the sines of the theta angle and half the phi angle are too close. Returns: Operations equivalent to cphase_gate and consisting solely of two copies of fsim_gate and a few single-qubit rotations. Raises: ValueError under any of the following circumstances: * cphase_gate or fsim_gate is parametrized, * cphase_gate and fsim_gate do not satisfy the conditions above, * fsim_gate has invalid angles (see atol argument above), * incorrect number of qubits are provided. """ if protocols.is_parameterized(cphase_gate): raise ValueError('Cannot decompose a parametrized gate.') if protocols.is_parameterized(fsim_gate): raise ValueError('Cannot decompose into a parametrized gate.') if qubits is None: qubits = devices.LineQubit.range(2) if len(qubits) != 2: raise ValueError(f'Expected a pair of qubits, but got {qubits!r}.') q0, q1 = qubits theta = fsim_gate.theta phi = fsim_gate.phi sin_half_phi = np.sin(phi / 2) cos_half_phi = np.cos(phi / 2) sin_theta = np.sin(theta) cos_theta = np.cos(theta) # # Step 1: find alpha # denominator = (sin_theta - sin_half_phi) * (sin_theta + sin_half_phi) if abs(denominator) < atol: raise ValueError( f'{fsim_gate} cannot be used to decompose CZPowGate because ' 'sin(theta)**2 is too close to sin(phi/2)**2 ' f'(difference is {denominator}).') # Parametrization of CZPowGate by a real angle is a non-injective function # with the preimage of cphase_gate infinite. However, it is sufficient to # check just two of the angles against the constraints of the decomposition. canonical_delta = -np.pi * (cphase_gate.exponent % 2) for delta in (canonical_delta, canonical_delta + 2 * np.pi): sin_quarter_delta = np.sin(delta / 4) numerator = (sin_quarter_delta - sin_half_phi) * (sin_quarter_delta + sin_half_phi) sin_alpha_squared = numerator / denominator if 0 <= sin_alpha_squared <= 1: break else: intervals = compute_cphase_exponents_for_fsim_decomposition(fsim_gate) raise ValueError( f'{cphase_gate} cannot be decomposed into two {fsim_gate}. Valid ' f'intervals for canonical exponent of CZPowGate: {intervals}.') assert 0 <= sin_alpha_squared <= 1 alpha = np.arcsin(np.sqrt(sin_alpha_squared)) # # Step 2: find xi and eta # tan_alpha = np.tan(alpha) xi = np.arctan2(tan_alpha * cos_theta, cos_half_phi) eta = np.arctan2(tan_alpha * sin_theta, sin_half_phi) if delta < 0: eta += np.pi # # Step 3: synthesize output circuit # return ( # Local X rotations to convert Γ1⊗I − iZ⊗Γ2 into exp(-i Z⊗Z δ/4) ops.rx(xi).on(q0), ops.rx(eta).on(q1), # Y(θ, φ) := exp(-i X⊗X θ/2) exp(-i Y⊗Y θ/2) exp(-i Z⊗Z φ/4) fsim_gate.on(q0, q1), ops.rz(phi / 2).on(q0), ops.rz(phi / 2).on(q1), ops.GlobalPhaseOperation(np.exp(1j * phi / 4)), # exp(i X1 α) ops.rx(-2 * alpha).on(q0), # Y(-θ, φ) := exp(i X⊗X θ/2) exp(i Y⊗Y θ/2) exp(-i Z⊗Z φ/4) ops.Z(q0), fsim_gate.on(q0, q1), ops.rz(phi / 2).on(q0), ops.rz(phi / 2).on(q1), ops.GlobalPhaseOperation(np.exp(1j * phi / 4)), ops.Z(q0), # Local X rotations to convert Γ1⊗I − iZ⊗Γ2 into exp(-i Z⊗Z δ/4) ops.rx(-eta).on(q1), ops.rx(xi).on(q0), # Local Z rotations to convert exp(-i Z⊗Z δ/4) into desired CPhase. ops.rz(-delta / 2).on(q0), ops.rz(-delta / 2).on(q1), ops.GlobalPhaseOperation(np.exp(-1j * delta / 4)), )
def generate_all_scalar_cell_makers() -> Iterator[CellMaker]: yield _scalar("NeGate", ops.GlobalPhaseOperation(-1)) yield _scalar("i", ops.GlobalPhaseOperation(1j)) yield _scalar("-i", ops.GlobalPhaseOperation(-1j)) yield _scalar("√i", ops.GlobalPhaseOperation(1j**0.5)) yield _scalar("√-i", ops.GlobalPhaseOperation((-1j)**0.5))