Skip to content

Commit

Permalink
Bugfix for Qiskit 1.x register name ambiguity
Browse files Browse the repository at this point in the history
  • Loading branch information
OkuyanBoga committed Dec 6, 2024
1 parent e03415e commit 0593805
Show file tree
Hide file tree
Showing 10 changed files with 77 additions and 144 deletions.
10 changes: 0 additions & 10 deletions docs/_templates/autosummary/base.rst

This file was deleted.

41 changes: 0 additions & 41 deletions docs/_templates/autosummary/class.rst

This file was deleted.

45 changes: 0 additions & 45 deletions docs/_templates/autosummary/class_no_inherited_members.rst

This file was deleted.

41 changes: 0 additions & 41 deletions docs/_templates/autosummary/module.rst

This file was deleted.

16 changes: 16 additions & 0 deletions docs/migration/02_migration_guide_0.8.rst
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,22 @@ Always add measurements before transpilation:
qc.measure_all()
pass_manager.run(qc)
- 🔪 Dynamic Attribute Naming in Qiskit v1.x:

In the latest version of Qiskit (v1.x), the dynamic naming of attributes based on the
classical register's name introduces potential bugs.
Please use `meas` or `c` for your register names to avoid any issues for SamplerV2.

.. code:: ipython3
# for measue_all():
dist = result[0].data.meas.get_counts()
.. code:: ipython3
# for cbit:
dist = result[0].data.c.get_counts()
- 🔪 Adapting observables for transpiled circuits:

.. code:: ipython3
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,11 @@ def _run_unique(
elif isinstance(self._sampler, BaseSamplerV2):
result = []
for x in range(partial_sum_n, partial_sum_n + n):
bitstring_counts = results[x].data.meas.get_counts()
if hasattr(result[x].data, "meas"):
bitstring_counts = result[x].data.meas.get_counts()
else:
# Fallback to 'c' if 'meas' is not available.
bitstring_counts = result[x].data.c.get_counts()

# Normalize the counts to probabilities
total_shots = sum(bitstring_counts.values())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,11 @@ def _run_unique(
elif isinstance(self._sampler, BaseSamplerV2):
result = []
for i in range(partial_sum_n, partial_sum_n + n):
bitstring_counts = results[i].data.meas.get_counts()

if hasattr(result[i].data, "meas"):
bitstring_counts = result[i].data.meas.get_counts()
else:
# Fallback to 'c' if 'meas' is not available.
bitstring_counts = result[i].data.c.get_counts()
# Normalize the counts to probabilities
total_shots = sum(bitstring_counts.values())
probabilities = {k: v / total_shots for k, v in bitstring_counts.items()}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,11 @@ def _run(
elif isinstance(self._sampler, BaseSamplerV2):
_result = []
for m in range(partial_sum_n, partial_sum_n + n):
_bitstring_counts = results[m].data.meas.get_counts()
if hasattr(result[i].data, "meas"):
_bitstring_counts = result[m].data.meas.get_counts()
else:
# Fallback to 'c' if 'meas' is not available.
_bitstring_counts = result[m].data.c.get_counts()
# Normalize the counts to probabilities
_total_shots = sum(_bitstring_counts.values())
_probabilities = {k: v / _total_shots for k, v in _bitstring_counts.items()}
Expand Down
7 changes: 5 additions & 2 deletions qiskit_machine_learning/neural_networks/sampler_qnn.py
Original file line number Diff line number Diff line change
Expand Up @@ -346,8 +346,11 @@ def _postprocess(self, num_samples: int, result: SamplerResult) -> np.ndarray |
counts = result.quasi_dists[i]

elif isinstance(self.sampler, BaseSamplerV2):
bitstring_counts = result[i].data.meas.get_counts()

if hasattr(result[i].data, "meas"):
bitstring_counts = result[i].data.meas.get_counts()
else:
# Fallback to 'c' if 'meas' is not available.
bitstring_counts = result[i].data.c.get_counts()
# Normalize the counts to probabilities
total_shots = sum(bitstring_counts.values())
probabilities = {k: v / total_shots for k, v in bitstring_counts.items()}
Expand Down
42 changes: 41 additions & 1 deletion test/algorithms/classifiers/test_vqc.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
OPTIMIZERS = ["cobyla", None]
DATASETS = ["binary", "multiclass", "no_one_hot"]
LOSSES = ["squared_error", "absolute_error", "cross_entropy"]
SAMPLERS = ["samplerv1", "samplerv2"]
SAMPLERS = ["samplerv1"]


@dataclass(frozen=True)
Expand Down Expand Up @@ -150,6 +150,46 @@ def test_VQC(self, num_qubits, f_m, ans, opt, d_s, smplr):

self.assertTrue(np.all(predict == unique_labels, axis=1).any())

def test_VQC_V2(self):
"""
Test VQC with binary and multiclass data using a range of quantum
instances, numbers of qubits, feature maps, and optimizers.
"""
num_qubits = 2
feature_map = self.properties.get("zz_feature_map")
optimizer = self.properties.get("cobyla")
ansatz = self.properties.get("real_amplitudes")
dataset = self.properties.get("binary")
sampler = self.properties.get("samplerv2")

pm = generate_preset_pass_manager(optimization_level=0, backend=self.backend)

unique_labels = np.unique(dataset.y, axis=0)
# we want to have labels as a column array, either 1D or 2D(one hot)
# thus, the assert works with plain and one hot labels
unique_labels = unique_labels.reshape(len(unique_labels), -1)
# the predicted value should be in the labels
num_classes = len(unique_labels)
parity_n_classes = lambda x: "{:b}".format(x).count("1") % num_classes

initial_point = np.array([0.5] * ansatz.num_parameters) if ansatz is not None else None

classifier = VQC(
num_qubits=num_qubits,
feature_map=feature_map,
ansatz=ansatz,
optimizer=optimizer,
initial_point=initial_point,
output_shape=num_classes,
interpret=parity_n_classes,
sampler=sampler,
pass_manager=pm,
)
classifier.fit(dataset.x, dataset.y)
predict = classifier.predict(dataset.x[0, :])

self.assertTrue(np.all(predict == unique_labels, axis=1).any())

def test_VQC_non_parameterized(self):
"""
Test VQC without an optimizer set.
Expand Down

0 comments on commit 0593805

Please sign in to comment.