diff --git a/.ci-support/fix-code-for-docs.sh b/.ci-support/fix-code-for-docs.sh new file mode 100755 index 0000000000000000000000000000000000000000..7d6da022e787ef34d092ff9cba5a74e4cf3b5915 --- /dev/null +++ b/.ci-support/fix-code-for-docs.sh @@ -0,0 +1,2 @@ +#! /bin/bash +sed -i "s/Dict\[str, DataInterface\]/Dict/" pytato/codegen.py diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ea72e3a1b8926360f9f0ec1f683cc937b5b428b0..cb8d11e97b9af10c5b4771664b409150514d82ec 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -64,10 +64,9 @@ Mypy: Documentation: script: - - EXTRA_INSTALL="sphinx-autodoc-typehints" + - EXTRA_INSTALL="pyopencl" - curl -L -O -k https://gitlab.tiker.net/inducer/ci-support/raw/master/build-docs.sh + - ./.ci-support/fix-code-for-docs.sh - ". ./build-docs.sh" tags: - python3 - only: - - master diff --git a/doc/conf.py b/doc/conf.py index 96130ca4a3b32adc496db9cbae054a3e773b6749..5a61a6cecd67a1764725678072623f440345b427 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -31,9 +31,10 @@ extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.intersphinx', 'sphinx.ext.mathjax', - 'sphinx_autodoc_typehints', ] +autoclass_content = "class" + # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -55,15 +56,15 @@ html_theme = 'alabaster' html_static_path = [] intersphinx_mapping = { - 'http://docs.python.org/': None, - 'http://documen.tician.de/boxtree/': None, - 'http://docs.scipy.org/doc/numpy/': None, - 'http://documen.tician.de/meshmode/': None, - 'http://documen.tician.de/modepy/': None, - 'http://documen.tician.de/pyopencl/': None, - 'http://documen.tician.de/pytools/': None, - 'http://documen.tician.de/pymbolic/': None, - 'http://documen.tician.de/loopy/': None, - 'http://documen.tician.de/sumpy/': None, - 'http://documen.tician.de/islpy/': None, + 'https://docs.python.org/3/': None, + 'https://numpy.org/doc/stable/': None, + 'https://documen.tician.de/boxtree/': None, + 'https://documen.tician.de/meshmode/': None, + 'https://documen.tician.de/modepy/': None, + 'https://documen.tician.de/pyopencl/': None, + 'https://documen.tician.de/pytools/': None, + 'https://documen.tician.de/pymbolic/': None, + 'https://documen.tician.de/loopy/': None, + 'https://documen.tician.de/sumpy/': None, + 'https://documen.tician.de/islpy/': None, } diff --git a/doc/design.rst b/doc/design.rst index 5114de67c23f18365d7bee7aba5deb54b94b1402..a569511ec98e9971a8b358a3821d76e66c8ae81e 100644 --- a/doc/design.rst +++ b/doc/design.rst @@ -71,7 +71,7 @@ Naming - There is (for now) one :class:`~Namespace` per computation "universe" that defines the computational "environment", by mapping :term:`identifier`\ s to :term:`array expression`\ s (note: :class:`DictOfNamedArrays` instances may not be named, but their constituent - parts can, by using :class:`AttributeLookup`). + parts can, by using :class:`pytato.array.AttributeLookup`). Operations involving array expressions not using the same namespace are prohibited. - Names in the :class:`~Namespace` are under user control and unique. I.e. @@ -95,7 +95,7 @@ Naming A[(A > 0).tagged(CountNamed("mycount"))] -- :class:`Placeholder` expressions, like all array expressions, +- :class:`pytato.array.Placeholder` expressions, like all array expressions, are considered read-only. When computation begins, the same actual memory may be supplied for multiple :term:`placeholder name`\ s, i.e. those arrays may alias. @@ -135,7 +135,7 @@ Reserved Identifiers - Identifiers matching the regular expression ``_in[0-9]+``. They are used as automatically generated names (if required) in - :attr:`IndexLambda.bindings`. + :attr:`pytato.array.IndexLambda.bindings`. Glossary ======== @@ -158,6 +158,6 @@ Glossary in a :class:`Namespace`. placeholder name - See :attr:`Placeholder.name`. + See :attr:`pytato.array.Placeholder.name`. .. vim: shiftwidth=4 diff --git a/doc/misc.rst b/doc/misc.rst index c6ab9702dfebe1a3e902994148917b30b4dd5840..5c6a7d0878e3e98a36ce6a8af9cbc461ba236ced 100644 --- a/doc/misc.rst +++ b/doc/misc.rst @@ -26,3 +26,33 @@ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +Cross-References for Other Documentation +======================================== +.. class:: ellipsis + + The type of the Python-builtin :data:`Ellipsis` object. (not otherwise + documented) + +.. currentmodule:: loopy.kernel + +.. class:: LoopKernel + + See :class:`loopy.LoopKernel`. + +.. currentmodule:: loopy.options + +.. class:: Options + + See :class:`loopy.Options`. + +.. currentmodule:: loopy.kernel.data + +.. class:: TemporaryVariable + + See :class:`loopy.TemporaryVariable`. + +.. currentmodule:: islpy._isl + +.. class:: BasicSet + + See :class:`islpy.BasicSet`. diff --git a/doc/reference.rst b/doc/reference.rst index 581f7b65b204ba8f2a1736ddc8d75d82e484ee34..5ee32af6b25683fcf743649f5027c4ad395d58ca 100644 --- a/doc/reference.rst +++ b/doc/reference.rst @@ -1,6 +1,8 @@ Reference ========= +.. module:: pytato + .. automodule:: pytato.array .. automodule:: pytato.scalar_expr .. automodule:: pytato.transform diff --git a/pytato/array.py b/pytato/array.py index 42070f5098e21facd7ddf7d550771cb6f84f4ee1..be55c4ecbd00cea69749bdb56738aae23a228b04 100644 --- a/pytato/array.py +++ b/pytato/array.py @@ -73,6 +73,7 @@ Pre-Defined Tags ---------------- .. autoclass:: ImplementAs +.. autoclass:: ImplementationStrategy .. autoclass:: CountNamed .. autoclass:: ImplStored .. autoclass:: ImplInlined @@ -86,6 +87,7 @@ Built-in Expression Nodes .. autoclass:: MatrixProduct .. autoclass:: LoopyFunction .. autoclass:: Stack +.. autoclass:: AttributeLookup Index Remapping ^^^^^^^^^^^^^^^ @@ -108,7 +110,7 @@ User-Facing Node Creation ------------------------- Node constructors such as :class:`Placeholder.__init__` and -:class:`DictOfNamedArrays.__init__` offer limited input validation +:class:`~pytato.DictOfNamedArrays.__init__` offer limited input validation (in favor of faster execution). Node creation from outside :mod:`pytato` should use the following interfaces: @@ -118,6 +120,33 @@ Node constructors such as :class:`Placeholder.__init__` and .. autofunction:: make_placeholder .. autofunction:: make_size_param .. autofunction:: make_data_wrapper + +Aliases +------- + +(This section exists because Sphinx, our documentation tool, can't (yet) +canonicalize type references. Once Sphinx 4.0 is released, we should use the +``:canonical:`` option here.) + +.. class:: Namespace + + Should be referenced as :class:`pytato.Namespace`. + +.. class:: DottedName + + Should be referenced as :class:`pytato.DottedName`. + +.. class:: Tag + + Should be referenced as :class:`pytato.Tag`. + +.. class:: Array + + Should be referenced as :class:`pytato.Array`. + +.. class:: DictOfNamedArrays + + Should be referenced as :class:`pytato.DictOfNamedArrays`. """ # }}} @@ -200,8 +229,8 @@ class Namespace(Mapping[str, "Array"]): r""" Represents a mapping from :term:`identifier` strings to :term:`array expression`\ s or *None*, where *None* indicates that the name - may not be used. (:class:`Placeholder` instances register their names in - this way to avoid ambiguity.) + may not be used. (:class:`pytato.array.Placeholder` instances register + their names in this way to avoid ambiguity.) .. attribute:: name_gen .. automethod:: __contains__ @@ -290,6 +319,8 @@ class Tag: of the form ``dotted.name(attr1=value1, attr2=value2)``. Positional arguments are not allowed. + .. automethod:: __repr__ + .. note:: This mirrors the tagging scheme that :mod:`loopy` @@ -419,7 +450,7 @@ class Array: .. attribute:: shape - Identifiers (:class:`pymbolic.Variable`) refer to names from + Identifiers (:class:`pymbolic.primitives.Variable`) refer to names from :attr:`namespace`. A tuple of integers or :mod:`pymbolic` expressions. Shape may be (at most affinely) symbolic in these identifiers. @@ -427,7 +458,8 @@ class Array: .. note:: Affine-ness is mainly required by code generation for - :class:`IndexLambda`, but :class:`IndexLambda` is used to produce + :class:`~pytato.array.IndexLambda`, but + :class:`~pytato.array.IndexLambda` is used to produce references to named arrays. Since any array that needs to be referenced in this way needs to obey this restriction anyway, a decision was made to requir the same of *all* array expressions. @@ -796,10 +828,11 @@ class DictOfNamedArrays(Mapping[str, Array]): to instances of :class:`Array`. May occur as a result type of array computations. - .. method:: __contains__ - .. method:: __getitem__ - .. method:: __iter__ - .. method:: __len__ + .. automethod:: __init__ + .. automethod:: __contains__ + .. automethod:: __getitem__ + .. automethod:: __iter__ + .. automethod:: __len__ .. note:: @@ -833,6 +866,8 @@ class DictOfNamedArrays(Mapping[str, Array]): class IndexLambda(_SuppliedShapeAndDtypeMixin, Array): """ + .. attribute:: namespace + .. attribute:: expr A scalar-valued :mod:`pymbolic` expression such as @@ -1021,13 +1056,25 @@ class Stack(Array): # }}} +# {{{ attribute lookup + +class AttributeLookup(Array): + """An expression node to extract an array from a :class:`DictOfNamedArrays`. + + .. warning:: + + Not yet implemented. + """ + pass + + # {{{ index remapping class IndexRemappingBase(Array): """Base class for operations that remap the indices of an array. Note that index remappings can also be expressed via - :class:`~pytato.IndexLambda`. + :class:`~pytato.array.IndexLambda`. .. attribute:: array @@ -1267,6 +1314,9 @@ class DataWrapper(InputArgumentBase): class Placeholder(_SuppliedShapeAndDtypeMixin, InputArgumentBase): r"""A named placeholder for an array whose concrete value is supplied by the user during evaluation. + + .. attribute:: name + .. automethod:: __init__ """ _mapper_method = "map_placeholder" @@ -1277,6 +1327,9 @@ class Placeholder(_SuppliedShapeAndDtypeMixin, InputArgumentBase): shape: ShapeType, dtype: np.dtype, tags: Optional[TagsType] = None): + """Should not be called directly. Use :func:`make_placeholder` + instead. + """ super().__init__(shape=shape, dtype=dtype, namespace=namespace, diff --git a/pytato/codegen.py b/pytato/codegen.py index a55b669aed17a6f86aa9d0c5adaba44bfc91a584..496b1766bea9d02a88f9f3920eab3490b69dd534 100644 --- a/pytato/codegen.py +++ b/pytato/codegen.py @@ -47,6 +47,17 @@ from pytato.transform import Mapper, CopyMapper __doc__ = """ +References +---------- + +.. class:: DictOfNamedArrays + + Should be referenced as :class:`pytato.DictOfNamedArrays`. + +.. class:: DataInterface + + Should be referenced as :class:`pytato.array.DataInterface`. + Generating Code --------------- @@ -78,8 +89,9 @@ Code Generation Internals .. autofunction:: rename_reductions .. autofunction:: normalize_outputs .. autofunction:: get_initial_codegen_state -.. autofunction:: preprocess +.. autoclass:: PreprocessResult +.. autofunction:: preprocess """ diff --git a/pytato/program.py b/pytato/program.py index ded19094ad9db8fff75ce722b7a5aacc37777e32..e2e2c867667665094e5d3bcddbec679b27d108cc 100644 --- a/pytato/program.py +++ b/pytato/program.py @@ -40,8 +40,8 @@ from typing import Any, Mapping, Optional if typing.TYPE_CHECKING: # Imports skipped for efficiency. FIXME: Neither of these work as type # stubs are not present. Types are here only as documentation. - import pyopencl as cl - import loopy as lp + import pyopencl + import loopy # Imports skipped to avoid circular dependencies. import pytato.target @@ -65,7 +65,7 @@ class BoundProgram: .. automethod:: __call__ """ - program: "lp.LoopKernel" + program: "loopy.LoopKernel" bound_arguments: Mapping[str, Any] target: "pytato.target.Target" @@ -83,7 +83,7 @@ class BoundPyOpenCLProgram(BoundProgram): .. automethod:: __call__ """ - queue: Optional["cl.CommandQueue"] + queue: Optional["pyopencl.CommandQueue"] def __call__(self, *args: Any, **kwargs: Any) -> Any: """Convenience function for launching a :mod:`pyopencl` computation.""" diff --git a/pytato/target.py b/pytato/target.py index 0242c0d07475fe4dad1e6f394c00a660ad170358..72e819b66e6390af0fb2e9f14a875e5ca39e63b8 100644 --- a/pytato/target.py +++ b/pytato/target.py @@ -32,17 +32,12 @@ Code Generation Targets .. autoclass:: PyOpenCLTarget """ -import typing from typing import Any, Mapping, Optional from pytato.program import BoundProgram, BoundPyOpenCLProgram - -if typing.TYPE_CHECKING: - # Skip imports for efficiency. FIXME: Neither of these work as type stubs - # are not present. Types are here only as documentation. - import pyopencl as cl - import loopy as lp +import pyopencl +import loopy class Target: @@ -52,11 +47,11 @@ class Target: .. automethod:: bind_program """ - def get_loopy_target(self) -> "lp.TargetBase": + def get_loopy_target(self) -> "loopy.TargetBase": """Return the corresponding :mod:`loopy` target.""" raise NotImplementedError - def bind_program(self, program: "lp.LoopKernel", + def bind_program(self, program: "loopy.LoopKernel", bound_arguments: Mapping[str, Any]) -> BoundProgram: """Create a :class:`pytato.program.BoundProgram` for this code generation target. @@ -74,17 +69,17 @@ class PyOpenCLTarget(Target): The :mod:`pyopencl` command queue, or *None*. """ - def __init__(self, queue: Optional["cl.CommandQueue"] = None): + def __init__(self, queue: Optional["pyopencl.CommandQueue"] = None): self.queue = queue - def get_loopy_target(self) -> "lp.PyOpenCLTarget": + def get_loopy_target(self) -> "loopy.PyOpenCLTarget": import loopy as lp device = None if self.queue is not None: device = self.queue.device return lp.PyOpenCLTarget(device) - def bind_program(self, program: "lp.LoopKernel", + def bind_program(self, program: "loopy.LoopKernel", bound_arguments: Mapping[str, Any]) -> BoundProgram: return BoundPyOpenCLProgram(program=program, queue=self.queue,