Skip to content

Commit

Permalink
Merge branch 'master' into feature/small_improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
thangleiter committed Nov 6, 2024
2 parents e34515b + d7f380b commit 5346dfa
Show file tree
Hide file tree
Showing 12 changed files with 70 additions and 134 deletions.
1 change: 0 additions & 1 deletion .readthedocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ python:
- doc
- plotting
- bloch_sphere_visualization
- fancy_progressbar

sphinx:
builder: html
Expand Down
8 changes: 8 additions & 0 deletions doc/source/api.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
API
===

.. autosummary::
:toctree: generated
:recursive:

filter_functions
5 changes: 3 additions & 2 deletions doc/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,27 +38,28 @@
'nbsphinx',
'sphinx.ext.mathjax',
'sphinx.ext.todo',
'sphinx.ext.autodoc',
'sphinx.ext.autosummary',
'numpydoc',
'sphinx.ext.extlinks',
'sphinx.ext.viewcode',
'sphinx.ext.ifconfig',
'sphinx.ext.napoleon',
'sphinx.ext.intersphinx',
#'sphinxcontrib.apidoc',
'sphinxcontrib.apidoc',
#'IPython.sphinxext.ipython_console_highlighting',
#'IPython.sphinxext.ipython_directive',
#'matplotlib.sphinxext.only_directives',
#'matplotlib.sphinxext.plot_directive',
#'matplotlib.sphinxext.mathmpl',
#'sphinx.ext.autodoc',
#'sphinx.ext.doctest',
]

# Apidoc config
apidoc_module_dir = '../../filter_functions'
apidoc_excluded_paths = ['../tests']
apidoc_separate_modules = True
apidoc_module_first = True

# Numpydoc settings
numpydoc_show_inherited_class_members = False
Expand Down
85 changes: 0 additions & 85 deletions doc/source/filter_functions.rst

This file was deleted.

2 changes: 1 addition & 1 deletion doc/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Documentation
:numbered:

examples/examples
filter_functions API Documentation <filter_functions>
filter_functions API Documentation <api>

Indices and tables
==================
Expand Down
2 changes: 1 addition & 1 deletion environment.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
name: filter_functions

channels:
- defaults
- conda-forge

dependencies:
- python >= 3.9
- qutip
- pandoc
- pip

prefix: /home/docs/.conda/envs/filter_functions
33 changes: 18 additions & 15 deletions filter_functions/basis.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@
import numpy as np
import opt_einsum as oe
from numpy import linalg as nla
from numpy.core import ndarray
from scipy import linalg as sla
from sparse import COO

Expand All @@ -56,7 +55,7 @@
__all__ = ['Basis', 'expand', 'ggm_expand', 'normalize']


