Describe the issue
TwoQubitGateTabulation.compile_two_qubit_gate returns an actual_gate that differs by a global phase from the product reconstructed from its local_unitaries and base gate. The result documentation defines actual_gate as that product, so the two representations should agree.
This is a return-value consistency issue, not a claim that success=True requires preservation of the target's global phase. The difference does not affect ordinary circuit execution, but can become observable if the compiled block is subsequently placed under coherent quantum control.
Explain how to reproduce the bug or problem
import cirq
import numpy as np
base = cirq.unitary(cirq.CZ)
tabulation = cirq.two_qubit_gate_product_tabulation(base, 0.1, random_state=42)
target = np.exp(1j * np.pi / 4) * base
result = tabulation.compile_two_qubit_gate(target)
built = np.kron(*result.local_unitaries[0])
for pair in result.local_unitaries[1:]:
built = np.kron(*pair) @ base @ built
print("success:", result.success)
print("built matches actual_gate:", np.allclose(built, result.actual_gate))
print("built matches target up to phase:",
cirq.linalg.allclose_up_to_global_phase(built, target))
# Illustrate the phase difference using coherent control and interference.
q0, q1, q2 = cirq.LineQubit.range(3)
for label, block in [("target", target), ("built", built)]:
circuit = cirq.Circuit(
cirq.X(q1), cirq.X(q2), cirq.H(q0),
cirq.MatrixGate(block).controlled().on(q0, q1, q2),
cirq.H(q0),
)
state = cirq.Simulator(dtype=np.complex128).simulate(
circuit, qubit_order=[q0, q1, q2]
).final_state_vector
print(f"{label} P(control=0): {np.sum(np.abs(state[:4])**2):.6f}")
Observed output:
success: True
built matches actual_gate: False
built matches target up to phase: True
target P(control=0): 0.146447
built P(control=0): 0.500000
The coherent-control example illustrates a consequence of reusing the compiled block; it does not demonstrate a failure in Cirq's standard compilation pipelines.
Tell us the version of Cirq where this happens
Cirq 1.7.0, Python 3.11.4, Linux.
Root cause
In _outer_locals_for_unitary, the reconstructed matrix is multiplied by np.conj(target_decomp.global_phase), but the returned local gates are unchanged. Keep actual_gate consistent with their product, or explicitly document the differing phase conventions.
Describe the issue
TwoQubitGateTabulation.compile_two_qubit_gatereturns anactual_gatethat differs by a global phase from the product reconstructed from itslocal_unitariesand base gate. The result documentation definesactual_gateas that product, so the two representations should agree.This is a return-value consistency issue, not a claim that
success=Truerequires preservation of the target's global phase. The difference does not affect ordinary circuit execution, but can become observable if the compiled block is subsequently placed under coherent quantum control.Explain how to reproduce the bug or problem
Observed output:
The coherent-control example illustrates a consequence of reusing the compiled block; it does not demonstrate a failure in Cirq's standard compilation pipelines.
Tell us the version of Cirq where this happens
Cirq 1.7.0, Python 3.11.4, Linux.
Root cause
In
_outer_locals_for_unitary, the reconstructed matrix is multiplied bynp.conj(target_decomp.global_phase), but the returned local gates are unchanged. Keepactual_gateconsistent with their product, or explicitly document the differing phase conventions.