Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
a32645d
Auto Commit
Siddharthgolecha Aug 6, 2025
58a92c3
Auto Commit tests
Siddharthgolecha Aug 6, 2025
31a48a5
Making lint, style changes with some migration fixes
Siddharthgolecha Aug 7, 2025
6ff8bf9
Merge branch 'main' into migrate-to-2.0
Siddharthgolecha Aug 7, 2025
4b2122c
Merge branch 'main' into migrate-to-2.0
OkuyanBoga Sep 3, 2025
37799be
Fix copyright
edoaltamura Sep 3, 2025
0278edc
Fix copyright
edoaltamura Sep 3, 2025
9683908
Fix copyright
edoaltamura Sep 3, 2025
58edda6
Fix copyright
edoaltamura Sep 3, 2025
6b85ef1
Fix copyright
edoaltamura Sep 3, 2025
0a03287
Fix copyright
edoaltamura Sep 3, 2025
08e15f5
'QuantumCircuit' objects implement '__hash__' deterministically
edoaltamura Sep 3, 2025
34fb82c
Fix lint
edoaltamura Sep 3, 2025
379f3e4
Merge branch 'main' into migrate-to-2.0
OkuyanBoga Sep 3, 2025
5e903ea
Lower scipy version requirement
edoaltamura Sep 3, 2025
b9be5bc
Merge branch 'qiskit-community:main' into migrate-to-2.0
Siddharthgolecha Sep 8, 2025
5449cdd
Relax scipy version
edoaltamura Sep 15, 2025
34d77d9
Fix mypy
edoaltamura Sep 15, 2025
5ae415f
Update `qiskit.primitives.StatevectorSampler`
edoaltamura Sep 15, 2025
4c79bdb
Update `qiskit.primitives.StatevectorSampler`
edoaltamura Sep 15, 2025
92554a5
Fix adjust_num_qubits.py
edoaltamura Sep 15, 2025
460d0bb
Fix mypy and lint
edoaltamura Sep 15, 2025
01c3bc2
Partially update type hinting
edoaltamura Sep 15, 2025
b8125c9
Update copyright and spelling
edoaltamura Sep 15, 2025
2759bb7
Implement circuit hashing.
edoaltamura Oct 6, 2025
4552959
Fix make checks.
edoaltamura Oct 6, 2025
0621e3f
Fix various numerical tests.
edoaltamura Oct 6, 2025
1a20e69
Fix neural networks tests. Options are outstanding.
edoaltamura Oct 6, 2025
aea918c
Fix neural networks tests + CI checks.
edoaltamura Oct 6, 2025
710427b
Fix copyright
edoaltamura Oct 6, 2025
9bb7e10
Fix for samplerv2 related unittests
OkuyanBoga Nov 3, 2025
fa5fa69
Fixed unit tests for SamplerV2
OkuyanBoga Nov 3, 2025
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
10 changes: 9 additions & 1 deletion .pylintdict
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ cerezo
chernoff
choi
chuang
cinds
circ
clbit
clbits
clopper
Expand All @@ -78,7 +80,9 @@ codebase
codec
coeffs
colin
coles
combinatorial
computable
concha
config
configs
Expand Down Expand Up @@ -335,6 +339,7 @@ msg
multiclass
multinomial
multioutput
multipartite
mxd
mypy
nabla
Expand All @@ -357,6 +362,7 @@ nfevs
nft
nielsen
njev
nlocal
nlopt
nn
noancilla
Expand Down Expand Up @@ -450,6 +456,7 @@ qgans
qgt
qgt's
qgts
qinds
qiskit
qiskit's
qn
Expand Down Expand Up @@ -494,6 +501,7 @@ RuntimeError
rx
ry
rz
qpy
samplerqnn
sanjiv
sashank
Expand All @@ -511,7 +519,7 @@ scipy
sdg
seealso
semidefinite
sep
sep
seperate
seperable
serializable
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ The Qiskit Machine Learning framework aims to be:
### Kernel-based methods

