def _run(self, circuit: circuits.AbstractCircuit, repetitions: int) -> Dict[str, np.ndarray]: measurements: Dict[str, List[int]] = { key: [] for key in protocols.measurement_key_names(circuit) } qubits = circuit.all_qubits() for _ in range(repetitions): state = ActOnCliffordTableauArgs( CliffordTableau(num_qubits=len(qubits)), qubits=list(qubits), prng=self._prng, log_of_measurement_results={}, ) for op in circuit.all_operations(): protocols.act_on(op, state) for k, v in state.log_of_measurement_results.items(): measurements[k].append(v) return {k: np.array(v) for k, v in measurements.items()}
def assert_circuits_with_terminal_measurements_are_equivalent( actual: circuits.AbstractCircuit, reference: circuits.AbstractCircuit, atol: float) -> None: """Determines if two circuits have equivalent effects. The circuits can contain measurements, but the measurements must be at the end of the circuit. Circuits are equivalent if, for all possible inputs, their outputs (classical bits for lines terminated with measurement and qubits for lines without measurement) are observationally indistinguishable up to a tolerance. Note that under this definition of equivalence circuits that differ solely in the overall phase of the post-measurement state of measured qubits are considered equivalent. For example, applying an extra Z gate to an unmeasured qubit changes the effect of a circuit. But inserting a Z gate operation just before a measurement does not. Args: actual: The circuit that was actually computed by some process. reference: A circuit with the correct function. atol: Absolute error tolerance. """ # pylint: disable=unused-variable __tracebackhide__ = True # pylint: enable=unused-variable measured_qubits_actual = { qubit for op in actual.all_operations() if protocols.is_measurement(op) for qubit in op.qubits } measured_qubits_reference = { qubit for op in reference.all_operations() if protocols.is_measurement(op) for qubit in op.qubits } assert actual.are_all_measurements_terminal() assert reference.are_all_measurements_terminal() assert measured_qubits_actual == measured_qubits_reference all_qubits = actual.all_qubits().union(reference.all_qubits()) matrix_actual = actual.unitary(qubits_that_should_be_present=all_qubits) matrix_reference = reference.unitary( qubits_that_should_be_present=all_qubits) n_qubits = len(all_qubits) n = matrix_actual.shape[0] assert n == 1 << n_qubits assert matrix_actual.shape == matrix_reference.shape == (n, n) # Consider the action of the two circuits Ca and Cr on state |x>: # # |ya> = Ca|x> # |yr> = Cr|x> # # Ca and Cr are equivalent according to the definition above iff # for each |x>: # - probability of each measurement outcome is the same for |ya> # and |yr> (across measured qubits), # - amplitudes of each post-measurement state are the same for |ya> # and |yr> except perhaps for an overall phase factor. # # These conditions are satisfied iff the matrices of the two circuits # are identical except perhaps for an overall phase factor for each # rectangular block spanning rows corresponding to the measurement # subspaces and all columns. # # Note two special cases of the rule above: # - if no qubits are measured then the circuits are equivalent if # their matrices are identical except for the global phase factor, # - if all qubits are measured then the circuits are equivalent if # their matrices differ by a diagonal unitary factor. subspaces = _measurement_subspaces(measured_qubits_actual, n_qubits) for subspace in subspaces: block_actual = matrix_actual[subspace, :] block_reference = matrix_reference[subspace, :] assert linalg.allclose_up_to_global_phase( block_actual, block_reference, atol=atol), ( "Circuit's effect differs from the reference circuit.\n" '\n' 'Diagram of actual circuit:\n' '{}\n' '\n' 'Diagram of reference circuit with desired function:\n' '{}\n'.format(actual, reference))
def validate_circuit(self, circuit: circuits.AbstractCircuit): super().validate_circuit(circuit) _verify_unique_measurement_keys(circuit.all_operations())