Skip to content

Commit

Permalink
Merge pull request #1088 from odlgroup/issue-342__tensor
Browse files Browse the repository at this point in the history
CPU tensors
  • Loading branch information
Holger Kohr authored Nov 13, 2017
2 parents 7a285a0 + cecad04 commit 6b73551
Show file tree
Hide file tree
Showing 115 changed files with 11,969 additions and 9,069 deletions.
10 changes: 5 additions & 5 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ language: python
matrix:
include:
- python: 2.7
env: NUMPY_VERSION=1.12
env: NUMPY_VERSION=1.13

- python: 3.6
env: NUMPY_VERSION=1.12 COVERALLS=true BUILD_DOCS=true
env: NUMPY_VERSION=1.12

- python: 3.6
env: NUMPY_VERSION=1.13 COVERALLS=true BUILD_DOCS=true

sudo: false

Expand All @@ -20,8 +22,6 @@ addons:
texlive-latex-extra
dvipng

# Enable cache for $HOME/.cache/pip (wheels and such)
cache: pip

# Setup numpy + scipy using miniconda
# See http://conda.pydata.org/docs/travis.html
Expand All @@ -41,7 +41,7 @@ install:
- conda info -a

# Install dependencies and enter test environment. Use conda for the minimal stuff to
# make it run faster and avoid downloading bug stuff like mkl
# make it run faster and avoid downloading big stuff like mkl
- conda create -n testenv python=$TRAVIS_PYTHON_VERSION nomkl pywavelets
- source activate testenv
# We avoid annoying issues with building pyfftw wheels by using a conda-forge version
Expand Down
4 changes: 2 additions & 2 deletions conda/meta.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ requirements:
- setuptools
- nomkl # [not win]
- future >=0.14
- numpy >=1.9,<1.13
- numpy >=1.9
- scipy >=0.14
run:
- python
- future >=0.14
- nomkl # [not win]
- numpy >=1.9,<1.13
- numpy >=1.9
- scipy >=0.14
- matplotlib
- pytest >=3.0.3
Expand Down
3 changes: 2 additions & 1 deletion doc/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@
'scipy': ('https://docs.scipy.org/doc/scipy/reference/', None),
'matplotlib': ('http://matplotlib.org/', None),
'pywt': ('http://www.pybytes.com/pywavelets/', None),
'pyfftw': ('https://hgomersall.github.io/pyFFTW/', None)}
'pyfftw': ('https://hgomersall.github.io/pyFFTW/', None),
'pytest': ('http://doc.pytest.org/en/latest/', None)}


# Stop autodoc from skipping __init__
Expand Down
2 changes: 1 addition & 1 deletion doc/source/dev/document.rst
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ given below.
def my_other_method(self):
"""Print the parameter.
See also
See Also
--------
my_method : some calculation, but not much
"""
Expand Down
30 changes: 21 additions & 9 deletions doc/source/dev/extend.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,30 @@ This lowers the requirement on code maturity, completeness of documentation, uni

There are several ways to extend ODL, some of which are listed below.

Adding Fn spaces
----------------
The abstract space `FnBase` is the workhorse of the ODL space machinery. They are used in both the discrete :math:`R^n` case, as well as data representation for discretized function spaces such as :math:`L^2([0, 1])` in the `DiscretizedSpace` class. These are in general created through the `rn` and `uniform_discr` functions who take an ``impl`` parameter, allowing users to select the backend to use.
Adding Tensor spaces
--------------------
The abstract `TensorSpace` is the workhorse of the ODL space machinery.
It is used in the discrete :math:`R^n` case, as well as data representation for discretized function spaces such as :math:`L^2([0, 1])` in the `DiscretizedSpace` class.
They are in general created through the `rn` and `uniform_discr` functions which take an ``impl`` parameter, allowing users to select the backend for array storage and computations.

In the core ODL package, there is only a single backend available: `NumpyFn`, given by ``impl='numpy'``, which is the default choice. Users can add CUDA support by installing the add-on library odlcuda_, which contains the additional space ``CudaFn``. By using the `rn`/`uniform_discr` functions, users can then seamlessly change the backend of their spaces.
In the core ODL package, there is only a single backend available: `NumpyTensorSpace`, given by ``impl='numpy'``, which is the default choice.

As an advanced user, you may need to add additional spaces of this type that can be used inside ODL, perhaps to add MPI_ support. There are a few steps to do this:
As an advanced user, you may need to add additional spaces of this type that can be used inside ODL, perhaps to add `MPI`_ support.
There are a few steps to do this:

