Skip to content

Add python 3.13 support #923

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

Merged
merged 1 commit into from
May 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
24 changes: 14 additions & 10 deletions .github/workflows/main.yml
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 2021, 2024.
# (C) Copyright IBM 2021, 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 @@ -112,17 +112,17 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest]
python-version: [3.9, '3.10', 3.11, 3.12]
python-version: [3.9, '3.10', 3.11, 3.12, 3.13]
include:
# macos-latest is an Arm64 image
- os: macos-latest
python-version: 3.9
- os: macos-latest
python-version: 3.12
python-version: 3.13
- os: windows-latest
python-version: 3.9
- os: windows-latest
python-version: 3.12
python-version: 3.13
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
Expand Down Expand Up @@ -184,7 +184,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest]
python-version: [3.9, 3.12]
python-version: [3.9, 3.13]
steps:
- uses: actions/checkout@v4
with:
Expand Down Expand Up @@ -282,28 +282,32 @@ jobs:
with:
name: ubuntu-latest-3.12
path: /tmp/u312
- uses: actions/download-artifact@v4
with:
name: ubuntu-latest-3.13
path: /tmp/u313
- uses: actions/download-artifact@v4
with:
name: macos-latest-3.9
path: /tmp/m39
- uses: actions/download-artifact@v4
with:
name: macos-latest-3.12
path: /tmp/m312
name: macos-latest-3.13
path: /tmp/m313
- uses: actions/download-artifact@v4
with:
name: windows-latest-3.9
path: /tmp/w39
- uses: actions/download-artifact@v4
with:
name: windows-latest-3.12
path: /tmp/w312
name: windows-latest-3.13
path: /tmp/w313
- name: Install Dependencies
run: pip install -U coverage coveralls diff-cover
shell: bash
- name: Combined Deprecation Messages
run: |
sort -f -u /tmp/u39/ml.dep /tmp/u310/ml.dep /tmp/u311/ml.dep /tmp/u312/ml.dep /tmp/m39/ml.dep /tmp/m312/ml.dep /tmp/w39/ml.dep /tmp/w312/ml.dep || true
sort -f -u /tmp/u39/ml.dep /tmp/u310/ml.dep /tmp/u311/ml.dep /tmp/u312/ml.dep /tmp/u313/ml.dep /tmp/m39/ml.dep /tmp/m313/ml.dep /tmp/w39/ml.dep /tmp/w313/ml.dep || true
shell: bash
- name: Coverage combine
run: coverage3 combine /tmp/u39/ml.dat
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
[tool.black]
line-length = 100

target-version = ['py39', 'py310', 'py311', 'py312']
target-version = ['py39', 'py310', 'py311', 'py312', 'py313']

[tool.pylint.main]
extension-pkg-allow-list = [
Expand Down
26 changes: 21 additions & 5 deletions qiskit_machine_learning/optimizers/gradient_descent.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 2021, 2024.
# (C) Copyright IBM 2021, 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 @@ -28,7 +28,7 @@
class GradientDescentState(OptimizerState):
"""State of :class:`~.GradientDescent`.

Dataclass with all the information of an optimizer plus the learning_rate and the stepsize.
Dataclass with all the information of an optimizer plus the learning_rate and the step-size.
"""

stepsize: float | None
Expand All @@ -42,6 +42,22 @@ class GradientDescentState(OptimizerState):

"""

# See parent class for a comment on having custom equals. I needed this
# too as it does not appear to use super by default and without this failed
# the exact same way. Note it does not include learning rate as that field
# is not included in the compare as per the field decorator. The __eq__
# method is supposed to accept any object. If you update the version of
# mypy you're using, it'll print out a note recommending this code
# structure.
def __eq__(self, other: object) -> bool:
if not isinstance(other, GradientDescentState):
# If we return NotImplemented, Python will automatically try
# running other.__eq__(self), in case 'other' knows what to do with
# Person objects.
return NotImplemented

return super().__eq__(other) and self.stepsize == other.stepsize


class GradientDescent(SteppableOptimizer):
r"""The gradient descent minimization routine.
Expand Down Expand Up @@ -88,7 +104,7 @@ def f(x):
"of {result.fun} using {result.nfev} evaluations.")

