"""Variational quantum classifier."""
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_machine_learning.algorithms import VQC
from ...utils.hyper_params_factory import gen_two_local, gen_zz_feature_map, get_spsa
from .quantic_classifier_base import QuanticClassifierBase
[docs]
class QuanticVQC(QuanticClassifierBase):
"""Variational quantum classifier
This class implements a variational quantum classifier (VQC).
Note that there is no classical version of this algorithm.
This will always run on a quantum computer (simulated or not).
Parameters
----------
optimizer : Optimizer, default=SPSA
The classical optimizer to use. See [3]_ for details.
gen_var_form : Callable[int, QuantumCircuit | VariationalForm], \
default=Callable[int, TwoLocal]
Function generating a variational form instance.
quantum : bool, default=True
- If true will run on local or remote backend
(depending on q_account_token value).
- If false, will perform classical computing instead.
q_account_token : string | None, default=None
If `quantum` is True and `q_account_token` provided,
the classification task will be running on a IBM quantum backend.
If `load_account` is provided, the classifier will use the previous
token saved with `IBMProvider.save_account()`.
verbose : bool, default=True
If true, will output all intermediate results and logs
shots : int, default=1024
Number of repetitions of each circuit, for sampling
gen_feature_map : Callable[[int, str], QuantumCircuit | FeatureMap], \
default=Callable[int, ZZFeatureMap]
Function generating a feature map to encode data into a quantum state.
seed : int | None, default=None
Random seed for the simulation.
Attributes
----------
evaluated_values_ : list[int]
Training curve values.
Notes
-----
.. versionadded:: 0.0.1
.. versionchanged:: 0.1.0
Fix: copy estimator not keeping base class parameters.
Added support for multi-class classification.
.. versionchanged:: 0.2.0
Add seed parameter
.. versionchanged:: 0.3.0
Add `evaluated_values_` attribute.
.. versionchanged:: 0.6.0
Pass ``pass_manager`` to ``VQC`` for Qiskit 2.x transpilation.
Moved to :mod:`pyriemann_qiskit.classification.wrappers.quantic_vqc`.
See Also
--------
QuanticClassifierBase
Raises
------
ValueError
Raised if ``quantum`` is False
References
----------
.. [1] H. Abraham et al., Qiskit:
An Open-source Framework for Quantum Computing.
Zenodo, 2019. doi: 10.5281/zenodo.2562110.
.. [2] V. Havlíček et al.,
'Supervised learning with quantum-enhanced feature spaces',
Nature, vol. 567, no. 7747, pp. 209–212, Mar. 2019,
doi: 10.1038/s41586-019-0980-2.
.. [3] \
https://qiskit.org/documentation/machine-learning/stubs/qiskit_machine_learning.algorithms.VQC.html
"""
[docs]
def __init__(
self,
optimizer=get_spsa(),
gen_var_form=gen_two_local(),
quantum=True,
q_account_token=None,
verbose=True,
shots=1024,
gen_feature_map=gen_zz_feature_map(),
seed=None,
):
if quantum is False:
raise ValueError(
"VQC can only run on a quantum \
computer or simulator."
)
QuanticClassifierBase.__init__(
self, quantum, q_account_token, verbose, shots, gen_feature_map, seed
)
self.optimizer = optimizer
self.gen_var_form = gen_var_form
def _init_algo(self, n_features):
self._log("VQC training...")
var_form = self.gen_var_form(n_features)
self.evaluated_values_ = []
def _callback(*args):
# qiskit-algorithms >= 0.4.0 with SPSA: (nfev, x, fx, dx, accept)
# earlier / other optimizers: (weights, value)
value = args[2] if len(args) == 5 else args[-1]
self.evaluated_values_.append(value)
pass_manager = None
if hasattr(self, "_quantum_instance") and self._quantum_instance is not None:
pass_manager = generate_preset_pass_manager(
optimization_level=1, backend=self._quantum_instance.backend
)
vqc = VQC(
optimizer=self.optimizer,
feature_map=self._feature_map,
ansatz=var_form,
sampler=self._quantum_instance,
num_qubits=n_features,
callback=_callback,
pass_manager=pass_manager,
)
return vqc
def predict(self, X):
"""Predict class labels for samples in X.
Parameters
----------
X : ndarray, shape (n_samples, n_features)
Test samples.
Returns
-------
y_pred : ndarray, shape (n_samples,)
Predicted class labels.
"""
labels = self._predict(X)
return self._map_indices_to_classes(labels)
@property
def parameter_count(self):
"""Returns the number of parameters inside the variational circuit.
This is determined by the `gen_var_form` attribute of this instance.
Returns
-------
n_params : int
The number of parameters in the variational circuit.
Returns 0 if the instance is not fit yet.
"""
if hasattr(self, "_classifier"):
return len(self._classifier.ansatz.parameters)
self._log("Instance not initialized. Parameter count is 0.")
return 0