Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add sampling for qubit_mixed module #6639

Merged
merged 55 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
a58d6e7
add measure
JerryChen97 Nov 26, 2024
8b67a6a
Init this branch
JerryChen97 Nov 26, 2024
ac8ecd2
add import
JerryChen97 Nov 26, 2024
8ba948d
add coverage and stop pylint from crime
JerryChen97 Nov 26, 2024
9816727
let's just eazy fix it
JerryChen97 Nov 26, 2024
d752148
Merge branch 'master' into add-qubit_mixed/measure
JerryChen97 Nov 26, 2024
0aa7876
add item to log
JerryChen97 Nov 26, 2024
cfe3aa0
merge changelogs of 6576 and 6564 into one
JerryChen97 Nov 27, 2024
9187533
reuse math.reduce_dm
JerryChen97 Nov 28, 2024
1307961
[skip-ci]
JerryChen97 Nov 28, 2024
a22d65b
Use probsmp process_density_matrix
JerryChen97 Nov 28, 2024
47f4929
Update doc/releases/changelog-dev.md
JerryChen97 Nov 28, 2024
ff09567
Merge branch 'master' into add-qubit_mixed/measure
JerryChen97 Nov 28, 2024
6631cef
import the common method from conftest
JerryChen97 Nov 28, 2024
b430bef
disable pylint
JerryChen97 Nov 28, 2024
38cd7a0
a better solution, also uncomment the mistakenly commented out ones
JerryChen97 Nov 28, 2024
6c4bee7
Merge branch 'master' into add-qubit_mixed/measure
JerryChen97 Nov 28, 2024
23efe08
copy-paste from qutrit with minimal mod
JerryChen97 Nov 28, 2024
e27ac44
Merge branch 'master' into add-qubit_mixed/measure
JerryChen97 Nov 29, 2024
2f52114
Update pennylane/devices/qubit_mixed/measure.py
JerryChen97 Nov 29, 2024
e763a1d
Update pennylane/devices/qubit_mixed/measure.py
JerryChen97 Nov 29, 2024
102b267
Merge branch 'master' into add-qubit_mixed/measure
JerryChen97 Nov 29, 2024
c49a66e
Merge branch 'master' into add-qubit_mixed/measure
JerryChen97 Nov 29, 2024
75c46ee
Init this branch
JerryChen97 Nov 26, 2024
ca1e5c7
copy-paste from qutrit with minimal mod
JerryChen97 Nov 28, 2024
0c75708
Merge branch 'add-qubit_mixed/sampling' of https://github.com/PennyLa…
JerryChen97 Nov 29, 2024
4d23fe5
export to the init
JerryChen97 Nov 29, 2024
aaf4796
add tests
JerryChen97 Nov 29, 2024
1fd2c5a
add list
JerryChen97 Nov 29, 2024
c8e05d8
fix match issue
JerryChen97 Nov 29, 2024
35c80bb
fix coverage
JerryChen97 Nov 29, 2024
ee7ee2d
silence the formmater
JerryChen97 Nov 29, 2024
6f35a7b
Merge branch 'master' into add-qubit_mixed/sampling
JerryChen97 Dec 2, 2024
74bc094
tr -> b
JerryChen97 Dec 2, 2024
01de04f
fix changelog
JerryChen97 Dec 2, 2024
fe9e329
re-arrange
JerryChen97 Dec 2, 2024
5d90d04
debug a potential bug
JerryChen97 Dec 2, 2024
a3453bc
reuse qubit sample probs
JerryChen97 Dec 2, 2024
1db7078
cancel exporting of sample_probs
JerryChen97 Dec 2, 2024
514fb7c
simplify logics
JerryChen97 Dec 2, 2024
8464658
Update pennylane/devices/qubit_mixed/measure.py
JerryChen97 Dec 3, 2024
a4d4fc1
Update pennylane/devices/qubit_mixed/sampling.py
JerryChen97 Dec 3, 2024
eedc419
Update pennylane/devices/qubit_mixed/sampling.py
JerryChen97 Dec 3, 2024
86398ae
imporve the CountsMP process logic
JerryChen97 Dec 3, 2024
5c08c07
rename the _process_single_shot to _process_single_shot_copy
JerryChen97 Dec 3, 2024
06ac221
Merge branch 'master' into add-qubit_mixed/sampling
JerryChen97 Dec 3, 2024
6cddf64
remove too few shots test
JerryChen97 Dec 3, 2024
ba9d784
Mkae the custom class more consistent with PL [skip-ci]
JerryChen97 Dec 3, 2024
a3c6a78
Merge branch 'master' into add-qubit_mixed/sampling
JerryChen97 Dec 4, 2024
e043f1d
clean up changelgo
JerryChen97 Dec 4, 2024
2772227
cleanup changelog
JerryChen97 Dec 4, 2024
d7577b8
Merge branch 'master' into add-qubit_mixed/sampling
JerryChen97 Dec 4, 2024
be4bdfc
Merge branch 'add-qubit_mixed/sampling' of https://github.com/PennyLa…
JerryChen97 Dec 4, 2024
749d934
Update doc/releases/changelog-dev.md
JerryChen97 Dec 4, 2024
9d66193
Merge branch 'master' into add-qubit_mixed/sampling
JerryChen97 Dec 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,34 @@ added `binary_mapping()` function to map `BoseWord` and `BoseSentence` to qubit
* Added submodule `devices.qubit_mixed.sampling` as a necessary step for the new API, featuring functions `sample_state`, `measure_with_samples` and `sample_probs` for sampling qubits in mixed-state devices.
[(#6639)](https://github.com/PennyLaneAI/pennylane/pull/6639)

* Support is added for `if`/`else` statements and `for` and `while` loops in circuits executed with `qml.capture.enabled`, via `autograph`
[(#6406)](https://github.com/PennyLaneAI/pennylane/pull/6406)
[(#6413)](https://github.com/PennyLaneAI/pennylane/pull/6413)
[(#6426)](https://github.com/PennyLaneAI/pennylane/pull/6426)

* Added `christiansen_mapping()` function to map `BoseWord` and `BoseSentence` to qubit operators, using christiansen mapping.
[(#6623)](https://github.com/PennyLaneAI/pennylane/pull/6623)

* The `qml.qchem.factorize` function now supports new methods for double factorization:
Cholesky decomposition (`cholesky=True`) and compressed double factorization (`compressed=True`).
[(#6573)](https://github.com/PennyLaneAI/pennylane/pull/6573)
[(#6611)](https://github.com/PennyLaneAI/pennylane/pull/6611)

* Added `qml.qchem.symmetry_shift` function to perform the
[block-invariant symmetry shift](https://arxiv.org/pdf/2304.13772) on the electronic integrals.
[(#6574)](https://github.com/PennyLaneAI/pennylane/pull/6574)

* Added submodule for calculating vibrational Hamiltonians
* Implemented helper functions for geometry optimization, harmonic analysis,
and normal-mode localization.
[(#6453)](https://github.com/PennyLaneAI/pennylane/pull/6453)
* Implemented helper functions for calculating one-mode PES, two-mode PES, and
three-mode PES.
[(#6616)](https://github.com/PennyLaneAI/pennylane/pull/6616)
* Implemented wrapper function for vibrational Hamiltonian calculation and dataclass
for storing the data.
[(#6652)](https://github.com/PennyLaneAI/pennylane/pull/6652)

<h3>Improvements 🛠</h3>

* Raises a comprehensive error when using `qml.fourier.qnode_spectrum` with standard numpy
Expand Down
2 changes: 1 addition & 1 deletion pennylane/devices/qubit_mixed/measure.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ def calculate_reduced_density_matrix(
state (TensorLike): state to apply the measurement to.
is_state_batched (bool): whether the state is batched or not.
readout_errors (List[Callable]): List of channels to apply to each wire being measured
to simulate readout errors. These are not applied on this type of measurement.
to simulate readout errors. These are not applied on this type of measurement.

Returns:
TensorLike: state or reduced density matrix.
Expand Down
20 changes: 6 additions & 14 deletions pennylane/devices/qubit_mixed/sampling.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Code relevant for sampling a qubit mixed state.
Submodule for sampling a qubit mixed state.
"""
# pylint: disable=too-many-positional-arguments, too-many-arguments
import functools
Expand Down Expand Up @@ -75,14 +75,6 @@ def _process_samples(
return mp.eigvals()[indices]


def _process_counts_samples(processed_sample, mp_has_obs):
"""Processes a set of samples and counts the results."""
observables, counts = math.unique(processed_sample, return_counts=True, axis=0)
if not mp_has_obs:
observables = ["".join(observable.astype("str")) for observable in observables]
return dict(zip(observables, counts))


def _process_expval_samples(processed_sample):
"""Processes a set of samples and returns the expectation value of an observable."""
eigvals, counts = math.unique(processed_sample, return_counts=True)
Expand Down Expand Up @@ -113,7 +105,7 @@ def _measure_with_samples_diagonalizing_gates(

Args:
mp (~.measurements.SampleMeasurement): The sample measurement to perform
state (np.ndarray[complex]): The state vector to sample from
state (TensorLike): The state vector to sample from
shots (~.measurements.Shots): The number of samples to take
is_state_batched (bool): whether the state is batched or not
rng (Union[None, int, array_like[int], SeedSequence, BitGenerator, Generator]): A
Expand All @@ -133,12 +125,12 @@ def _measure_with_samples_diagonalizing_gates(
total_indices = _get_num_wires(state, is_state_batched)
wires = qml.wires.Wires(range(total_indices))

def _process_single_shot(samples):
def _process_single_shot_copy(samples):
JerryChen97 marked this conversation as resolved.
Show resolved Hide resolved
samples_processed = _process_samples(mp, samples, wires)
if isinstance(mp, SampleMP):
return math.squeeze(samples_processed)
if isinstance(mp, CountsMP):
process_func = functools.partial(_process_counts_samples, mp_has_obs=mp.obs is not None)
process_func = functools.partial(mp.process_samples, wire_order=wires)
elif isinstance(mp, ExpectationMP):
process_func = _process_expval_samples
elif isinstance(mp, VarianceMP):
mudit2812 marked this conversation as resolved.
Show resolved Hide resolved
Expand Down Expand Up @@ -169,7 +161,7 @@ def _process_single_shot(samples):
prng_key=prng_key,
readout_errors=readout_errors,
)
processed_samples.append(_process_single_shot(samples))
processed_samples.append(_process_single_shot_copy(samples))

return tuple(processed_samples)

Expand All @@ -183,7 +175,7 @@ def _process_single_shot(samples):
readout_errors=readout_errors,
)

return _process_single_shot(samples)
return _process_single_shot_copy(samples)


def _measure_sum_with_samples(
Expand Down
38 changes: 31 additions & 7 deletions tests/devices/qubit_mixed/test_qubit_mixed_sampling.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ def test_entangled_states(self, state_vector, expected_ratio):
ratio, expected_ratio, atol=APPROX_ATOL
), f"Ratio {ratio} deviates from expected {expected_ratio}"

@pytest.mark.parametrize("num_shots", [10, 100, 1000])
@pytest.mark.parametrize("num_shots", [100, 1000])
@pytest.mark.parametrize("seed", [42, 123, 987])
def test_reproducibility(self, num_shots, seed, two_qubit_pure_state):
"""Test reproducibility with different shots and seeds."""
Expand All @@ -153,7 +153,7 @@ def test_reproducibility(self, num_shots, seed, two_qubit_pure_state):
samples2 = sample_state(two_qubit_pure_state, num_shots, rng=rng2)
assert np.array_equal(samples1, samples2), "Samples with the same seed are not equal"

@pytest.mark.parametrize("num_shots", [10, 100, 1000])
@pytest.mark.parametrize("num_shots", [100, 1000])
@pytest.mark.parametrize("seed1, seed2", [(42, 43), (123, 124), (987, 988)])
def test_different_seeds_produce_different_samples(
self, num_shots, seed1, seed2, two_qubit_pure_state
Expand Down Expand Up @@ -182,10 +182,10 @@ def test_measure_with_samples_not_implemented_error(self):
class CustomSampleMeasurement(SampleMeasurement):
"""A custom measurement process for testing."""

def process_counts(self, counts):
def process_counts(self, counts, wire_order=None):
return counts

def process_samples(self, samples, wire_orders=None):
def process_samples(self, samples, wire_order=None, shot_range=None, bin_size=None):
return samples

# Prepare a simple state
Expand All @@ -200,7 +200,7 @@ def process_samples(self, samples, wire_orders=None):
class TestMeasurements:
"""Test different measurement types"""

@pytest.mark.parametrize("num_shots", [10, 100, 1000])
@pytest.mark.parametrize("num_shots", [100, 1000])
@pytest.mark.parametrize("wires", [(0,), (1,), (0, 1)])
def test_sample_measurement(self, num_shots, wires, two_qubit_pure_state):
"""Test sample measurements with different shots and wire configurations."""
Expand Down Expand Up @@ -231,6 +231,30 @@ def test_counts_measurement(self, num_shots, two_qubit_pure_state):
valid_states
), f"Invalid states in counts: {result.keys()}"

@pytest.mark.parametrize("num_shots", [100, 500])
def test_counts_measurement_all_outcomes(self, num_shots, two_qubit_pure_state):
"""Test counts measurement with all_outcomes=True."""
shots = Shots(num_shots)
result = measure_with_samples(qml.counts(all_outcomes=True), two_qubit_pure_state, shots)

assert isinstance(result, dict), "Result is not a dictionary"
total_counts = sum(result.values())
assert (
total_counts == num_shots
), f"Total counts {total_counts} do not match shots {num_shots}"

# Check that all possible 2-qubit states are present in the keys
all_possible_states = {"00", "01", "10", "11"}
assert (
set(result.keys()) == all_possible_states
), f"Missing states in counts: {all_possible_states - set(result.keys())}"

# Check that only '01', '10', '11' have non-zero counts (based on two_qubit_pure_state fixture)
assert result["00"] == 0, "State '00' should have zero counts"
assert (
sum(result[state] > 0 for state in ["01", "10", "11"]) == 3
), "Expected non-zero counts for '01', '10', and '11'"

@pytest.mark.parametrize(
"observable",
[
Expand All @@ -247,7 +271,7 @@ def test_observable_measurements(self, observable, measurement, two_qubit_pure_s
shots = Shots(10000)
result = measure_with_samples(measurement(observable), two_qubit_pure_state, shots)
assert isinstance(result, (float, np.floating)), "Result is not a floating point number"
if measurement == qml.expval:
if measurement is qml.expval:
assert -1 <= result <= 1, f"Expectation value {result} out of bounds"
else:
assert 0 <= result <= 1, f"Variance {result} out of bounds"
Expand Down Expand Up @@ -314,7 +338,7 @@ def test_measure_sum_with_samples_partitioned_shots(self):
class TestBatchedOperations:
"""Test batched state handling"""

@pytest.mark.parametrize("num_shots", [10, 100])
@pytest.mark.parametrize("num_shots", [100, 500])
@pytest.mark.parametrize("batch_size", [2, 3, 4])
def test_batched_sampling(self, num_shots, batch_size):
"""Test sampling with different batch sizes."""
Expand Down
Loading