diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8377cdf..f20cbad 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -11,7 +11,7 @@ jobs: strategy: fail-fast: false matrix: - python_version: ['3.7', '3.8', '3.9', '3.10'] + python_version: ['3.9', '3.10', '3.11', '3.12'] install_extras: ['tests', 'plotting,fancy_progressbar,tests', 'plotting,bloch_sphere_visualization,fancy_progressbar,doc,tests'] steps: diff --git a/.readthedocs.yml b/.readthedocs.yml index 5aad26f..5d50b07 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -2,10 +2,11 @@ version: 2 build: image: stable + python: "3.10" conda: environment: environment.yml - + python: system_packages: true install: diff --git a/environment.yml b/environment.yml index 60f2a3c..018eb5f 100644 --- a/environment.yml +++ b/environment.yml @@ -5,9 +5,8 @@ channels: - conda-forge dependencies: - - python < 3.9 + - python >= 3.9 - qutip - pip prefix: /home/docs/.conda/envs/filter_functions - diff --git a/examples/randomized_benchmarking.py b/examples/randomized_benchmarking.py index e366bd0..8d5b154 100644 --- a/examples/randomized_benchmarking.py +++ b/examples/randomized_benchmarking.py @@ -32,7 +32,7 @@ import qutip as qt from numpy import ndarray from numpy.random import permutation -from scipy import io, optimize +from scipy import io, optimize, integrate # %% @@ -46,7 +46,7 @@ def state_infidelity(pulse: ff.PulseSequence, S: ndarray, omega: ndarray, """Compute state infidelity for input state eigenstate of pauli *ind*""" R = pulse.get_control_matrix(omega) F = np.einsum('jko->jo', ff.util.abs2(R[:, np.delete([0, 1, 2, 3], ind)])) - return np.trapz(F*S, omega)/(2*np.pi*pulse.d) + return integrate.trapezoid(F*S, omega)/(2*np.pi*pulse.d) def find_inverse(U: ndarray, cliffords: Sequence[ff.PulseSequence]) -> ndarray: diff --git a/filter_functions/analytic.py b/filter_functions/analytic.py index dbc24e9..c556840 100644 --- a/filter_functions/analytic.py +++ b/filter_functions/analytic.py @@ -80,7 +80,7 @@ def CPMG(z, n): def CDD(z, g): return 2**(2*g + 1)*np.sin(z/2**(g + 1))**2 *\ - np.product([np.sin(z/2**(k + 1))**2 for k in range(1, g+1)], axis=0) + np.prod([np.sin(z/2**(k + 1))**2 for k in range(1, g+1)], axis=0) def UDD(z, n): diff --git a/filter_functions/basis.py b/filter_functions/basis.py index f98dde1..a69fefd 100644 --- a/filter_functions/basis.py +++ b/filter_functions/basis.py @@ -174,7 +174,7 @@ def __new__(cls, basis_array: Sequence, traceless: Optional[bool] = None, pass basis = util.parse_operators(basis_array, 'basis_array') - if basis.shape[0] > np.product(basis.shape[1:]): + if basis.shape[0] > np.prod(basis.shape[1:]): raise ValueError('Given overcomplete set of basis matrices. ' 'Not linearly independent.') diff --git a/filter_functions/plotting.py b/filter_functions/plotting.py index 7aee0eb..9d78e0c 100644 --- a/filter_functions/plotting.py +++ b/filter_functions/plotting.py @@ -261,7 +261,8 @@ def plot_bloch_vector_evolution( b.axes.add_collection3d(lc, zdir='z', zs=segments[:, :, 2]) if add_cbar: - default_cbar_kwargs = dict(shrink=2/3, pad=0.05, label=r'$t$ ($\tau$)', ticks=[0, 1]) + default_cbar_kwargs = dict(shrink=2/3, pad=0.05, label=r'$t$ ($\tau$)', ticks=[0, 1], + ax=b.axes) cbar_kwargs = {**default_cbar_kwargs, **(cbar_kwargs or {})} b.fig.colorbar(cm.ScalarMappable(cmap=cmap), **cbar_kwargs) diff --git a/filter_functions/util.py b/filter_functions/util.py index c5de78c..4064ee0 100644 --- a/filter_functions/util.py +++ b/filter_functions/util.py @@ -227,6 +227,9 @@ def parse_operators(opers: Sequence[Operator], err_loc: str) -> List[ndarray]: elif hasattr(oper, 'full'): # qutip.Qobj parsed_opers.append(oper.full()) + elif hasattr(oper, 'to_array'): + # qutip.Dia object + parsed_opers.append(oper.to_array()) elif hasattr(oper, 'todense'): # sparse object parsed_opers.append(oper.todense()) @@ -843,7 +846,7 @@ def integrate(f: ndarray, x: Optional[ndarray] = None, dx: float = 1.0) -> Union See Also -------- - numpy.trapz + scipy.integrate.trapezoid """ dx = np.diff(x) if x is not None else dx diff --git a/setup.py b/setup.py index edc38a9..a6bd5b3 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- import os import re -import sys from setuptools import setup @@ -17,11 +16,6 @@ def extract_version(version_file): raise RuntimeError("Unable to find version string.") - -if sys.version_info < (3, 7): - sys.stderr.write('ERROR: You need Python 3.7 or later to install this package.\n') - exit(1) - extras_require = {'plotting': ['matplotlib'], 'bloch_sphere_visualization': ['qutip', 'matplotlib'], 'fancy_progressbar': ['ipynbname', 'jupyter'], @@ -40,6 +34,7 @@ def extract_version(version_file): author_email='tobias.hangleiter@rwth-aachen.de', packages=['filter_functions'], package_dir={'filter_functions': 'filter_functions'}, + python_requires='>=3.8', install_requires=['numpy', 'scipy', 'opt_einsum', 'sparse', 'tqdm'], extras_require=extras_require, test_suite='tests', diff --git a/tests/test_precision.py b/tests/test_precision.py index 6a359b2..162dd0d 100644 --- a/tests/test_precision.py +++ b/tests/test_precision.py @@ -41,7 +41,7 @@ def _get_integrals_first_order(d, E, eigval, dt, t0): EdE = np.add.outer(E, dE) integrand = np.exp(1j*np.multiply.outer(EdE, tspace - t0)) - integral_numeric = integrate.trapz(integrand, tspace) + integral_numeric = integrate.trapezoid(integrand, tspace) integral = numeric._first_order_integral(E, eigval, dt, exp_buf, int_buf) return integral, integral_numeric @@ -61,12 +61,12 @@ def _get_integrals_second_order(d, E, eigval, dt, t0): ex = (np.multiply.outer(dE, tspace - t0) + np.multiply.outer(E, tspace)[:, None, None]) - I1 = integrate.cumtrapz(util.cexp(ex), tspace, initial=0) + I1 = integrate.cumulative_trapezoid(util.cexp(ex), tspace, initial=0) ex = (np.multiply.outer(dE, tspace - t0) - np.multiply.outer(E, tspace)[:, None, None]) integrand = util.cexp(ex)[:, :, :, None, None] * I1[:, None, None] - integral_numeric = integrate.trapz(integrand, tspace) + integral_numeric = integrate.trapezoid(integrand, tspace) integral = numeric._second_order_integral(E, eigval, dt, int_buf, frc_bufs, dE_bufs, exp_buf, msk_bufs) return integral, integral_numeric diff --git a/tests/test_superoperator.py b/tests/test_superoperator.py index 8b52024..ab5774d 100644 --- a/tests/test_superoperator.py +++ b/tests/test_superoperator.py @@ -129,7 +129,7 @@ def partial_transpose(A): self.assertArrayEqual(CP, _CP) self.assertTrue(np.all(CP)) if U_sup.ndim == 2: - self.assertIsInstance(CP, (bool, np.bool8)) + self.assertIsInstance(CP, (bool, np.bool_)) else: self.assertEqual(CP.shape[0], U_sup.shape[0]) # Only one nonzero eigenvalue @@ -143,7 +143,7 @@ def partial_transpose(A): CP = superoperator.liouville_is_CP(U_sup, pulse.basis) self.assertTrue(np.all(CP)) - self.assertIsInstance(CP, (bool, np.bool8)) + self.assertIsInstance(CP, (bool, np.bool_)) def test_liouville_is_cCP(self): for d in rng.integers(2, 9, (15,)): @@ -165,7 +165,7 @@ def test_liouville_is_cCP(self): self.assertArrayEqual(cCP, _cCP) self.assertTrue(np.all(cCP)) if H_sup.ndim == 2: - self.assertIsInstance(cCP, (bool, np.bool8)) + self.assertIsInstance(cCP, (bool, np.bool_)) else: self.assertEqual(cCP.shape[0], H_sup.shape[0]) self.assertArrayAlmostEqual(D, 0, atol=1e-14) @@ -182,6 +182,6 @@ def test_liouville_is_cCP(self): self.assertTrue(np.all(cCP)) if K_sup.ndim == 2: - self.assertIsInstance(cCP, (bool, np.bool8)) + self.assertIsInstance(cCP, (bool, np.bool_)) else: self.assertEqual(cCP.shape[0], K_sup.shape[0]) diff --git a/tests/test_util.py b/tests/test_util.py index 469cc84..531078d 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -23,6 +23,7 @@ """ import numpy as np import pytest +from scipy import integrate from filter_functions import PulseSequence, util from tests import testutil @@ -415,11 +416,11 @@ def test_mdot(self): def test_integrate(self): f = rng.standard_normal(32) x = rng.random(32) - self.assertEqual(util.integrate(f, x), np.trapz(f, x)) + self.assertEqual(util.integrate(f, x), integrate.trapezoid(f, x)) f = rng.standard_normal((2, 32)).astype(complex) x = rng.random(32) - self.assertArrayEqual(util.integrate(f, x), np.trapz(f, x)) + self.assertArrayEqual(util.integrate(f, x), integrate.trapezoid(f, x)) f = rng.standard_normal(32) x = np.linspace(0, 1, 32)