class Basis(ndarray):
class Basis(np.ndarray):
r"""
Class for operator bases. There are several ways to instantiate a
Basis object:
Expand Down Expand Up @@ -211,22 +210,26 @@ def __eq__(self, other: object) -> bool:
# Not ndarray
return np.equal(self, other)

return np.allclose(self.view(ndarray), other.view(ndarray),
return np.allclose(self.view(np.ndarray), other.view(np.ndarray),
atol=self._atol, rtol=self._rtol)

def __contains__(self, item: ndarray) -> bool:
def __contains__(self, item: np.ndarray) -> bool:
"""Implement 'in' operator."""
return any(np.isclose(item.view(ndarray), self.view(ndarray),
return any(np.isclose(item.view(np.ndarray), self.view(np.ndarray),
rtol=self._rtol, atol=self._atol).all(axis=(1, 2)))

def __array_wrap__(self, out_arr, context=None):
def __array_wrap__(self, arr, context=None, return_scalar=False):
"""
Fixes problem that ufuncs return 0-d arrays instead of scalars.
https://github.com/numpy/numpy/issues/5819#issue-72454838
"""
if out_arr.ndim:
return ndarray.__array_wrap__(self, out_arr, context)
try:
return super().__array_wrap__(arr, context, return_scalar=True)
except TypeError:
if arr.ndim:
# Numpy < 2
return np.ndarray.__array_wrap__(self, arr, context)

def _print_checks(self) -> None:
"""Print checks for debug purposes."""
Expand Down Expand Up @@ -595,7 +598,7 @@ def _full_from_partial(elems: Sequence, traceless: bool, labels: Sequence[str])
# sort Identity label to the front, default to first if not found
# (should not happen since traceless checks that it is present)
id_idx = next((i for i, elem in enumerate(elems)
if np.allclose(Id.view(ndarray), elem.view(ndarray),
if np.allclose(Id.view(np.ndarray), elem.view(np.ndarray),
rtol=elems._rtol, atol=elems._atol)), 0)
labels.insert(0, labels.pop(id_idx))

Expand All @@ -604,7 +607,7 @@ def _full_from_partial(elems: Sequence, traceless: bool, labels: Sequence[str])
return basis, labels


def _norm(b: Sequence) -> ndarray:
def _norm(b: Sequence) -> np.ndarray:
"""Frobenius norm with two singleton dimensions inserted at the end."""
b = np.asanyarray(b)
norm = nla.norm(b, axis=(-1, -2))
Expand All @@ -631,8 +634,8 @@ def normalize(b: Basis) -> Basis:
return (b/_norm(b)).squeeze().view(Basis)


def expand(M: Union[ndarray, Basis], basis: Union[ndarray, Basis],
normalized: bool = True, hermitian: bool = False, tidyup: bool = False) -> ndarray:
def expand(M: Union[np.ndarray, Basis], basis: Union[np.ndarray, Basis],
normalized: bool = True, hermitian: bool = False, tidyup: bool = False) -> np.ndarray:
r"""
Expand the array *M* in the basis given by *basis*.
Expand Down Expand Up @@ -682,7 +685,7 @@ def cast(arr):
return util.remove_float_errors(coefficients) if tidyup else coefficients


def ggm_expand(M: Union[ndarray, Basis], traceless: bool = False,
def ggm_expand(M: Union[np.ndarray, Basis], traceless: bool = False,
hermitian: bool = False, tidyup: bool = False) -> ndarray:
r"""
Expand the matrix *M* in a Generalized Gell-Mann basis [Bert08]_.
Expand Down Expand Up @@ -771,7 +774,7 @@ def cast(arr):
return coeffs


def equivalent_pauli_basis_elements(idx: Union[Sequence[int], int], N: int) -> ndarray:
def equivalent_pauli_basis_elements(idx: Union[Sequence[int], int], N: int) -> np.ndarray:
"""
Get the indices of the equivalent (up to identities tensored to it)
basis elements of Pauli bases of qubits at position idx in the total
Expand All @@ -784,7 +787,7 @@ def equivalent_pauli_basis_elements(idx: Union[Sequence[int], int], N: int) -> n
return elem_idx


def remap_pauli_basis_elements(order: Sequence[int], N: int) -> ndarray:
def remap_pauli_basis_elements(order: Sequence[int], N: int) -> np.ndarray:
"""
For a N-qubit Pauli basis, transpose the order of the subsystems and
return the indices that permute the old basis to the new.
Expand Down
32 changes: 20 additions & 12 deletions filter_functions/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@
:func:`abs2`
Absolute value squared
:func:`get_indices_from_identifiers`
The the indices of a subset of identifiers within a list of
identifiers.
The indices of a subset of identifiers within a list of identifiers.
:func:`tensor`
Fast, flexible tensor product of an arbitrary number of inputs using
:func:`~numpy.einsum`
Expand Down Expand Up @@ -70,6 +69,7 @@
import functools
import inspect
import operator
import os
import string
from itertools import zip_longest
from typing import Callable, Iterable, List, Optional, Sequence, Tuple, Union
Expand All @@ -79,17 +79,25 @@

from .types import Operator, State

try:
import ipynbname
_NOTEBOOK_NAME = ipynbname.name()
except (ImportError, IndexError, FileNotFoundError):
_NOTEBOOK_NAME = ''

if _NOTEBOOK_NAME:
from tqdm.notebook import tqdm as _tqdm
def _in_notebook_kernel():
# https://github.com/jupyterlab/jupyterlab/issues/16282
return 'JPY_SESSION_NAME' in os.environ and os.environ['JPY_SESSION_NAME'].endswith('.ipynb')


def _in_jupyter_kernel():
# https://discourse.jupyter.org/t/how-to-know-from-python-script-if-we-are-in-jupyterlab/23993
return 'JPY_PARENT_PID' in os.environ


if not _in_notebook_kernel():
if _in_jupyter_kernel():
# (10/24) Autonotebook gets confused in jupyter consoles
from tqdm.std import tqdm
else:
from tqdm.autonotebook import tqdm
else:
# Either not running notebook or not able to determine
from tqdm import tqdm as _tqdm
from tqdm.notebook import tqdm

__all__ = ['paulis', 'abs2', 'all_array_equal', 'dot_HS', 'get_sample_frequencies',
'hash_array_along_axis', 'mdot', 'oper_equiv', 'progressbar', 'remove_float_errors',
Expand Down Expand Up @@ -1067,7 +1075,7 @@ def progressbar(iterable: Iterable, *args, **kwargs):
for i in progressbar(range(10)):
do_something()
"""
return _tqdm(iterable, *args, **kwargs)
return tqdm(iterable, *args, **kwargs)


def progressbar_range(*args, show_progressbar: bool = True, **kwargs):
Expand Down
3 changes: 1 addition & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,8 @@ def extract_version(version_file):

extras_require = {'plotting': ['matplotlib'],
'bloch_sphere_visualization': ['qutip', 'matplotlib'],
'fancy_progressbar': ['ipynbname', 'jupyter'],
'doc': ['jupyter', 'nbsphinx', 'numpydoc', 'sphinx', 'sphinx_rtd_theme',
'ipympl', 'qutip-qip', 'qutip-qtrl'],
'sphinxcontrib-apidoc', 'ipympl', 'qutip-qip', 'qutip-qtrl', 'numpy<2'],
'tests': ['pytest>=4.6', 'pytest-cov', 'codecov']}

