def _gate_product_tabulation_cached( optimizer_type: str, tabulation_resolution: float ) -> cirq.TwoQubitGateTabulation: random_state = np.random.RandomState(51) if optimizer_type == 'sycamore': return cirq.two_qubit_gate_product_tabulation( cirq.unitary(cg_ops.SYC), tabulation_resolution, random_state=random_state ) else: raise NotImplementedError(f"Two qubit gate tabulation not supported for {optimizer_type}")
def test_convert_to_sycamore_tabulation(): # A tabulation for the sycamore gate with an infidelity of .1. sycamore_tabulation = cirq.two_qubit_gate_product_tabulation( cirq.unitary(cirq_google.SYC), 0.1, random_state=cirq.value.parse_random_state(11) ) circuit = cirq.Circuit(cirq.MatrixGate(cirq.unitary(cirq.CX)).on(*cirq.LineQubit.range(2))) converted_circuit = cirq.optimize_for_target_gateset( circuit, gateset=cirq_google.SycamoreTargetGateset(tabulation=sycamore_tabulation) ) u1 = cirq.unitary(circuit) u2 = cirq.unitary(converted_circuit) overlap = abs(np.trace(u1.conj().T @ u2)) assert np.isclose(overlap, 4.0, 0.1)
def test_convert_to_sycamore_tabulation(): # A tabulation for the sycamore gate with an infidelity of .1. sycamore_tabulation = cirq.two_qubit_gate_product_tabulation( cirq.unitary(cirq_google.SYC), 0.1, random_state=_rng ) qubits = [cirq.NamedQubit('a'), cirq.NamedQubit('b')] operation = cirq.MatrixGate(cirq.unitary(cirq.CX), qid_shape=(2, 2)).on(qubits[0], qubits[1]) with cirq.testing.assert_deprecated("Use cirq.optimize_for_target_gateset", deadline='v1.0'): converted = cgoc.ConvertToSycamoreGates(sycamore_tabulation).convert(operation) u1 = cirq.unitary(cirq.Circuit(converted)) u2 = cirq.unitary(operation) overlap = abs(np.trace(u1.conj().T @ u2)) assert np.isclose(overlap, 4.0, 0.1)
def gate_product_tabulation( base_gate: np.ndarray, max_infidelity: float, *, sample_scaling: int = 50, allow_missed_points: bool = True, random_state: cirq.RANDOM_STATE_OR_SEED_LIKE = None, ) -> GateTabulation: r"""Generate a GateTabulation for a base two qubit unitary. Args: base_gate: The base gate of the tabulation. max_infidelity: Sets the desired density of tabulated product unitaries. The typical nearest neighbor Euclidean spacing (of the KAK vectors) will be on the order of $\sqrt{max\_infidelity}$. Thus the number of tabulated points will scale as $max\_infidelity^{-3/2}$. sample_scaling: Relative number of random gate products to use in the tabulation. The total number of random local unitaries scales as ~ $max\_infidelity^{-3/2} * sample\_scaling$. Must be positive. random_state: Random state or random state seed. allow_missed_points: If True, the tabulation is allowed to conclude even if not all points in the Weyl chamber are expected to be compilable using 2 or 3 base gates. Otherwise an error is raised in this case. Returns: A GateTabulation object used to compile new two-qubit gates from products of the base gate with 1-local unitaries. Raises: ValueError: If `allow_missed_points` is False and not all points in the Weyl chamber were compilable using 2 or 3 base gates. """ return cast( GateTabulation, two_qubit_gate_product_tabulation( base_gate, max_infidelity, sample_scaling=sample_scaling, allow_missed_points=allow_missed_points, random_state=random_state, ), )
def main(samples: int = 1000, max_infidelity: float = 0.01): """Demonstration of the usage of the TwoQubitGateTabulation gate compiler. Args: samples: Number of random 2-qubit unitary samples to compile. max_infidelity: Maximum allowed infidelity between randomly generated gate and the gate compilation used to generate it. The example runtime scales as max_infidelity^{-2}. """ # Define a base gate for compilation theta = np.pi / 4 phi = np.pi / 24 base = cirq.unitary(cirq.FSimGate(theta, phi)) # The TwoQubitGateTabulation object is essentially a tabulation of many randomly # generated gate products (of the form A k A or A k A k A), along with their # associate KAK vectors. The parameter max_infidelity determines the # approximate "density" of the tabulated gates. Specifically, it bounds the # typical distance between an arbitrary two-qubit gate and the nearest # tabulated gate. start = time() tabulation = cirq.two_qubit_gate_product_tabulation(base, max_infidelity) print(tabulation.summary) print(f'Gate tabulation time : {time() - start} seconds.') # Generate many random two-qubit gates, then attempt to compile them using # the tabulation. unitaries = [random_special_unitary(4) for _ in range(samples)] infidelities = [] failed_infidelities = [] start = time() for target in unitaries: # result.actual_gate is the compiled gate product intended to match the # target. result.success denotes is the actual gate is expected to be # within the desired fidelity to the target. It can be False if the # base gate cannot "fill" the Weyl chamber using at most 3 products. # result.local_unitaries stores the local unitaries required to # compile the target unitary from the base unitary. result = tabulation.compile_two_qubit_gate(target) infidelity = 1 - unitary_entanglement_fidelity(target, result.actual_gate) if result.success: infidelities.append(infidelity) else: failed_infidelities.append(infidelity) # coverage: ignore t_comp = time() - start print( f'Gate compilation time : {t_comp:.3f} seconds ({t_comp / samples:.4f} s per gate)' ) infidelities = np.array(infidelities) failed_infidelities = np.array(failed_infidelities) if np.size(failed_infidelities): # coverage: ignore print( f'Number of "failed" compilations: {np.size(failed_infidelities)}.' ) print( f'Maximum infidelity of "failed" compilation: {np.max(failed_infidelities)}' ) plt.figure() plt.hist(infidelities, bins=25, range=[0, max_infidelity * 1.1]) ylim = plt.ylim() plt.plot([max_infidelity] * 2, ylim, '--', label='Maximum tabulation infidelity') plt.xlabel('Compiled gate infidelity vs target') plt.ylabel('Counts') plt.legend() plt.title(f'Base FSim(theta={theta:.4f}, phi={phi:.4f})') plt.show()
matrix_gate(q[0]).controlled_by(q[1]).with_tags('test_tags'), matrix_gate(q[0]).with_tags('test_tags').controlled_by(q[1]), ], ) def test_supported_operation(op): circuit = cirq.Circuit(op) converted_circuit = cirq.optimize_for_target_gateset( circuit, gateset=cirq_google.SycamoreTargetGateset() ) cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent( circuit, converted_circuit, atol=1e-8 ) multi_qubit_ops = [e for e in converted_circuit.all_operations() if len(e.qubits) > 1] assert all(isinstance(e.gate, cirq_google.SycamoreGate) for e in multi_qubit_ops) @pytest.mark.parametrize( 'gateset', [ cirq_google.SycamoreTargetGateset(), cirq_google.SycamoreTargetGateset( tabulation=cirq.two_qubit_gate_product_tabulation( cirq.unitary(cirq_google.SYC), 0.1, random_state=cirq.value.parse_random_state(11) ) ), ], ) def test_repr_json(gateset): assert eval(repr(gateset)) == gateset assert cirq.read_json(json_text=cirq.to_json(gateset)) == gateset