Skip to content

Commit

Permalink
Add Python 3.12 and drop 3.8 (#322)
Browse files Browse the repository at this point in the history
  • Loading branch information
DanPuzzuoli authored Feb 8, 2024
1 parent 4d4c2b7 commit f29573f
Show file tree
Hide file tree
Showing 40 changed files with 196 additions and 199 deletions.
10 changes: 5 additions & 5 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
python-version: ['3.8', '3.9', '3.10', '3.11']
python-version: ['3.9', '3.10', '3.11', '3.12']
os: ["ubuntu-latest", "macOS-latest", "windows-latest"]
steps:
- uses: actions/checkout@v2
Expand Down Expand Up @@ -40,10 +40,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python 3.8
- name: Set up Python 3.10
uses: actions/setup-python@v2
with:
python-version: 3.8
python-version: '3.10'
- name: Pip cache
uses: actions/cache@v2
with:
Expand All @@ -64,10 +64,10 @@ jobs:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Set up Python 3.8
- name: Set up Python 3.10
uses: actions/setup-python@v2
with:
python-version: 3.8
python-version: '3.10'
- name: Pip cache
uses: actions/cache@v2
with:
Expand Down
14 changes: 7 additions & 7 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,12 +201,12 @@ environment that tox sets up matches the CI environment more closely and it
runs the tests in parallel (resulting in much faster execution). To run tests
on all installed supported python versions and lint/style checks you can simply
run `tox`. Or if you just want to run the tests once run for a specific python
version: `tox -epy38` (or replace py38 with the python version you want to use,
py39 or py310).
version: `tox -epy39` (or replace py39 with the python version you want to use,
py310, py311, or py312).

If you just want to run a subset of tests you can pass a selection regex to
the test runner. For example, if you want to run all tests that have "dag" in
the test id you can run: `tox -epy38 -- dag`. You can pass arguments directly to
the test id you can run: `tox -epy39 -- dag`. You can pass arguments directly to
the test runner after the bare `--`. To see all the options on test selection
you can refer to the stestr manual:
https://stestr.readthedocs.io/en/stable/MANUAL.html#test-selection
Expand All @@ -216,21 +216,21 @@ you can do this faster with the `-n`/`--no-discover` option. For example:

to run a module:
```
tox -epy38 -- -n test.python.test_examples
tox -epy39 -- -n test.python.test_examples
```
or to run the same module by path:

```
tox -epy38 -- -n test/python/test_examples.py
tox -epy39 -- -n test/python/test_examples.py
```
to run a class:

```
tox -epy38 -- -n test.python.test_examples.TestPythonExamples
tox -epy39 -- -n test.python.test_examples.TestPythonExamples
```
to run a method:
```
tox -epy38 -- -n test.python.test_examples.TestPythonExamples.test_all_examples
tox -epy39 -- -n test.python.test_examples.TestPythonExamples.test_all_examples
```

##### STDOUT/STDERR and logging capture
Expand Down
6 changes: 6 additions & 0 deletions docs/userguide/perturbative_solvers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ explanation of how to work with JAX in Qiskit Dynamics.

.. jupyter-execute::

#################################################################################
# Remove this
#################################################################################
import warnings
warnings.filterwarnings("ignore")

# configure jax to use 64 bit mode
import jax
jax.config.update("jax_enable_x64", True)
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ build-backend = "setuptools.build_meta"

[tool.black]
line-length = 100
target-version = ['py38', 'py39', 'py310', 'py311']
target-version = ['py39', 'py310', 'py311', 'py312']
2 changes: 1 addition & 1 deletion qiskit_dynamics/arraylias/alias.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,6 @@ def decorated_init(self, *args, **kwargs):
return obj

else:
raise Exception(f"Cannot decorate object {obj} that is not a class or function.")
raise ValueError(f"Cannot decorate object {obj} that is not a class or function.")

return decorator
20 changes: 10 additions & 10 deletions qiskit_dynamics/backend/backend_string_parser/regex_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ def parse(self, qubit_list=None):
# convert to reverse Polish notation
for ham in self.h_str:
if len(re.findall(r"\|\|", ham)) > 1:
raise Exception(f"Multiple time-dependent terms in {ham}")
raise ValueError(f"Multiple time-dependent terms in {ham}")
p_td = re.search(r"(?P<opr>[\S]+)\|\|(?P<ch>[\S]+)", ham)

# find time-dependent term
Expand Down Expand Up @@ -135,7 +135,7 @@ def _expand_sum(self):
p_sums = list(sum_str.finditer(ham))
p_brks = list(brk_str.finditer(ham))
if len(p_sums) != len(p_brks):
raise Exception(f"Missing correct number of brackets in {ham}")
raise ValueError(f"Missing correct number of brackets in {ham}")

# find correct sum-bracket correspondence
if any(p_sums) == 0:
Expand Down Expand Up @@ -223,7 +223,7 @@ def _tokenizer(self, op_str, qubit_list=None):
prev = _key
break
else:
raise Exception(f"Invalid input string {op_str} is found")
raise ValueError(f"Invalid input string {op_str} is found")

# split coefficient
coef = ""
Expand All @@ -235,7 +235,7 @@ def _tokenizer(self, op_str, qubit_list=None):
token_list = token_list[ii + 1 :]
break
else:
raise Exception(f"Invalid order of operators and coefficients in {op_str}")
raise ValueError(f"Invalid order of operators and coefficients in {op_str}")

return coef, token_list

Expand All @@ -259,12 +259,12 @@ def _shunting_yard(self, token_list):
while stack[-1].type not in ["BrkL", "Func"]:
queue.append(stack.pop(-1))
if not any(stack):
raise Exception("Missing correct number of brackets")
raise ValueError("Missing correct number of brackets")
pop = stack.pop(-1)
if pop.type == "Func":
queue.append(pop)
else:
raise Exception(f"Invalid token {token.name} is found")
raise ValueError(f"Invalid token {token.name} is found")

while any(stack):
queue.append(stack.pop(-1))
Expand Down Expand Up @@ -297,12 +297,12 @@ def _token2qobj(self, tokens):
if token.name == "dag":
stack.append(np.conjugate(np.transpose(stack.pop(-1))))
else:
raise Exception(f"Invalid token {token.name} of type Func, Ext.")
raise ValueError(f"Invalid token {token.name} of type Func, Ext.")
else:
raise Exception(f"Invalid token {token.name} is found.")
raise ValueError(f"Invalid token {token.name} is found.")

if len(stack) > 1:
raise Exception("Invalid mathematical operation in string.")
raise ValueError("Invalid mathematical operation in string.")

return stack[0]

Expand Down Expand Up @@ -363,7 +363,7 @@ def parse_binop(op_str, operands={}, cast_str=True):
retv = 0
break
else:
raise Exception(f"Invalid string {op_str}")
raise ValueError(f"Invalid string {op_str}")

if cast_str:
return str(retv)
Expand Down
2 changes: 1 addition & 1 deletion qiskit_dynamics/backend/dynamics_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.
# pylint: disable=invalid-name
# pylint: disable=invalid-name, arguments-differ

"""
Pulse-enabled simulator backend.
Expand Down
2 changes: 1 addition & 1 deletion qiskit_dynamics/dispatch/dispatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,6 @@ def decorated_init(self, *args, **kwargs):
return obj

else:
raise Exception(f"Cannot decorate object {obj} that is not a class or function.")
raise ValueError(f"Cannot decorate object {obj} that is not a class or function.")

return decorator
2 changes: 1 addition & 1 deletion qiskit_dynamics/models/generator_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ def evaluate_rhs(self, time: float, y: ArrayLike) -> ArrayLike:
)
sig_vals = None
else:
sig_vals = self._signals.__call__(time)
sig_vals = self._signals(time)

if self.rotating_frame is not None:
# First, compute e^{tF}y as a pre-rotation in the frame basis
Expand Down
3 changes: 1 addition & 2 deletions qiskit_dynamics/models/rotating_wave_approximation.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,8 +238,7 @@ def jax_transformable_func(t):
)

if return_signal_map:
signal_translator = lambda a: (get_rwa_signals(a[0]), get_rwa_signals(a[1]))
return rwa_model, signal_translator
return rwa_model, lambda a: (get_rwa_signals(a[0]), get_rwa_signals(a[1]))
return rwa_model


Expand Down
9 changes: 7 additions & 2 deletions qiskit_dynamics/perturbation/array_polynomial.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ class ArrayPolynomial:
is similar to ``ap1 @ ap2``, but will result in an :class:`.ArrayPolynomial` in which all
terms of degree larger than ``3`` will not be included in the results.
"""

__array_priority__ = 20

def __init__(
Expand Down Expand Up @@ -743,7 +744,9 @@ def _array_polynomial_distributive_binary_op(

# if no filter is provided, set to always return True
if monomial_filter is None:
monomial_filter = lambda x: True

def monomial_filter(_):
return True

if ap1.constant_term is not None:
for multiset in ap2.monomial_labels:
Expand Down Expand Up @@ -845,7 +848,9 @@ def _array_polynomial_addition(
)

if monomial_filter is None:
monomial_filter = lambda x: True

def monomial_filter(_):
return True

# construct constant term
new_constant_term = None
Expand Down
6 changes: 2 additions & 4 deletions qiskit_dynamics/perturbation/custom_binary_op.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,9 @@ def __init__(
):
"""Initialize."""

binary_op = lambda A, B: A @ B
super().__init__(
operation_rule=operation_rule,
binary_op=binary_op,
binary_op=lambda A, B: A @ B,
index_offset=index_offset,
operation_rule_compiled=operation_rule_compiled,
)
Expand All @@ -136,10 +135,9 @@ def __init__(
):
"""Initialize."""

binary_op = lambda A, B: A * B
super().__init__(
operation_rule=operation_rule,
binary_op=binary_op,
binary_op=lambda A, B: A * B,
index_offset=index_offset,
operation_rule_compiled=operation_rule_compiled,
)
Expand Down
5 changes: 4 additions & 1 deletion qiskit_dynamics/solvers/fixed_step_solvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -590,7 +590,10 @@ def fixed_step_lmde_solver_parallel_template_jax(

# multiply propagators together in parallel
ys = None
reverse_mul = lambda A, B: jnp.matmul(B, A)

def reverse_mul(A, B):
return jnp.matmul(B, A)

if y0.ndim == 2 and y0.shape[0] == y0.shape[1]:
# if square, append y0 as the first step propagator, scan, and extract
intermediate_props = associative_scan(
Expand Down
11 changes: 7 additions & 4 deletions qiskit_dynamics/solvers/lanczos.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,10 +180,13 @@ def lanczos_iter(carry, _):

def cond_func(qpb, _):
_, _, beta_i = qpb
zeros_func = lambda _: (
[jnp.zeros_like(y0), jnp.zeros_like(y0), 0.0],
[jnp.zeros(1, dtype=data_type)[0], 0.0, jnp.zeros_like(y0)],
)

def zeros_func(_):
return (
[jnp.zeros_like(y0), jnp.zeros_like(y0), 0.0],
[jnp.zeros(1, dtype=data_type)[0], 0.0, jnp.zeros_like(y0)],
)

carry_next2, accumulate2 = cond(
beta_i > 0, lambda carry: lanczos_iter(carry, _), zeros_func, qpb
)
Expand Down
5 changes: 4 additions & 1 deletion qiskit_dynamics/solvers/perturbative_solvers/dyson_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,10 @@ def _solve(
_perturbative_solve_jax(self.model.evaluate, self.model, signals, y0, t0, n_steps),
]
else:
single_step = lambda coeffs, y: self.model.evaluate(coeffs) @ y

def single_step(coeffs, y):
return self.model.evaluate(coeffs) @ y

ys = [y0, _perturbative_solve(single_step, self.model, signals, y0, t0, n_steps)]

return OdeResult(t=[t0, t0 + n_steps * self.model.dt], y=ys)
Original file line number Diff line number Diff line change
Expand Up @@ -436,9 +436,8 @@ def _signal_list_envelope_DCT(
if include_imag is None:
include_imag = [True] * len(signal_list)

envelope_DCT = lambda sig, freq, degree: _signal_envelope_DCT(
sig, freq, degree, t0, dt, n_intervals
)
def envelope_DCT(sig, freq, degree):
return _signal_envelope_DCT(sig, freq, degree, t0, dt, n_intervals)

# initialize coefficient array with first signal
coeffs = envelope_DCT(signal_list[0], reference_freqs[0], degrees[0])
Expand Down
10 changes: 8 additions & 2 deletions qiskit_dynamics/solvers/perturbative_solvers/magnus_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,16 @@ def _solve(
) -> OdeResult:
ys = None
if jax_control_flow:
single_step = lambda x: self.model.Udt @ jexpm(self.model.evaluate(x))

def single_step(x):
return self.model.Udt @ jexpm(self.model.evaluate(x))

ys = [y0, _perturbative_solve_jax(single_step, self.model, signals, y0, t0, n_steps)]
else:
single_step = lambda coeffs, y: self.model.Udt @ expm(self.model.evaluate(coeffs)) @ y

def single_step(coeffs, y):
return self.model.Udt @ expm(self.model.evaluate(coeffs)) @ y

ys = [y0, _perturbative_solve(single_step, self.model, signals, y0, t0, n_steps)]

return OdeResult(t=[t0, t0 + n_steps * self.model.dt], y=ys)
2 changes: 1 addition & 1 deletion qiskit_dynamics/solvers/solver_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.
# pylint: disable=invalid-name
# pylint: disable=invalid-name, unnecessary-lambda-assignment

r"""
Solver classes.
Expand Down
1 change: 1 addition & 0 deletions qiskit_dynamics/solvers/solver_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
]

# diffrax solver type placeholder
# pylint: disable=typevar-name-mismatch
DiffraxAbstractSolver = TypeVar("AbstractSolver")


Expand Down
4 changes: 1 addition & 3 deletions qiskit_dynamics/solvers/solver_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,9 +271,7 @@ def setup_args_lists(
if arg_len not in (1, max_len):
max_name = args_names[arg_lens.index(max_len)]

arg_name_sequence = ""
for name in args_names[:-1]:
arg_name_sequence += f"{name}, "
arg_name_sequence = "".join(f"{name}, " for name in args_names[:-1])
arg_name_sequence += f"and {args_names[-1]}"

raise QiskitError(
Expand Down
4 changes: 4 additions & 0 deletions releasenotes/notes/python-versions-655040935a2359c2.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
upgrade:
- |
Support for Python 3.12 has been added, and Python 3.8 has been dropped.
6 changes: 3 additions & 3 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
stestr>=3.0.0
astroid==2.9.3
pylint==2.12.2
black~=22.0
astroid==2.14.2
pylint==2.16.2
black~=24.1
qiskit-sphinx-theme~=1.16.0
sphinx-autodoc-typehints
jupyter-sphinx
Expand Down
Loading

0 comments on commit f29573f

Please sign in to comment.