extras_require['all'] = list({dep for deps in extras_require.values() for dep in deps})
Expand Down
19 changes: 16 additions & 3 deletions tests/test_basis.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from copy import copy
from itertools import product

import filter_functions as ff
import numpy as np
import pytest
from opt_einsum import contract
Expand Down Expand Up @@ -153,9 +154,21 @@ def test_basis_properties(self):

base._print_checks()

basis = util.paulis[1].view(ff.Basis)
self.assertTrue(basis.isorthonorm)
self.assertArrayEqual(basis.T, basis.view(np.ndarray).T)
# single element always considered orthonormal
orthonorm = rng.normal(size=(d, d))
self.assertTrue(orthonorm.view(ff.Basis).isorthonorm)

herm = testutil.rand_herm(d).squeeze()
self.assertTrue(herm.view(ff.Basis).isherm)

herm[0, 1] += 1
self.assertFalse(herm.view(ff.Basis).isherm)

traceless = testutil.rand_herm_traceless(d).squeeze()
self.assertTrue(traceless.view(ff.Basis).istraceless)

traceless[0, 0] += 1
self.assertFalse(traceless.view(ff.Basis).istraceless)

def test_transpose(self):
arr = rng.normal(size=(2, 3, 3))
Expand Down
12 changes: 1 addition & 11 deletions tests/test_extras.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,11 @@

from . import matplotlib

all_extras = ['fancy_progressbar', 'plotting', 'bloch_sphere_visualization']
all_extras = ['plotting', 'bloch_sphere_visualization']


class MissingExtrasTest(testutil.TestCase):

@pytest.mark.skipif(
'fancy_progressbar' in os.environ.get('INSTALL_EXTRAS', all_extras),
reason='Skipping tests for missing fancy progressbar extra in build with ipynbname')
def test_fancy_progressbar_not_available(self):
from tqdm import tqdm

from filter_functions import util
self.assertEqual(util._NOTEBOOK_NAME, '')
self.assertIs(tqdm, util._tqdm)

@pytest.mark.skipif(
any(extra in os.environ.get('INSTALL_EXTRAS', all_extras)
for extra in ['plotting', 'bloch_sphere_visualization']),
Expand Down
Loading

0 comments on commit 5346dfa

Please sign in to comment.