An example where the learning rate is an iterator and we supply the analytic gradient.
Note how much faster this convergences (i.e. less ``nfev``) compared to the previous
Note how much faster this converges (i.e. less ``nfev``) compared to the previous
example.

.. code-block:: python
Expand Down Expand Up @@ -121,7 +137,7 @@ def grad_f(x):
"of {result.fun} using {result.nfev} evaluations.")


An other example where the evaluation of the function has a chance of failing. The user, with
Another example where the evaluation of the function has a chance of failing. The user, with
specific knowledge about his function can catch this errors and handle them before passing the
result to the optimizer.

Expand Down Expand Up @@ -227,7 +243,7 @@ def state(self, state: GradientDescentState) -> None:
def tol(self) -> float:
"""Returns the tolerance of the optimizer.

Any step with smaller stepsize than this value will stop the optimization."""
Any step with smaller step-size than this value will stop the optimization."""
return self._tol

@tol.setter
Expand Down
35 changes: 32 additions & 3 deletions qiskit_machine_learning/optimizers/steppable_optimizer.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 @@ -73,6 +73,35 @@ class OptimizerState:
nit: int | None
"""Number of optimization steps performed so far in the optimization."""

# Under Python 3.13 the auto-generated equal fails with an error around
# using numpy all or any. See https://github.com/qiskit-community/qiskit-algorithms/pull/225
# for further information. Hence, this custom function was added. The __eq__
# method is supposed to accept any object. If you update the version of
# mypy you're using, it'll print out a note recommending this code structure.
def __eq__(self, other: object) -> bool:
if not isinstance(other, OptimizerState):
# If we return NotImplemented, Python will automatically try
# running other.__eq__(self), in case 'other' knows what to do with
# Person objects.
return NotImplemented

return (
(
self.x == other.x
if isinstance(self.x, float) and isinstance(other.x, float)
else (
False
if isinstance(self.x, float) or isinstance(other.x, float)
else self.x.shape == other.x.shape and (self.x == other.x).all()
)
)
and self.fun == other.fun
and self.jac == other.jac
and self.nfev == other.nfev
and self.njev == other.njev
and self.nit == other.nit
)


class SteppableOptimizer(Optimizer):
"""
Expand Down Expand Up @@ -177,7 +206,7 @@ def ask(self) -> AskData:
This method asks the optimizer which are the next points to evaluate.
These points can, e.g., correspond to function values and/or its derivative.
It may also correspond to variables that let the user infer which points to evaluate.
It is the first method inside of a :meth:`~.step` in the optimization process.
It is the first method inside a :meth:`~.step` in the optimization process.

Returns:
An object containing the data needed to make the function evaluation to advance the
Expand Down Expand Up @@ -260,7 +289,7 @@ def minimize(
) -> OptimizerResult:
"""Minimizes the function.

For well behaved functions the user can call this method to minimize a function.
For well-behaved functions the user can call this method to minimize a function.
If the user wants more control on how to evaluate the function a custom loop can be
created using :meth:`~.ask` and :meth:`~.tell` and evaluating the function manually.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
features:
- |
Added support for using Qiskit Machine Learning with Python 3.13 following the release of
Python 3.13 (final) in October 2024 (`PEP 719 <https://peps.python.org/pep-0719/>`__). To
access the latest features of Python 3.13, you may update your Qiskit Machine Learning
environment.
3 changes: 2 additions & 1 deletion setup.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 2021, 2024.
# (C) Copyright IBM 2021, 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 @@ -65,6 +65,7 @@
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Scientific/Engineering",
],
keywords="qiskit sdk quantum machine learning ml",
Expand Down
2 changes: 1 addition & 1 deletion tox.ini
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[tox]
# Sets this min.version because of differences with env_tmp_dir env.
minversion = 4.0.2
envlist = py39, py310, py311, py312, lint, gpu, gpu-amd
envlist = py39, py310, py311, py312, py313, lint, gpu, gpu-amd
skipsdist = True

[testenv]
Expand Down