From bfe717fa1a8362d6dfd5b9ba4490f46d6cd584e1 Mon Sep 17 00:00:00 2001 From: "Christopher J. Wood" Date: Tue, 24 Jan 2023 12:12:36 -0500 Subject: [PATCH] Add mitigated tomo tests --- .../tomography/test_process_tomography.py | 59 ++++++++++++++++++- .../tomography/test_state_tomography.py | 57 +++++++++++++++++- test/library/tomography/tomo_utils.py | 14 +++++ 3 files changed, 126 insertions(+), 4 deletions(-) diff --git a/test/library/tomography/test_process_tomography.py b/test/library/tomography/test_process_tomography.py index 2dc3117524..1b75e44de4 100644 --- a/test/library/tomography/test_process_tomography.py +++ b/test/library/tomography/test_process_tomography.py @@ -22,9 +22,15 @@ import qiskit.quantum_info as qi from qiskit_aer import AerSimulator from qiskit_aer.noise import NoiseModel -from qiskit_experiments.library import ProcessTomography +from qiskit_experiments.library import ProcessTomography, MitigatedProcessTomography from qiskit_experiments.library.tomography import ProcessTomographyAnalysis, basis -from .tomo_utils import FITTERS, filter_results, teleport_circuit, teleport_bell_circuit +from .tomo_utils import ( + FITTERS, + filter_results, + teleport_circuit, + teleport_bell_circuit, + readout_noise_model, +) @ddt.ddt @@ -422,3 +428,52 @@ def test_qpt_amat_pauli_basis(self): self.assertExperimentDone(expdata) fid = expdata.analysis_results("process_fidelity").value self.assertGreater(fid, 0.95) + + @ddt.data((0,), (1,), (2,), (3,), (0, 1), (2, 0), (0, 3)) + def test_mitigated_full_qpt_random_unitary(self, qubits): + """Test QPT experiment""" + seed = 1234 + shots = 5000 + f_threshold = 0.95 + + noise_model = readout_noise_model(4, seed=seed) + backend = AerSimulator(seed_simulator=seed, shots=shots, noise_model=noise_model) + target = qi.random_unitary(2 ** len(qubits), seed=seed) + exp = MitigatedProcessTomography(target, backend=backend) + exp.analysis.set_options(unmitigated_fit=True) + expdata = exp.run(analysis=None) + self.assertExperimentDone(expdata) + + for fitter in FITTERS: + with self.subTest(fitter=fitter, qubits=qubits): + if fitter: + exp.analysis.set_options(fitter=fitter) + fitdata = exp.analysis.run(expdata) + self.assertExperimentDone(fitdata) + # Should be 2 results, mitigated and unmitigated + states = expdata.analysis_results("state") + self.assertEqual(len(states), 2) + + # Check state is density matrix + for state in states: + self.assertTrue( + isinstance(state.value, qi.Choi), + msg=f"{fitter} fitted state is not density matrix for qubits {qubits}", + ) + + # Check fit state fidelity + fids = expdata.analysis_results("process_fidelity") + self.assertEqual(len(fids), 2) + mitfid, nomitfid = fids + # Check mitigation improves fidelity + self.assertTrue( + mitfid.value >= nomitfid.value, + msg="mitigated {} did not improve fidelity for qubits {} ({:.4f} < {:.4f})".format( + fitter, qubits, mitfid.value, nomitfid.value + ), + ) + self.assertGreater( + mitfid.value, + f_threshold, + msg=f"{fitter} fit fidelity is low for qubits {qubits}", + ) diff --git a/test/library/tomography/test_state_tomography.py b/test/library/tomography/test_state_tomography.py index 86c80fc030..67b846011b 100644 --- a/test/library/tomography/test_state_tomography.py +++ b/test/library/tomography/test_state_tomography.py @@ -24,9 +24,15 @@ from qiskit_aer import AerSimulator from qiskit_aer.noise import NoiseModel -from qiskit_experiments.library import StateTomography +from qiskit_experiments.library import StateTomography, MitigatedStateTomography from qiskit_experiments.library.tomography import StateTomographyAnalysis, basis -from .tomo_utils import FITTERS, filter_results, teleport_circuit, teleport_bell_circuit +from .tomo_utils import ( + FITTERS, + filter_results, + teleport_circuit, + teleport_bell_circuit, + readout_noise_model, +) @ddt.ddt @@ -322,3 +328,50 @@ def test_qst_amat_pauli_basis(self): self.assertExperimentDone(expdata) fid = expdata.analysis_results("state_fidelity").value self.assertGreater(fid, 0.95) + + @ddt.data((0,), (1,), (2,), (3,), (0, 1), (2, 0), (0, 3), (0, 3, 1)) + def test_mitigated_full_qst(self, qubits): + """Test QST experiment""" + seed = 1234 + shots = 5000 + f_threshold = 0.95 + + noise_model = readout_noise_model(4, seed=seed) + backend = AerSimulator(seed_simulator=seed, shots=shots, noise_model=noise_model) + target = qi.random_statevector(2 ** len(qubits), seed=seed) + exp = MitigatedStateTomography(target, physical_qubits=qubits, backend=backend) + exp.analysis.set_options(unmitigated_fit=True) + expdata = exp.run(analysis=None) + self.assertExperimentDone(expdata) + + for fitter in FITTERS: + with self.subTest(fitter=fitter, qubits=qubits): + if fitter: + exp.analysis.set_options(fitter=fitter) + fitdata = exp.analysis.run(expdata) + self.assertExperimentDone(fitdata) + # Should be 2 results, mitigated and unmitigated + states = expdata.analysis_results("state") + self.assertEqual(len(states), 2) + for state in states: + self.assertTrue( + isinstance(state.value, qi.DensityMatrix), + msg=f"{fitter} fitted state is not density matrix for qubits {qubits}", + ) + + # Check fit state fidelity + fids = expdata.analysis_results("state_fidelity") + self.assertEqual(len(fids), 2) + mitfid, nomitfid = fids + # Check mitigation improves fidelity + self.assertTrue( + mitfid.value >= nomitfid.value, + msg="mitigated {} did not improve fidelity for qubits {} ({:.4f} < {:.4f})".format( + fitter, qubits, mitfid.value, nomitfid.value + ), + ) + self.assertGreater( + mitfid.value, + f_threshold, + msg=f"{fitter} fit fidelity is low for qubits {qubits}", + ) diff --git a/test/library/tomography/tomo_utils.py b/test/library/tomography/tomo_utils.py index 7cdfc5f892..2a1e75b9ec 100644 --- a/test/library/tomography/tomo_utils.py +++ b/test/library/tomography/tomo_utils.py @@ -13,7 +13,9 @@ """ Common methods for tomography tests """ +import numpy as np from qiskit import QuantumCircuit, ClassicalRegister, QuantumRegister +from qiskit_aer.noise import NoiseModel FITTERS = [ @@ -77,3 +79,15 @@ def teleport_bell_circuit(flatten_creg=True): teleport.z(2).c_if(creg[0], 1) teleport.x(2).c_if(creg[1], 1) return teleport + + +def readout_noise_model(num_qubits, seed=None): + """Generate noise model of random local readout errors""" + rng = np.random.default_rng(seed=seed) + p1g0s = 0.15 * rng.random(num_qubits) + p0g1s = 0.3 * rng.random(num_qubits) + amats = np.stack([[1 - p1g0s, p1g0s], [p0g1s, 1 - p0g1s]]).T + noise_model = NoiseModel() + for i, amat in enumerate(amats): + noise_model.add_readout_error(amat.T, [i]) + return noise_model