* Create a new library with a ``setuptools`` installer.
* Add the spaces that you want to add to the library. The space needs to inherit from `FnBase` and implement all of the abstract methods in those spaces. See the spaces for further information on the specific methods that need to be implemented.
* Add the methods ``fn_impl_names()`` and ``fn_impls()`` to a file ``odl_plugin.py`` in your library. These should return a ``dict`` mapping names to implementations.
* Add the following to your library's ``setup.py`` setup call: ``entry_points={'odl.space': ['odl_cuda = odlcuda.odl_plugin']``, where you replace ``odlcuda`` with the name of your plugin.
* Create a new library with a ``setuptools`` installer in the form of a ``setup.py`` file.
* Add the spaces that you want to add to the library.
The spaces need to inherit from `TensorSpace` and implement all of its abstract methods.
See the documentation for further information on the specific methods that need to be implemented.
* Add the methods ``tensor_space_impl()`` and ``tensor_space_impl_names()`` to a file ``odl_plugin.py`` in your library.
The former should return a ``dict`` mapping implementation names to tensor space classes, the latter the names only.
* Add the following to your library's ``setup.py`` in the call of the ``setup`` function:

entry_points={'odl.space': ['mylib = mylib.odl_plugin']

Replace ``mylib`` with the name of your plugin.

For a blueprint of all these steps, check out the implementation of the `odlcuda`_ plugin.

.. _odlcuda: https://github.com/odlgroup/odlcuda
.. _MPI: https://en.wikipedia.org/wiki/Message_Passing_Interface
52 changes: 34 additions & 18 deletions doc/source/generate_doc.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,40 +55,57 @@


def import_submodules(package, name=None, recursive=True):
""" Import all submodules of a module, recursively, including subpackages
"""Import all submodules of ``package``.
Parameters
----------
package : `module` or string
Package whose submodules to import.
name : string, optional
Override the package name with this value in the full
submodule names. By default, ``package`` is used.
recursive : bool, optional
If ``True``, recursively import all submodules of ``package``.
Otherwise, import only the modules at the top level.
Returns
-------
pkg_dict : dict
Dictionary where keys are the full submodule names and values
are the corresponding module objects.
"""
if isinstance(package, str):
package = importlib.import_module(package)

if name is None:
name = package.__name__

submodules = [m[0] for m in inspect.getmembers(
package, inspect.ismodule) if m[1].__name__.startswith('odl')]
submodules = [m[0] for m in inspect.getmembers(package, inspect.ismodule)
if m[1].__name__.startswith('odl')]

results = {}
for pkgname in submodules:
full_name = name + '.' + pkgname
try:
results[full_name] = importlib.import_module(full_name)
if recursive:
results.update(import_submodules(full_name, full_name))
except ImportError:
pass
else:
if recursive:
results.update(import_submodules(full_name, full_name))
return results


def make_interface():
modnames = [modname for modname in import_submodules(odl)]

modnames += ['odl']
"""Generate the RST files for the API doc of ODL."""
modnames = ['odl'] + list(import_submodules(odl).keys())

for modname in modnames:
if not modname.startswith('odl'):
modname = 'odl.' + modname

shortmodname = modname.split('.')[-1]
print('{: <16} : generated {}.rst'.format(shortmodname, modname))
print('{: <25} : generated {}.rst'.format(shortmodname, modname))

line = '=' * len(shortmodname)

Expand Down Expand Up @@ -125,16 +142,15 @@ def make_interface():
else:
this_class_string = ''

text_file = open(modname + '.rst', "w")
text_file.write(string.format(shortname=shortmodname,
name=modname,
line=line,
docstring=docstring,
module_string=this_mod_string,
fun_string=this_fun_string,
class_string=this_class_string))
with open(modname + '.rst', 'w') as text_file:
text_file.write(string.format(shortname=shortmodname,
name=modname,
line=line,
docstring=docstring,
module_string=this_mod_string,
fun_string=this_fun_string,
class_string=this_class_string))

text_file.close()

if __name__ == '__main__':
make_interface()
2 changes: 1 addition & 1 deletion doc/source/getting_started/about_odl.rst
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ The method needs a relaxation :math:`\lambda < 2 / \lVert A\rvert^2` to converge
>>> matrix = np.array([[1.0, 3.0, 2.0],
... [2.0, -1.0, 1.0]])
>>> matrix_op = odl.MatVecOperator(matrix) # operator defined by the matrix
>>> matrix_op = odl.MatrixOperator(matrix) # operator defined by the matrix
>>> matrix_op.domain
rn(3)
>>> matrix_op.range
Expand Down
4 changes: 2 additions & 2 deletions doc/source/guide/glossary.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Glossary

array-like
Any data structure which can be converted into a `numpy.ndarray` by the
`numpy.array` constructor. Includes all `NtuplesBaseVector` based classes.
`numpy.array` constructor. Includes all `Tensor` based classes.

convex conjugate
The convex conjugate (also called Fenchel conjugate) is an important tool in convex optimization.
Expand All @@ -22,7 +22,7 @@ Glossary
discretization
Structure to handle the mapping between abstract objects (e.g. functions) and concrete, finite realizations.
It encompasses an abstract `Set`, a finite data container (`NtuplesBaseVector` in general) and the mappings between them, :term:`sampling` and :term:`interpolation`.
It encompasses an abstract `Set`, a `Tensor` as finite data container and the mappings between them, :term:`sampling` and :term:`interpolation`.

domain
Set of elements to which an operator can be applied.
Expand Down
Loading

0 comments on commit 6b73551

Please sign in to comment.