Skip to content

Commit

Permalink
Updates to documentation: add demo page and update basic usage guide
Browse files Browse the repository at this point in the history
  • Loading branch information
Ashwin Srinath committed Jul 7, 2018
1 parent 1a1f36c commit 3b31f04
Show file tree
Hide file tree
Showing 50 changed files with 3,729 additions and 171 deletions.
17 changes: 15 additions & 2 deletions demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,26 @@
pyamgx.initialize()

# Initialize config and resources:
cfg = pyamgx.Config().create_from_file(os.environ['AMGX_DIR']+'/core/configs/FGMRES_AGGREGATION.json')
cfg = pyamgx.Config().create_from_dict({
"config_version": 2,
"determinism_flag": 1,
"exception_handling" : 1,
"solver": {
"monitor_residual": 1,
"solver": "BICGSTAB",
"convergence": "RELATIVE_INI_CORE",
"preconditioner": {
"solver": "NOSOLVER"
}
}
})

rsc = pyamgx.Resources().create_simple(cfg)

# Create matrices and vectors:
A = pyamgx.Matrix().create(rsc)
x = pyamgx.Vector().create(rsc)
b = pyamgx.Vector().create(rsc)
x = pyamgx.Vector().create(rsc)

# Create solver:
solver = pyamgx.Solver().create(rsc, cfg)
Expand Down
Binary file added docs/.quick-start.rst.swp
Binary file not shown.
242 changes: 242 additions & 0 deletions docs/basic.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
Basic Usage
===========

Initializing and finalizing pyamgx
----------------------------------

The :py:func:`~pyamgx.initialize` and :py:func:`~pyamgx.finalize` functions
**must** be called to initialize and finalize the library respectively.

.. code-block:: python
import pyamgx
pyamgx.initialize()
# use pyamgx
pyamgx.finalize()
Config objects
--------------

:py:class:`~pyamgx.Config` objects are used to store configuration settings
for the linear solver used, including
algorithm, preconditioner(s), smoother(s) and associated parameters.

:py:class:`~pyamgx.Config` objects can be constructed from
JSON files or :py:class:`dict` objects.

As an example, the :py:class:`~pyamgx.Config` object below
represents the configuration for a BICGSTAB solver
without preconditioning, and is constructed using
the :py:meth:`~pyamgx.Config.create_from_dict` method:

.. code-block:: python
cfg = pyamgx.Config()
cfg.create_from_dict({
"config_version": 2,
"determinism_flag": 1,
"exception_handling" : 1,
"solver": {
"monitor_residual": 1,
"solver": "BICGSTAB",
"convergence": "RELATIVE_INI_CORE",
"preconditioner": {
"solver": "NOSOLVER"
}
}
})
Examples of more complex configurations can be found
`here <https://github.com/NVIDIA/AMGX/tree/master/core/configs>`_,
and a description of all configuration settings can be found in the
AMGX Reference Guide.

The :py:meth:`~pyamgx.Config.create_from_file` method can be used
to read configuration settings from a JSON file instead:

.. code-block:: python
cfg = pyamgx.Config()
cfg.create_from_file('/path/to/GMRES.json')
After use, :py:class:`~pyamgx.Config` objects **must** be destroyed using the
:py:meth:`~pyamgx.Config.destroy` method.

.. code-block:: python
cfg.destroy()
Resources objects
-----------------

:py:class:`~pyamgx.Resources` objects are used to specify the resources
(GPUs, MPI ranks) used by :py:class:`~pyamgx.Vector`, :py:class:`~pyamgx.Matrix`
and :py:class:`~pyamgx.Solver` objects.
Currently, pyamgx only supports "simple" :py:class:`~pyamgx.Resources` objects for
single threaded, single GPU applications.
created using the :py:meth:`~pyamgx.Resources.create_simple` method:

.. code-block:: python
resources = pyamgx.Resources()
resources.create_simple(cfg)
After use, :py:class:`~pyamgx.Resources` objects **must** be destroyed using the
:py:meth:`~pyamgx.Resources.destroy` method.

.. code-block:: python
resources.destroy()
.. important::

A :py:class:`~pyamgx.Resources` object should be destroyed only **after**
all :py:class:`~pyamgx.Vector`, :py:class:`~pyamgx.Matrix` and :py:class:`~pyamgx.Solver`
objects constructed from it are destroyed.

Vectors
-------

:py:class:`~pyamgx.Vector` objects store vectors on
either the host (CPU memory) or device (GPU memory).

The value of the optional `mode` argument to the :py:meth:`~pyamgx.Vector.create` method
specifies whether the data resides on the host or device.
If it is ``'dDDI'`` (default), the data resides on the device.
If it is ``'hDDI'``, the data resides on the host.

