Skip to content

Commit

Permalink
Integration with qiskit-symb (#313)
Browse files Browse the repository at this point in the history
* add support for qiskit-symb

* temp fix (as per Simone suggestion)

* fix feature map

* solution with threads

* working solution with a dumping statevector

* add param_prefix to gen_x_featuremap

* param prefix for all feature maps

* clean SymFidelityStatevectorKernel

* add documentation

* add some common feature maps

* [pre-commit.ci] auto fixes from pre-commit.com hooks

* edge case for pegasos implementation

* flake8

* fix typo

* add qiskit-symb as an optional dependency

* fix no bare exception

* [pre-commit.ci] auto fixes from pre-commit.com hooks

* Update deploy_ghpages.yml

copy cached feature maps to examples at runtime

* Update pyriemann_qiskit/utils/hyper_params_factory.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Update pyriemann_qiskit/utils/hyper_params_factory.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* [pre-commit.ci] auto fixes from pre-commit.com hooks

* Update pyriemann_qiskit/utils/quantum_provider.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Update pyriemann_qiskit/utils/quantum_provider.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* Update pyriemann_qiskit/utils/hyper_params_factory.py

Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>

* [pre-commit.ci] auto fixes from pre-commit.com hooks

* correct workflow file

* tentative to fix error in workflow
(features map not found)

* fix workflow: wrong directory

* simplify workflow file

* revert changes to workflow back.
Correct syntax of cp command

* create missing cache `symb_statevectors` inside doc

* second version (not passed as a prebuilt command)

* add debug trace

* joblib result assignation read-only when started from within another job.
Disabling multhithreading for one of the moabb example

* simplify workflow

* disable multithreading for financial data too

* [pre-commit.ci] auto fixes from pre-commit.com hooks

* fix version of symengine for serialization

* improve simulation time for plot_financial_data

* Missing flag to deactivate qiskit_symb

* [pre-commit.ci] auto fixes from pre-commit.com hooks

---------

Co-authored-by: Gregoire Cattan <gregoire.cattan@ibm.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Quentin Barthélemy <q.barthelemy@gmail.com>
  • Loading branch information
4 people authored Oct 1, 2024
1 parent b6268c7 commit 94ed524
Show file tree
Hide file tree
Showing 16 changed files with 262 additions and 37 deletions.
7 changes: 6 additions & 1 deletion .github/workflows/deploy_ghpages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ jobs:
with:
path: ~/.cache/pip
key: deploy_ghpages.yml
- name: Copy feature maps
run: |
cp -a ./symb_statevectors/. ./examples/ERP/symb_statevectors
cp -a ./symb_statevectors/. ./examples/MI/symb_statevectors
cp -a ./symb_statevectors/. ./examples/other_datasets/symb_statevectors
cp -a ./symb_statevectors/. ./examples/toys_dataset/symb_statevectors
- name: Generate HTML docs
env:
FIREBASE_CERTIFICATE: ${{ secrets.FIREBASE_CERTIFICATE }}
Expand All @@ -33,7 +39,6 @@ jobs:
python -m pip install --upgrade pip
apt-get -y install --fix-missing git-core
apt-get -y install build-essential
pip install -r doc/requirements.txt
- name: Upload generated HTML as artifact
uses: actions/upload-artifact@v4
with:
Expand Down
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,12 +123,21 @@ To check the installation, open a python shell and type:
import pyriemann_qiskit
```

To enable Qiskit GPU optimization when using quantum simulation, run:
To enable Qiskit GPU optimization (for Linux) when using quantum simulation, run:

```
pip install .[optim_linux]
```

To use symbolic quantum simulation, run:

```
pip install .[optim]
```

Which will enable [qiskit-symb](https://github.com/SimoneGasperini/qiskit-symb)
integration.

Note, Qiskit only provide binaries for Linux. For other platforms, or if you want to
enable specific NVIDIA optimization for quantum, you need to build the binary
[yourself](https://github.com/Qiskit/qiskit-aer/blob/main/CONTRIBUTING.md#building-with-gpu-support).
Expand Down
2 changes: 2 additions & 0 deletions doc/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,5 @@ moabb==1.1.0
pyriemann==0.6
docplex>=2.21.207
firebase_admin==6.5.0
qiskit-symb
symengine==0.11.0
5 changes: 4 additions & 1 deletion examples/ERP/plot_classify_P300_bi.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,10 @@
# the non-qunatum SVM version used in qiskit
# On a real Quantum computer (n_components = qubits)
dim_red=PCA(n_components=5),
# params={'q_account_token': '<IBM Quantum TOKEN>'}
params={
"n_jobs": 1, # Number of jobs for the simulator
# 'q_account_token': '<IBM Quantum TOKEN>'
},
)

# Here we provide a pipeline for comparison:
Expand Down
11 changes: 10 additions & 1 deletion examples/other_datasets/plot_financial_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
from sklearn.metrics import balanced_accuracy_score

from pyriemann_qiskit.classification import QuanticSVM
from pyriemann_qiskit.utils.hyper_params_factory import gen_zz_feature_map
from pyriemann_qiskit.utils.preprocessing import NdRobustScaler

print(__doc__)
Expand Down Expand Up @@ -370,7 +371,15 @@ def transform(self, X):
# for the quantum SVM as for the classical one.
gs.best_estimator_.steps[-1] = (
"quanticsvm",
QuanticSVM(quantum=True, C=best_C, gamma=best_gamma, seed=42),
QuanticSVM(
quantum=True,
C=best_C,
gamma=best_gamma,
gen_feature_map=gen_zz_feature_map(),
seed=42,
n_jobs=1,
use_qiskit_symb=False,
),
)
train_pred_qsvm = gs.best_estimator_.fit(X_train, y_train).predict(X_train)
train_score_qsvm = balanced_accuracy_score(y_train, train_pred_qsvm)
Expand Down
25 changes: 21 additions & 4 deletions pyriemann_qiskit/classification.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class QuanticClassifierBase(BaseEstimator, ClassifierMixin):
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, QuantumCircuit | FeatureMap], \
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
Expand Down Expand Up @@ -328,6 +328,9 @@ class QuanticSVM(QuanticClassifierBase):
Predict is now using predict_proba with a softmax, when using QSVC.
.. versionchanged:: 0.3.0
Add use_fidelity_state_vector_kernel parameter
.. versionchanged:: 0.4.0
Add n_jobs and use_qiskit_symb parameter
for SymbFidelityStatevectorKernel
Parameters
----------
Expand Down Expand Up @@ -359,17 +362,24 @@ class QuanticSVM(QuanticClassifierBase):
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, QuantumCircuit | FeatureMap], \
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
use_fidelity_state_vector_kernel: boolean (default=True)
use_fidelity_state_vector_kernel: boolean, default=True
if True, use a FidelitystatevectorKernel for simulation.
use_qiskit_symb: boolean, default=True
This flag is used only if qiskit-symb is installed, and pegasos is False.
If True and the number of qubits < 9, then qiskit_symb is used.
n_jobs: boolean
The number of jobs for the qiskit-symb fidelity state vector
(if applicable)
See Also
--------
QuanticClassifierBase
SymbFidelityStatevectorKernel
References
----------
Expand Down Expand Up @@ -407,6 +417,8 @@ def __init__(
gen_feature_map=gen_zz_feature_map(),
seed=None,
use_fidelity_state_vector_kernel=True,
use_qiskit_symb=True,
n_jobs=4,
):
QuanticClassifierBase.__init__(
self, quantum, q_account_token, verbose, shots, gen_feature_map, seed
Expand All @@ -416,14 +428,19 @@ def __init__(
self.max_iter = max_iter
self.pegasos = pegasos
self.use_fidelity_state_vector_kernel = use_fidelity_state_vector_kernel
self.n_jobs = n_jobs
self.use_qiskit_symb = use_qiskit_symb

def _init_algo(self, n_features):
self._log("SVM initiating algorithm")
if self.quantum:
quantum_kernel = get_quantum_kernel(
self._feature_map,
self.gen_feature_map,
self._quantum_instance,
self.use_fidelity_state_vector_kernel,
self.use_qiskit_symb and not self.pegasos,
self.n_jobs,
)
if self.pegasos:
self._log("[Warning] `gamma` is not supported by PegasosQSVC")
Expand Down Expand Up @@ -498,7 +515,7 @@ class QuanticVQC(QuanticClassifierBase):
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, QuantumCircuit | FeatureMap], \
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
Expand Down
2 changes: 1 addition & 1 deletion pyriemann_qiskit/pipelines.py
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ class QuantumMDMVotingClassifier(BasePipeline):
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, QuantumCircuit | FeatureMap] \
gen_feature_map : Callable[[int, str], QuantumCircuit | FeatureMap] \
(default : Callable[int, ZZFeatureMap])
Function generating a feature map to encode data into a quantum state.
Expand Down
47 changes: 36 additions & 11 deletions pyriemann_qiskit/utils/hyper_params_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,12 @@ def gen_x_feature_map(reps=2):
Returns
-------
ret : XFeatureMap
An instance of XFeatureMap.
ret : Callable[[int, str], XFeatureMap]
A callable that takes into arguments:
- the number of features
- the prefix string for the parameters
And returns an instance of XFeatureMap.
Raises
------
Expand All @@ -40,16 +44,18 @@ def gen_x_feature_map(reps=2):
Notes
-----
.. versionadded:: 0.2.0
.. versionchanged:: 0.4.0
Possibility to specify parameter prefix.
"""
if reps < 1:
raise ValueError(f"Parameter reps must be superior or equal to 1 (Got {reps})")

return lambda n_features: PauliFeatureMap(
return lambda n_features, param_prefix="x": PauliFeatureMap(
feature_dimension=n_features,
paulis=["X"],
reps=reps,
data_map_func=None,
parameter_prefix="x",
parameter_prefix=param_prefix,
insert_barriers=False,
name="XFeatureMap",
)
Expand All @@ -69,8 +75,12 @@ def gen_z_feature_map(reps=2):
Returns
-------
ret : ZFeatureMap
An instance of ZFeatureMap.
ret : Callable[[int, str], ZFeatureMap]
A callable that takes into arguments:
- the number of features
- the prefix string for the parameters
And returns an instance of ZFeatureMap.
Raises
------
Expand All @@ -85,11 +95,17 @@ def gen_z_feature_map(reps=2):
Notes
-----
.. versionadded:: 0.2.0
.. versionchanged:: 0.4.0
Possibility to specify parameter prefix.
"""
if reps < 1:
raise ValueError(f"Parameter reps must be superior or equal to 1 (Got {reps})")

return lambda n_features: ZFeatureMap(feature_dimension=n_features, reps=reps)
return lambda n_features, param_prefix="x": ZFeatureMap(
feature_dimension=n_features,
reps=reps,
parameter_prefix=param_prefix,
)


def gen_zz_feature_map(reps=2, entanglement="linear"):
Expand All @@ -113,8 +129,12 @@ def gen_zz_feature_map(reps=2, entanglement="linear"):
Returns
-------
ret : ZZFeatureMap
An instance of ZZFeatureMap.
ret : Callable[[int, str], ZZFeatureMap]
A callable that takes into arguments:
- the number of features
- the prefix string for the parameters
And returns an instance of ZZFeatureMap.
Raises
------
Expand All @@ -131,12 +151,17 @@ def gen_zz_feature_map(reps=2, entanglement="linear"):
Notes
-----
.. versionadded:: 0.0.1
.. versionchanged:: 0.4.0
Possibility to specify parameter prefix.
"""
if reps < 1:
raise ValueError(f"Parameter reps must be superior or equal to 1 (Got {reps})")

return lambda n_features: ZZFeatureMap(
feature_dimension=n_features, reps=reps, entanglement=entanglement
return lambda n_features, param_prefix="x": ZZFeatureMap(
feature_dimension=n_features,
reps=reps,
entanglement=entanglement,
parameter_prefix=param_prefix,
)


Expand Down
Loading

0 comments on commit 94ed524

Please sign in to comment.