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 generate_library_of_2q_circuits( n_library_circuits: int, two_qubit_gate: 'cirq.Gate', *, max_cycle_depth: int = 100, q0: 'cirq.Qid' = devices.LineQubit(0), q1: 'cirq.Qid' = devices.LineQubit(1), random_state: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None, ) -> List['cirq.Circuit']: """Generate a library of two-qubit Circuits. For single-qubit gates, this uses PhasedXZGates where the axis-in-XY-plane is one of eight eighth turns and the Z rotation angle is one of eight eighth turns. This provides 8*8=64 total choices, each implementable with one PhasedXZGate. This is appropriate for architectures with microwave single-qubit control. Args: n_library_circuits: The number of circuits to generate. two_qubit_gate: The two qubit gate to use in the circuits. max_cycle_depth: The maximum cycle_depth in the circuits to generate. If you are using XEB, this must be greater than or equal to the maximum value in `cycle_depths`. q0: The first qubit to use when constructing the circuits. q1: The second qubit to use when constructing the circuits random_state: A random state or seed used to deterministically sample the random circuits. """ rs = value.parse_random_state(random_state) exponents = np.linspace(0, 7 / 4, 8) single_qubit_gates = [ ops.PhasedXZGate(x_exponent=0.5, z_exponent=z, axis_phase_exponent=a) for a, z in itertools.product(exponents, repeat=2) ] return [ random_rotations_between_two_qubit_circuit( q0, q1, depth=max_cycle_depth, two_qubit_op_factory=lambda a, b, _: two_qubit_gate(a, b), single_qubit_gates=single_qubit_gates, seed=rs, ) for _ in range(n_library_circuits) ]
random_rotations_between_grid_interaction_layers_circuit, ) if TYPE_CHECKING: import cirq DEFAULT_BASE_DIR = os.path.expanduser( os.path.join('~', 'cirq-results', 'grid-parallel-two-qubit-xeb')) LAYER_A = GridInteractionLayer(col_offset=0, vertical=True, stagger=True) LAYER_B = GridInteractionLayer(col_offset=1, vertical=True, stagger=True) LAYER_C = GridInteractionLayer(col_offset=1, vertical=False, stagger=True) LAYER_D = GridInteractionLayer(col_offset=0, vertical=False, stagger=True) SINGLE_QUBIT_GATES = [ ops.PhasedXZGate(x_exponent=0.5, z_exponent=z, axis_phase_exponent=a) for a, z in itertools.product(np.linspace(0, 7 / 4, 8), repeat=2) ] GridQubitPair = Tuple['cirq.GridQubit', 'cirq.GridQubit'] def save(params: Any, obj: Any, base_dir: str, mode: str = 'x') -> str: """Save an object to filesystem as a JSON file. Arguments: params: Parameters describing the object. This should have an `filename` attribute containing the filename with which to save the object. obj: The object to save. base_dir: The directory in which to save the object. mode: The mode with which to open the file to write. Defaults to 'x',