.. code-block:: python
vec = pyamgx.Vector()
vec.create(resources, mode='dDDI')
Values of :py:class:`~pyamgx.Vector` objects can be populated
in the following ways:

1. From an array using the :py:meth:`~pyamgx.Vector.upload` method

.. code-block:: python
vec.upload(np.array([1, 2, 3], dtype=np.float64))
2. Using the :py:meth:`~pyamgx.Vector.set_zero` method

.. code-block:: python
vec.set_zero(5) # implicitly allocates storage for the vector
3. From a raw pointer using the :py:meth:`~pyamgx.Vector.upload_raw` method.
This allows uploading values from arrays already on the GPU,
for instance from :py:class:`numba.cuda.device_array` objects.

.. code-block:: python
import numba.cuda
a = np.array([1, 2, 3], dtype=np.float64)
d_a = numba.cuda.to_device(a, dtype=np.float64))
vec.upload_raw(d_a.device_ctypes_pointer.value, 3) # copies directly from GPU
After use, :py:class:`~pyamgx.Vector` objects **must** be destroyed using the
:py:meth:`~pyamgx.Vector.destroy` method.

Matrices
--------

:py:class:`~pyamgx.Matrix` objects store sparse matrices on
either the host (CPU memory) or device (GPU memory).

The value of the optional `mode` argument to the :py:meth:`~pyamgx.Matrix.create` method
specifies whether the data resides on the host or device.
If it is ``'dDDI'`` (default), the data resides on the device.
If it is ``'hDDI'``, the data resides on the host.

.. code-block:: python
mat = pyamgx.Matrix()
mat.create(resources, mode='dDDI')
:py:class:`~pyamgx.Matrix` objects store matrices
in the `CSR`_ sparse format.

Matrix data can be copied into the :py:class:`~pyamgx.Matrix`
object in the following ways:

1. From the arrays *row_ptrs*, *col_indices* and *data* that define
the CSR matrix, using the :py:meth:`~pyamgx.Matrix.upload` method:

.. code-block:: python
mat.upload(
row_ptrs=np.array([0, 2, 4], dtype=np.int32),
col_indices=np.array([0, 1, 0, 1], dtype=np.int32),
data=np.array([1., 2., 3., 4.], dtype=np.float64))
2. From a :py:class:`scipy.sparse.csr_matrix`,
using the :py:meth:`~pyamgx.Matrix.upload_CSR` method:

.. code-block:: python
import scipy.sparse
M = scipy.sparse.csr_matrix(np.random.rand(5, 5))
mat.upload_CSR(M)
.. _CSR: https://en.wikipedia.org/wiki/Sparse_matrix#Compressed_sparse_row_(CSR,_CRS_or_Yale_format)

After use, :py:class:`~pyamgx.Matrix` objects **must** be destroyed using the
:py:meth:`~pyamgx.Matrix.destroy` method.

Solvers
-------

A :py:class:`~pyamgx.Solver` encapsulates the linear solver specified
in the :py:class:`~pyamgx.Config` object.

The :py:meth:`~pyamgx.Solver.setup` method,
must be called prior to solving a linear system;
it sets the coefficient matrix of the linear system:

.. code-block:: python
solver = pyamgx.Solver()
solver.create(resources, cfg)
solver.setup(mat)
The :py:meth:`~pyamgx.Solver.solve` method solves the linear system.
The two required parameters to :py:meth:`~pyamgx.Solver.solve`
the right hand side :py:class:`~pyamgx.Vector` `b` and
the solution vector :py:class:`~pyamgx.Vector` `x`
respectively.
The optional argument `zero_initial_guess` can be set to ``True`` to specify
that an initial guess of zero is to be used for the solution,
regardless of the values in `x`.

.. code-block:: python
b = pyamgx.Vector().create(resources)
x = pyamgx.Vector().create(resources)
b.upload(np.random.rand(5))
solver.solve(b, x, zero_initial_guess=True)
After use, :py:class:`~pyamgx.Solver` objects **must** be destroyed using the
:py:meth:`~pyamgx.Solver.destroy` method.

Typically, the :py:meth:`pyamgx.Solver.solve` method is called multiple times
(e.g., in a time-stepping simulation loop).
For the case in which the coefficient matrix remains fixed,
the :py:meth:`pyamgx.Solver.setup` method should only be called once
(prior to iteration).

If the coefficient matrix changes
at each iteration (e.g., in a non-linear solver),
the :py:meth:`pyamgx.Solver.setup` method should be called every iteration.
In this case, the :py:meth:`pyamgx.Matrix.replace_coefficients` method
can be used to update the values of the coefficient matrix,
as long as the location of non-zeros in the matrix remains the same.

