def is_clifford(circuit: QPROGRAM) -> bool: """Returns True if the input argument is Clifford, else False. Args: circuit: A single operation, list of operations, or circuit. """ return all( cirq.has_stabilizer_effect(op) for op in circuit.all_operations())
def count_non_cliffords(circuit: QPROGRAM) -> int: """Returns the number of non-Clifford operations in the circuit. Assumes the circuit consists of only Rz, Rx, and CNOT operations. Args: circuit: Circuit to count the number of non-Clifford operations in. """ return sum(not cirq.has_stabilizer_effect(op) for op in circuit.all_operations())
def generate_training_circuits( circuit: QPROGRAM, num_training_circuits: int, fraction_non_clifford: float, method_select: str = "uniform", method_replace: str = "closest", random_state: Optional[Union[int, np.random.RandomState]] = None, **kwargs, ) -> List[QPROGRAM]: r"""Returns a list of (near) Clifford circuits obtained by replacing (some) non-Clifford gates in the input circuit by Clifford gates. The way in which non-Clifford gates are selected to be replaced is determined by ``method_select`` and ``method_replace``. In the Clifford Data Regression (CDR) method [Czarnik2020]_, data generated from these circuits is used as a training set to learn the effect of noise. Args: circuit: A circuit of interest assumed to be compiled into the gate set {Rz, sqrt(X), CNOT}, or such that all the non-Clifford gates are contained in the Rz rotations. num_training_circuits: Number of circuits in the returned training set. fraction_non_clifford: The (approximate) fraction of non-Clifford gates in each returned circuit. method_select: Method by which non-Clifford gates are selected to be replaced by Clifford gates. Options are 'uniform' or 'gaussian'. method_replace: Method by which selected non-Clifford gates are replaced by Clifford gates. Options are 'uniform', 'gaussian' or 'closest'. random_state: Seed for sampling. kwargs: Available keyword arguments are: - sigma_select (float): Width of the Gaussian distribution used for ``method_select='gaussian'``. - sigma_replace (float): Width of the Gaussian distribution used for ``method_replace='gaussian'``. .. [Czarnik2020] : Piotr Czarnik, Andrew Arramsmith, Patrick Coles, Lukasz Cincio, "Error mitigation with Clifford quantum circuit data," (https://arxiv.org/abs/2005.10189). """ if random_state is None or isinstance(random_state, int): random_state = np.random.RandomState(random_state) # Find the non-Clifford operations in the circuit. operations = np.array(list(circuit.all_operations())) non_clifford_indices_and_ops = np.array( [[i, op] for i, op in enumerate(operations) if not cirq.has_stabilizer_effect(op)]) if len(non_clifford_indices_and_ops) == 0: raise ValueError("Circuit is already Clifford.") non_clifford_indices = np.int32(non_clifford_indices_and_ops[:, 0]) non_clifford_ops = non_clifford_indices_and_ops[:, 1] # Replace (some of) the non-Clifford operations. near_clifford_circuits = [] for _ in range(num_training_circuits): new_ops = _map_to_near_clifford( non_clifford_ops, fraction_non_clifford, method_select, method_replace, random_state, **kwargs, ) operations[non_clifford_indices] = new_ops near_clifford_circuits.append(Circuit(operations)) return near_clifford_circuits