From 57399f3a0db2848a285de8249b70bd9cff3d8044 Mon Sep 17 00:00:00 2001 From: DanPuzzuoli Date: Wed, 5 Jul 2023 12:21:10 -0700 Subject: [PATCH 1/4] modifying DynamicsBackend sampling routine to include the option to normalize the probabilities --- qiskit_dynamics/backend/backend_utils.py | 9 ++++++++- qiskit_dynamics/backend/dynamics_backend.py | 10 +++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/qiskit_dynamics/backend/backend_utils.py b/qiskit_dynamics/backend/backend_utils.py index 1c6f1a39b..444204a30 100644 --- a/qiskit_dynamics/backend/backend_utils.py +++ b/qiskit_dynamics/backend/backend_utils.py @@ -146,7 +146,7 @@ def _get_memory_slot_probabilities( def _sample_probability_dict( - probability_dict: Dict, shots: int, seed: Optional[int] = None + probability_dict: Dict, shots: int, normalize_probabilities: bool = True, seed: Optional[int] = None, ) -> List[str]: """Sample outcomes based on probability dictionary. @@ -154,6 +154,8 @@ def _sample_probability_dict( probability_dict: Dictionary representing probability distribution, with keys being outcomes, values being probabilities. shots: Number of shots. + normalize_probabilities: Whether or not to normalize the probabilities to sum to 1 before + sampling. seed: Seed to use in rng construction. Return: @@ -161,6 +163,11 @@ def _sample_probability_dict( """ rng = np.random.default_rng(seed=seed) alphabet, probs = zip(*probability_dict.items()) + + if normalize_probabilities: + probs = np.array(probs) + probs = probs / probs.sum() + return rng.choice(alphabet, size=shots, replace=True, p=probs) diff --git a/qiskit_dynamics/backend/dynamics_backend.py b/qiskit_dynamics/backend/dynamics_backend.py index 02e4d1603..5e2ef78b8 100644 --- a/qiskit_dynamics/backend/dynamics_backend.py +++ b/qiskit_dynamics/backend/dynamics_backend.py @@ -118,9 +118,9 @@ class DynamicsBackend(BackendV2): indicating that the ground state for the system Hamiltonian should be used, or an arbitrary ``Statevector`` or ``DensityMatrix``. Defaults to ``"ground_state"``. * ``normalize_states``: Boolean indicating whether to normalize states before computing outcome - probabilities. Defaults to ``True``. Setting to ``False`` can result in errors if the solution - tolerance results in probabilities with significant numerical deviation from a proper - probability distribution. + probabilities, and normalize probablities before sampling. Defaults to ``True``. Setting to + ``False`` can result in errors if the solution tolerance results in probabilities with + significant numerical deviation from a proper probability distribution. * ``meas_level``: Form of measurement output. Supported values are ``1`` and ``2``. ``1`` returns IQ points and ``2`` returns counts. Defaults to ``meas_level == 2``. * ``meas_return``: Level of measurement data to return. For ``meas_level = 1`` ``"single"`` @@ -785,7 +785,7 @@ def default_experiment_result_function( yf = solver_result.y[-1] tf = solver_result.t[-1] - + print(yf.trace()) # Take state out of frame, put in dressed basis, and normalize if isinstance(yf, Statevector): yf = np.array(backend.options.solver.model.rotating_frame.state_out_of_frame(t=tf, y=yf)) @@ -819,7 +819,7 @@ def default_experiment_result_function( # sample memory_samples = _sample_probability_dict( - memory_slot_probabilities, shots=backend.options.shots, seed=seed + memory_slot_probabilities, shots=backend.options.shots, normalize_probabilities=backend.options.normalize_states, seed=seed ) counts = _get_counts_from_samples(memory_samples) From 301f1b0feaf41174f6d98366849a8016828f6347 Mon Sep 17 00:00:00 2001 From: DanPuzzuoli Date: Wed, 5 Jul 2023 12:24:24 -0700 Subject: [PATCH 2/4] linting --- qiskit_dynamics/backend/backend_utils.py | 5 ++++- qiskit_dynamics/backend/dynamics_backend.py | 7 +++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/qiskit_dynamics/backend/backend_utils.py b/qiskit_dynamics/backend/backend_utils.py index 444204a30..95ccbab16 100644 --- a/qiskit_dynamics/backend/backend_utils.py +++ b/qiskit_dynamics/backend/backend_utils.py @@ -146,7 +146,10 @@ def _get_memory_slot_probabilities( def _sample_probability_dict( - probability_dict: Dict, shots: int, normalize_probabilities: bool = True, seed: Optional[int] = None, + probability_dict: Dict, + shots: int, + normalize_probabilities: bool = True, + seed: Optional[int] = None, ) -> List[str]: """Sample outcomes based on probability dictionary. diff --git a/qiskit_dynamics/backend/dynamics_backend.py b/qiskit_dynamics/backend/dynamics_backend.py index 5e2ef78b8..d685a0871 100644 --- a/qiskit_dynamics/backend/dynamics_backend.py +++ b/qiskit_dynamics/backend/dynamics_backend.py @@ -118,7 +118,7 @@ class DynamicsBackend(BackendV2): indicating that the ground state for the system Hamiltonian should be used, or an arbitrary ``Statevector`` or ``DensityMatrix``. Defaults to ``"ground_state"``. * ``normalize_states``: Boolean indicating whether to normalize states before computing outcome - probabilities, and normalize probablities before sampling. Defaults to ``True``. Setting to + probabilities, and normalize probablities before sampling. Defaults to ``True``. Setting to ``False`` can result in errors if the solution tolerance results in probabilities with significant numerical deviation from a proper probability distribution. * ``meas_level``: Form of measurement output. Supported values are ``1`` and ``2``. ``1`` @@ -819,7 +819,10 @@ def default_experiment_result_function( # sample memory_samples = _sample_probability_dict( - memory_slot_probabilities, shots=backend.options.shots, normalize_probabilities=backend.options.normalize_states, seed=seed + memory_slot_probabilities, + shots=backend.options.shots, + normalize_probabilities=backend.options.normalize_states, + seed=seed, ) counts = _get_counts_from_samples(memory_samples) From e379c1188ab704169753ce7d2f5d548c1ef528ca Mon Sep 17 00:00:00 2001 From: DanPuzzuoli Date: Wed, 5 Jul 2023 12:27:18 -0700 Subject: [PATCH 3/4] adding release note --- .../notes/normalize-probabilities-d729245bb3fe5f10.yaml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 releasenotes/notes/normalize-probabilities-d729245bb3fe5f10.yaml diff --git a/releasenotes/notes/normalize-probabilities-d729245bb3fe5f10.yaml b/releasenotes/notes/normalize-probabilities-d729245bb3fe5f10.yaml new file mode 100644 index 000000000..568d77eaf --- /dev/null +++ b/releasenotes/notes/normalize-probabilities-d729245bb3fe5f10.yaml @@ -0,0 +1,5 @@ +--- +fixes: + - | + ``DynamicsBackend.options.normalize_states`` now also controls whether or not the probability + distribution over outcomes is normalized before sampling outcomes. From c6cbeedf8ed7e86f8cbbecdd1c51b5fc9fc0a48b Mon Sep 17 00:00:00 2001 From: DanPuzzuoli Date: Thu, 6 Jul 2023 07:34:04 -0700 Subject: [PATCH 4/4] removing spurious print statement --- qiskit_dynamics/backend/dynamics_backend.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_dynamics/backend/dynamics_backend.py b/qiskit_dynamics/backend/dynamics_backend.py index d685a0871..7fea3611c 100644 --- a/qiskit_dynamics/backend/dynamics_backend.py +++ b/qiskit_dynamics/backend/dynamics_backend.py @@ -785,7 +785,7 @@ def default_experiment_result_function( yf = solver_result.y[-1] tf = solver_result.t[-1] - print(yf.trace()) + # Take state out of frame, put in dressed basis, and normalize if isinstance(yf, Statevector): yf = np.array(backend.options.solver.model.rotating_frame.state_out_of_frame(t=tf, y=yf))