3 changes: 2 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,8 @@ def __getattr__(cls, name):
'python': ('https://docs.python.org/dev', None),
'numpy': ('https://docs.scipy.org/doc/numpy/', None),
'scipy': ('https://docs.scipy.org/doc/scipy/reference', None),
'matplotlib': ('http://matplotlib.org', None)
'matplotlib': ('http://matplotlib.org', None),
'numba': ('http://numba.pydata.org/numba-doc/latest/', None)
}

# -- Hack for copying manually built pages to _build
Expand Down
81 changes: 81 additions & 0 deletions docs/demo.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
Demo
====

To give you an idea of pyamgx usage,
here is a simple demo program that sets up and solves a linear system
using pyamgx, and compares the result with
:py:func:`scipy.sparse.linalg.spsolve`

.. code-block:: python
import os
import numpy as np
import scipy.sparse as sparse
import scipy.sparse.linalg as splinalg
import pyamgx
pyamgx.initialize()
# Initialize config and resources:
cfg = pyamgx.Config().create_from_dict({
"config_version": 2,
"determinism_flag": 1,
"exception_handling" : 1,
"solver": {
"monitor_residual": 1,
"solver": "BICGSTAB",
"convergence": "RELATIVE_INI_CORE",
"preconditioner": {
"solver": "NOSOLVER"
}
}
})
rsc = pyamgx.Resources().create_simple(cfg)
# Create matrices and vectors:
A = pyamgx.Matrix().create(rsc)
b = pyamgx.Vector().create(rsc)
x = pyamgx.Vector().create(rsc)
# Create solver:
solver = pyamgx.Solver().create(rsc, cfg)
# Upload system:
M = sparse.csr_matrix(np.random.rand(5, 5))
rhs = np.random.rand(5)
sol = np.zeros(5, dtype=np.float64)
A.upload_CSR(M)
b.upload(rhs)
x.upload(sol)
# Setup and solve system:
solver.setup(A)
solver.solve(b, x)
# Download solution
x.download(sol)
print("pyamgx solution: ", sol)
print("scipy solution: ", splinalg.spsolve(M, rhs))
# Clean up:
A.destroy()
x.destroy()
b.destroy()
solver.destroy()
rsc.destroy()
cfg.destroy()
pyamgx.finalize()
::

AMGX version 2.0.0.130-opensource
Built on Jul 6 2018, 12:08:15
Compiled with CUDA Runtime 8.0, using CUDA driver 9.2
pyamgx solution: [-0.90571145 0.85909259 0.54397665 2.02579923 -0.94139638]
scipy solution: [-0.90571145 0.85909259 0.54397665 2.02579923 -0.94139638]
20 changes: 15 additions & 5 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,27 @@ Features
========

* Provides a Pythonic interface to all AMGX C-API functions for solving linear systems on a single GPU
* Allows directly uploading SciPy sparse CSR matrices, NumPy arrays or Numba.
`DeviceArrays <https://numba.pydata.org/numba-doc/dev/cuda/memory.html#device-arrays>`_
to the GPU>
* Solver settings can be provided in JSON files or as ``dict`` objects.
* Error checking and handling: AMGX errors are automatically converted into Python exceptions.
* Allows directly uploading data from
SciPy sparse CSR matrices, NumPy arrays and Numba
`DeviceArrays <http://numba.pydata.org/numba-doc/latest/cuda/memory.html#device-arrays>`_,
among others
* Solver settings can be provided in JSON files or as ``dict`` objects
* Error checking and handling: AMGX errors are automatically converted into Python exceptions

Contents
========

.. include:: toctree.rst

.. note::

This guide provides an overview of the pyamgx library, its classes and functions.
It does not contain information about AMGX algorithms (solvers and preconditioners),
and their configuration. For that, please refer to the
`AMGX Reference Manual`_

.. _AMGX Reference Manual: https://github.com/NVIDIA/AMGX/blob/master/doc/AMGX_Reference.pdf

Indices and tables
==================

Expand Down
Binary file added docs/local/doctrees/basic.doctree
Binary file not shown.
Binary file added docs/local/doctrees/demo.doctree
Binary file not shown.
Binary file modified docs/local/doctrees/environment.pickle
Binary file not shown.
Binary file modified docs/local/doctrees/index.doctree
Binary file not shown.
Binary file modified docs/local/doctrees/quick-start.doctree
Binary file not shown.
Binary file modified docs/local/doctrees/toctree.doctree
Binary file not shown.

0 comments on commit 3b31f04

Please sign in to comment.