The [`FidelityQuantumKernel`](https://qiskit-community.github.io/qiskit-machine-learning/stubs/qiskit_machine_learning.kernels.QuantumKernel.html#qiskit_machine_learning.kernels.FidelityQuantumKernel)
class uses the [`Fidelity`](https://qiskit-community.github.io/qiskit-machine-learning/stubs/qiskit_machine_learning.state_fidelities.BaseStateFidelity.html))
class uses the [`Fidelity`](https://qiskit-community.github.io/qiskit-machine-learning/stubs/qiskit_machine_learning.state_fidelities.BaseStateFidelity.html)
algorithm. It computes kernel matrices for datasets and can be combined with a Quantum Support Vector Classifier ([`QSVC`](https://qiskit-community.github.io/qiskit-machine-learning/stubs/qiskit_machine_learning.algorithms.QSVC.html#qiskit_machine_learning.algorithms.QSVC))
or a Quantum Support Vector Regressor ([`QSVR`](https://qiskit-community.github.io/qiskit-machine-learning/stubs/qiskit_machine_learning.algorithms.QSVR.html#qiskit_machine_learning.algorithms.QSVR))
to solve classification or regression problems respectively. It is also compatible with classical kernel-based machine learning algorithms.
Expand Down
1 change: 1 addition & 0 deletions qiskit_machine_learning/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
kernels
neural_networks
optimizers
primitives
state_fidelities
utils

Expand Down
18 changes: 4 additions & 14 deletions qiskit_machine_learning/algorithm_job.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This code is part of a Qiskit project.
#
# (C) Copyright IBM 2022, 2024.
# (C) Copyright IBM 2022, 2025.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
Expand Down Expand Up @@ -29,17 +29,7 @@ def submit(self) -> None:
"""
Submit the job for execution.

For V1 primitives, Qiskit ``PrimitiveJob`` subclassed JobV1 and defined ``submit()``.
``PrimitiveJob`` was updated for V2 primitives, no longer subclasses ``JobV1``, and
now has a private ``_submit()`` method, with ``submit()`` being deprecated as of
Qiskit version 0.46. This maintains the ``submit()`` for ``AlgorithmJob`` here as
it's called in many places for such a job. An alternative could be to make
0.46 the required minimum version and alter all algorithm's call sites to use
``_submit()`` and make this an empty class again as it once was. For now this
way maintains compatibility with the current min version of 0.44.
Since the library has been migrated to Qiskit v2.1, it is no longer necessary to
keep the :meth:``JobV1.submit()`` for the exception handling.
"""
# TODO: Considering changing this in the future - see above docstring.
try:
super()._submit()
except AttributeError:
super().submit() # pylint: disable=no-member
super()._submit()
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
"""Classifiers Package"""

from .neural_network_classifier import NeuralNetworkClassifier
from .qsvc import QSVC
from .pegasos_qsvc import PegasosQSVC
from .qsvc import QSVC
from .vqc import VQC

__all__ = ["NeuralNetworkClassifier", "QSVC", "PegasosQSVC", "VQC"]
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def __init__(
raise ValueError("'quantum_kernel' has to be None to use a precomputed kernel")
else:
if quantum_kernel is None:
msg = "No quantum kernel is provided, SamplerV1 based quantum kernel will be used."
msg = "No quantum kernel is provided, SamplerV2 based fidelity quantum kernel will be used."
warnings.warn(msg, QiskitMachineLearningWarning, stacklevel=2)
quantum_kernel = FidelityQuantumKernel()

Expand Down
2 changes: 1 addition & 1 deletion qiskit_machine_learning/algorithms/classifiers/qsvc.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def __init__(self, *, quantum_kernel: Optional[BaseKernel] = None, **kwargs):
# if we don't delete, then this value clashes with our quantum kernel
del kwargs["kernel"]
if quantum_kernel is None:
msg = "No quantum kernel is provided, SamplerV1 based quantum kernel will be used."
msg = "No quantum kernel is provided, SamplerV2 based fidelity quantum kernel will be used."
warnings.warn(msg, QiskitMachineLearningWarning, stacklevel=2)
self._quantum_kernel = quantum_kernel if quantum_kernel else FidelityQuantumKernel()

Expand Down
11 changes: 5 additions & 6 deletions qiskit_machine_learning/algorithms/classifiers/vqc.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,18 @@
"""An implementation of variational quantum classifier."""

from __future__ import annotations

from typing import Callable

import numpy as np

from qiskit import QuantumCircuit
from qiskit.primitives import BaseSampler
from qiskit.primitives import BaseSamplerV2
from qiskit.transpiler.passmanager import BasePassManager

from ...neural_networks import SamplerQNN
from ...optimizers import Optimizer, OptimizerResult, Minimizer
from ...optimizers import Minimizer, Optimizer, OptimizerResult
from ...utils import derive_num_qubits_feature_map_ansatz
from ...utils.loss_functions import Loss

from .neural_network_classifier import NeuralNetworkClassifier


Expand Down Expand Up @@ -58,7 +57,7 @@ def __init__(
initial_point: np.ndarray | None = None,
callback: Callable[[np.ndarray, float], None] | None = None,
*,
sampler: BaseSampler | None = None,
sampler: BaseSamplerV2 | None = None, # change: BaseSampler is migrated to BaseSamplerV2
interpret: Callable[[int], int | tuple[int, ...]] | None = None,
output_shape: int | None = None,
pass_manager: BasePassManager | None = None,
Expand Down Expand Up @@ -108,7 +107,7 @@ def __init__(
"""

num_qubits, feature_map, ansatz = derive_num_qubits_feature_map_ansatz(
num_qubits, feature_map, ansatz, use_methods=True
num_qubits, feature_map, ansatz
)

if output_shape is None:
Expand Down
108 changes: 60 additions & 48 deletions qiskit_machine_learning/algorithms/inference/qbayesian.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,19 @@
from __future__ import annotations

import copy
from typing import Tuple, Dict, Set, List
from typing import Dict, Set

from qiskit import QuantumCircuit, ClassicalRegister
from qiskit.quantum_info import Statevector
from qiskit import ClassicalRegister, QuantumCircuit
from qiskit.circuit import Qubit
from qiskit.circuit.library import grover_operator
from qiskit.primitives import BaseSampler, Sampler, BaseSamplerV2, BaseSamplerV1
from qiskit.transpiler.passmanager import BasePassManager
from qiskit.primitives import (
BaseSamplerV2,
# StatevectorSampler as Sampler,
)
from qiskit_machine_learning.primitives import QML_Sampler as Sampler
from qiskit.quantum_info import Statevector
from qiskit.result import QuasiDistribution

from ...utils.deprecation import issue_deprecation_msg
from qiskit.transpiler.passmanager import BasePassManager


class QBayesian:
Expand Down Expand Up @@ -67,7 +69,7 @@ def __init__(
*,
limit: int = 10,
threshold: float = 0.9,
sampler: BaseSampler | BaseSamplerV2 | None = None,
sampler: BaseSamplerV2 | None = None,
pass_manager: BasePassManager | None = None,
):
"""
Expand Down Expand Up @@ -98,14 +100,6 @@ def __init__(
if sampler is None:
sampler = Sampler()

if isinstance(sampler, BaseSamplerV1):
issue_deprecation_msg(
msg="V1 Primitives are deprecated",
version="0.8.0",
remedy="Use V2 primitives for continued compatibility and support.",
period="4 months",
)

self._sampler = sampler

if hasattr(circuit.layout, "_input_qubit_count"):
Expand Down Expand Up @@ -164,43 +158,61 @@ def _get_grover_op(self, evidence: Dict[str, int]) -> QuantumCircuit:
return grover_operator(oracle, state_preparation=self._circ)

def _run_circuit(self, circuit: QuantumCircuit) -> Dict[str, float]:
"""Run the quantum circuit with the sampler."""
counts = {}

if isinstance(self._sampler, BaseSampler):
# Sample from circuit
job = self._sampler.run(circuit)
result = job.result()
"""Run the quantum circuit with the sampler and return P(bitstring) with fixed width."""
if self._pass_manager is not None:
circuit = self._pass_manager.run(circuit)

job = self._sampler.run([circuit])
res = job.result()
pub = res[0]

# Prefer robust, register-agnostic access.
try:
bit_counts = pub.join_data().get_counts()
except Exception:
# Fallback: try first known register if present (e.g., 'meas').
if hasattr(pub, "data") and hasattr(pub.data, "get"):
# pick any available register deterministically
for reg_name in getattr(pub.data, "__dir__", lambda: [])():
try:
bit_counts = getattr(pub.data, reg_name).get_counts()
break
except Exception:
pass
else:
bit_counts = {}
else:
bit_counts = {}

# Get the counts of quantum state results
counts = result.quasi_dists[0].nearest_probability_distribution().binary_probabilities()
total = sum(bit_counts.values())
if total == 0:
return {}

elif isinstance(self._sampler, BaseSamplerV2):
# Sample from circuit
if self._pass_manager is not None:
circuit = self._pass_manager.run(circuit)
job = self._sampler.run([circuit])
result = job.result()
width = circuit.num_clbits # number of measured classical bits in this circuit instance

bit_array = list(result[0].data.values())[0]
bitstring_counts = bit_array.get_counts()
out: Dict[str, float] = {}

# Normalize the counts to probabilities
total_shots = sum(bitstring_counts.values())
probabilities = {k: v / total_shots for k, v in bitstring_counts.items()}
# Convert to quasi-probabilities
quasi_dist = QuasiDistribution(probabilities)
binary_prob = quasi_dist.nearest_probability_distribution().binary_probabilities()
counts = {k: v for k, v in binary_prob.items() if int(k) < 2**self.num_virtual_qubits}
def _to_bin_key(k) -> str:
if isinstance(k, (int,)):
return format(int(k), f"0{width}b")
ks = str(k).replace(" ", "")
if ks.startswith(("0b", "0B")):
return format(int(ks, 2), f"0{width}b")
if ks.startswith(("0x", "0X")):
return format(int(ks, 16), f"0{width}b")
if set(ks) <= {"0", "1"} and len(ks) <= width:
return ks.zfill(width)
# decimal string
return format(int(ks), f"0{width}b")

# counts = QuasiDistribution(probabilities)
# counts = {k: v for k, v in counts.items()}
for k, v in bit_counts.items():
out[_to_bin_key(k)] = out.get(_to_bin_key(k), 0.0) + v / total

return counts
return out

def __power_grover(
self, grover_op: QuantumCircuit, evidence: Dict[str, int], k: int
) -> Tuple[QuantumCircuit, Set[Tuple[Qubit, int]]]:
) -> tuple[QuantumCircuit, Set[tuple[Qubit, int]]]:
"""
Applies the Grover operator to the quantum circuit 2^k times, measures the evidence qubits,
and returns a tuple containing the updated quantum circuit and a set of the measured
Expand Down Expand Up @@ -246,7 +258,7 @@ def __power_grover(
}
return qc, e_meas

def _format_samples(self, samples: Dict[str, float], evidence: List[str]) -> Dict[str, float]:
def _format_samples(self, samples: Dict[str, float], evidence: list[str]) -> Dict[str, float]:
"""Transforms samples keys back to their variables names."""
f_samples: Dict[str, float] = {}
for smpl_key, smpl_val in samples.items():
Expand Down Expand Up @@ -295,7 +307,7 @@ def rejection_sampling(
grover_op = self._get_grover_op(evidence)
# Amplitude amplification
true_e = {(self._label2qubit[e_key], e_val) for e_key, e_val in evidence.items()}
meas_e: Set[Tuple[str, int]] = set()
meas_e: Set[tuple[str, int]] = set()
best_qc, best_inter = QuantumCircuit(), -1
self._converged = False
k = -1
Expand Down Expand Up @@ -412,12 +424,12 @@ def limit(self, limit: int):
self._limit = limit

@property
def sampler(self) -> BaseSampler | BaseSamplerV2:
def sampler(self) -> BaseSamplerV2:
"""Returns the sampler primitive used to compute the samples."""
return self._sampler

@sampler.setter
def sampler(self, sampler: BaseSampler | BaseSamplerV2):
def sampler(self, sampler: BaseSamplerV2):
"""Set the sampler primitive used to compute the samples."""
self._sampler = sampler

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@

"""Regressors Package"""

from .qsvr import QSVR
from .neural_network_regressor import NeuralNetworkRegressor
from .qsvr import QSVR
from .vqr import VQR

__all__ = ["QSVR", "VQR", "NeuralNetworkRegressor"]
2 changes: 1 addition & 1 deletion qiskit_machine_learning/algorithms/regressors/qsvr.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def __init__(self, *, quantum_kernel: Optional[BaseKernel] = None, **kwargs):
# if we don't delete, then this value clashes with our quantum kernel
del kwargs["kernel"]
if quantum_kernel is None:
msg = "No quantum kernel is provided, SamplerV1 based quantum kernel will be used."
msg = "No quantum kernel is provided, SamplerV2 based fidelity quantum kernel will be used."
warnings.warn(msg, QiskitMachineLearningWarning, stacklevel=2)
self._quantum_kernel = quantum_kernel if quantum_kernel else FidelityQuantumKernel()

Expand Down
Loading
Loading