def test_run_factory(): rand_circ = random_identity_circuit(depth=TEST_DEPTH) qp = measure(rand_circ, qid=0) fac = RichardsonFactory([1.0, 2.0, 3.0]) fac.run(qp, basic_executor, scale_noise) result = fac.reduce() assert np.isclose(result, 1.0, atol=1.0e-1)
def test_run_factory(): """Tests qrun of a Richardson Factory.""" qp = random_one_qubit_identity_circuit(num_cliffords=TEST_DEPTH) qp = measure(qp, 0) fac = RichardsonFactory([1.0, 2.0, 3.0]) fac.run(qp, basic_executor, scale_noise) result = fac.reduce() assert np.isclose(result, 1.0, atol=1.0e-1)
def test_richardson_extr(test_f: Callable[[float], float]): """Test of the Richardson's extrapolator.""" seeded_f = apply_seed_to_func(test_f, SEED) fac = RichardsonFactory(scale_factors=X_VALS) assert not fac._opt_params fac.run_classical(seeded_f) zne_value = fac.reduce() assert np.isclose(zne_value, seeded_f(0, err=0), atol=CLOSE_TOL) assert len(fac._opt_params) == len(X_VALS) assert np.isclose(fac._opt_params[-1], zne_value)
def test_fake_nodes_extrapolation(): """Test that there exists a regime in which FakeNodesFactory is better than RichardsonFactory. Note: in many cases RichardsonFactory is better. """ y_vals = [f_runge(x) for x in UNIFORM_X] zne_runge = FakeNodesFactory.extrapolate(UNIFORM_X, y_vals) zne_richard = RichardsonFactory.extrapolate(UNIFORM_X, y_vals) abs_err_runge = np.abs(zne_runge - f_runge(0.0)) abs_err_richard = np.abs(zne_richard - f_runge(0.0)) # Test Richardson extrapolation error is much larger assert 500 * abs_err_runge < abs_err_richard
def execute_with_zne( qp: QPROGRAM, executor: Callable[[QPROGRAM], float], factory: Optional[Factory] = None, scale_noise: Callable[[QPROGRAM, float], QPROGRAM] = fold_gates_at_random, num_to_average: int = 1, ) -> float: """Returns the zero-noise extrapolated expectation value that is computed by running the quantum program `qp` with the executor function. Args: qp: Quantum program to execute with error mitigation. executor: Executes a circuit and returns an expectation value. factory: Factory object that determines the zero-noise extrapolation method. scale_noise: Function for scaling the noise of a quantum circuit. num_to_average: Number of times expectation values are computed by the executor after each call to scale_noise, then averaged. """ if not factory: factory = RichardsonFactory(scale_factors=[1.0, 2.0, 3.0]) if not callable(executor): raise TypeError("Argument `executor` must be callable.") if not isinstance(factory, Factory): raise TypeError( f"Argument `factory` must be of type mitiq.factories.Factory " f"but type(factory) is {type(factory)}.") if not callable(scale_noise): raise TypeError("Argument `scale_noise` must be callable.") if num_to_average < 1: raise ValueError("Argument `num_to_average` must be a positive int.") factory.run(qp, executor, scale_noise, int(num_to_average)) # print(factory.get_scale_factors()) # print(factory.get_expectation_values()) zero_lim = factory.reduce() plt.plot(factory.get_scale_factors(), factory.get_expectation_values(), 'bo') plt.show() return zero_lim
def execute_with_zne( circuit: QPROGRAM, executor: Union[Executor, Callable[[QPROGRAM], QuantumResult]], observable: Optional[Observable] = None, *, factory: Optional[Factory] = None, scale_noise: Callable[[QPROGRAM, float], QPROGRAM] = fold_gates_at_random, num_to_average: int = 1, ) -> float: """Estimates the error-mitigated expectation value associated to the input circuit, via the application of zero-noise extrapolation (ZNE). Args: circuit: The input circuit to execute with ZNE. executor: A Mitiq executor that executes a circuit and returns the unmitigated ``QuantumResult`` (e.g. an expectation value). observable: Observable to compute the expectation value of. If ``None``, the ``executor`` must return an expectation value. Otherwise, the ``QuantumResult`` returned by ``executor`` is used to compute the expectation of the observable. factory: ``Factory`` object that determines the zero-noise extrapolation method. scale_noise: The function for scaling the noise of a quantum circuit. A list of built-in functions can be found in ``mitiq.zne.scaling``. num_to_average: Number of times expectation values are computed by the executor after each call to ``scale_noise``, then averaged. Returns: The expectation value estimated with ZNE. """ if not factory: factory = RichardsonFactory(scale_factors=[1.0, 2.0, 3.0]) if not isinstance(factory, Factory): raise TypeError( f"Argument `factory` must be of type mitiq.factories.Factory " f"but type(factory) is {type(factory)}.") if not callable(scale_noise): raise TypeError("Argument `scale_noise` must be callable.") if num_to_average < 1: raise ValueError("Argument `num_to_average` must be a positive int.") return factory.run(circuit, executor, observable, scale_noise, int(num_to_average)).reduce()
def execute_with_zne( circuit: QPROGRAM, executor: Union[Executor, Callable[[QPROGRAM], QuantumResult]], observable: Optional[Observable] = None, *, factory: Optional[Factory] = None, scale_noise: Callable[[QPROGRAM, float], QPROGRAM] = fold_gates_at_random, num_to_average: int = 1, ) -> float: """Returns the zero-noise extrapolated expectation value that is computed by running the quantum program `qp` with the executor function. Args: circuit: Quantum program to execute with error mitigation. executor: A ``mitiq.Executor`` or a function which inputs a (list of) quantum circuits and outputs a (list of) ``mitiq.QuantumResult`` s. observable: Observable to compute the expectation value of. If None, the `executor` must return an expectation value. Otherwise, the `QuantumResult` returned by `executor` is used to compute the expectation of the observable. factory: Factory object that determines the zero-noise extrapolation method. scale_noise: Function for scaling the noise of a quantum circuit. num_to_average: Number of times expectation values are computed by the executor after each call to scale_noise, then averaged. """ if not factory: factory = RichardsonFactory(scale_factors=[1.0, 2.0, 3.0]) if not isinstance(factory, Factory): raise TypeError( f"Argument `factory` must be of type mitiq.factories.Factory " f"but type(factory) is {type(factory)}." ) if not callable(scale_noise): raise TypeError("Argument `scale_noise` must be callable.") if num_to_average < 1: raise ValueError("Argument `num_to_average` must be a positive int.") return factory.run( circuit, executor, observable, scale_noise, int(num_to_average) ).reduce()
def test_execute_with_zne_with_supported_circuits(circuit_type): # Define a circuit equivalent to the identity qreg = cirq.LineQubit.range(2) cirq_circuit = cirq.Circuit( cirq.H.on_each(qreg), cirq.CNOT(*qreg), cirq.CNOT(*qreg), cirq.H.on_each(qreg), ) # Convert to one of the supported program types circuit = convert_from_mitiq(cirq_circuit, circuit_type) expected = generic_executor(circuit, noise_level=0.0) unmitigated = generic_executor(circuit) # Use odd scale factors for deterministic results fac = RichardsonFactory([1.0, 3.0, 5.0]) zne_value = execute_with_zne(circuit, generic_executor, factory=fac) # Test zero noise limit is better than unmitigated expectation value assert abs(unmitigated - expected) > abs(zne_value - expected)
def test_mitigate_executor_with_shot_list(): """Tests the mitigation of an executor using different shots for each noise scale factor. """ rand_circ = random_one_qubit_identity_circuit(num_cliffords=TEST_DEPTH) qp = measure(rand_circ, qid=0) fac = RichardsonFactory( [1.0, 2.0, 3.0], shot_list=[10 ** 4, 10 ** 5, 10 ** 6] ) new_executor = mitigate_executor( basic_executor, scale_noise=scale_noise, factory=fac ) # bad_result is computed with native noise (scale = 1) bad_result = basic_executor(scale_noise(qp, 1)) good_result = new_executor(qp) assert not np.isclose(bad_result, 1.0, atol=1.0e-1) assert np.isclose(good_result, 1.0, atol=1.0e-1) assert fac._instack[0] == {"scale_factor": 1.0, "shots": 10 ** 4} assert fac._instack[1] == {"scale_factor": 2.0, "shots": 10 ** 5} assert fac._instack[2] == {"scale_factor": 3.0, "shots": 10 ** 6}
fold_global, ) from mitiq.benchmarks.utils import noisy_simulation from mitiq.zne import mitigate_executor SCALE_FUNCTIONS = [ fold_gates_at_random, fold_gates_from_left, fold_gates_from_right, fold_global, ] FACTORIES = [ AdaExpFactory(steps=3, scale_factor=1.5, asymptote=0.25), ExpFactory([1.0, 1.4, 2.1], asymptote=0.25), RichardsonFactory([1.0, 1.4, 2.1]), LinearFactory([1.0, 1.6]), PolyFactory([1.0, 1.4, 2.1], order=2), ] def test_rb_circuits(): depths = range(2, 10, 2) # test single qubit RB for trials in [2, 3]: circuits = rb_circuits(n_qubits=1, num_cliffords=depths, trials=trials) for qc in circuits: # we check the ground state population to ignore any global phase wvf = qc.final_wavefunction() zero_prob = abs(wvf[0]**2)