提交 54160cd1 authored 作者: Iban Harlouchet's avatar Iban Harlouchet

numpydoc for theano/gof/type.py

上级 4289537c
"""WRITEME Defines the `Type` class.""" """
WRITEME
Defines the `Type` class.
"""
from theano.compat import PY3 from theano.compat import PY3
from six import string_types from six import string_types
...@@ -15,7 +20,8 @@ __docformat__ = "restructuredtext en" ...@@ -15,7 +20,8 @@ __docformat__ = "restructuredtext en"
class CLinkerType(CLinkerObject): class CLinkerType(CLinkerObject):
"""Interface specification for Types that can be arguments to a `CLinkerOp`. """
Interface specification for Types that can be arguments to a `CLinkerOp`.
A CLinkerType instance is mainly reponsible for providing the C code that A CLinkerType instance is mainly reponsible for providing the C code that
interfaces python objects with a C `CLinkerOp` implementation. interfaces python objects with a C `CLinkerOp` implementation.
...@@ -25,84 +31,101 @@ class CLinkerType(CLinkerObject): ...@@ -25,84 +31,101 @@ class CLinkerType(CLinkerObject):
""" """
def c_is_simple(self): def c_is_simple(self):
"""Optional: Return True for small or builtin C types. """
Optional: Return True for small or builtin C types.
A hint to tell the compiler that this type is a builtin C type or a A hint to tell the compiler that this type is a builtin C type or a
small struct and that its memory footprint is negligible. Simple small struct and that its memory footprint is negligible. Simple
objects may be passed on the stack. objects may be passed on the stack.
""" """
return False return False
def c_literal(self, data): def c_literal(self, data):
"""Optional: WRITEME """
Optional: WRITEME
:Parameters: Parameters
- `data`: WRITEME ----------
data : WRITEME
WRITEME WRITEME
:Exceptions: Raises
- `MethodNotDefined`: Subclass does not implement this method ------
MethodNotDefined
Subclass does not implement this method.
""" """
raise MethodNotDefined("c_literal", type(self), raise MethodNotDefined("c_literal", type(self),
self.__class__.__name__) self.__class__.__name__)
def c_declare(self, name, sub, check_input=True): def c_declare(self, name, sub, check_input=True):
"""Required: Return c code to declare variables that will be """
Required: Return c code to declare variables that will be
instantiated by `c_extract`. instantiated by `c_extract`.
Example: Parameters
.. code-block: python ----------
name: str
return "PyObject ** addr_of_%(name)s;" The name of the ``PyObject *`` pointer that will
:param name: the name of the ``PyObject *`` pointer that will
the value for this Type the value for this Type
sub: dict string -> string
a dictionary of special codes. Most importantly
sub['fail']. See CLinker for more info on `sub` and ``fail``.
:type name: string Notes
-----
It is important to include the `name` inside of variables which
are declared here, so that name collisions do not occur in the
source file that is generated.
:param sub: a dictionary of special codes. Most importantly The variable called ``name`` is not necessarily defined yet
sub['fail']. See CLinker for more info on `sub` and ``fail``. where this code is inserted. This code might be inserted to
create class variables for example, whereas the variable ``name``
might only exist inside certain functions in that class.
:type sub: dict string -> string TODO: Why should variable declaration fail? Is it even allowed to?
:note: It is important to include the `name` inside of variables which Raises
are declared here, so that name collisions do not occur in the ------
source file that is generated. MethodNotDefined
Subclass does not implement this method.
:note: The variable called ``name`` is not necessarily defined yet Examples
where this code is inserted. This code might be inserted to --------
create class variables for example, whereas the variable ``name`` .. code-block: python
might only exist inside certain functions in that class.
:todo: Why should variable declaration fail? Is it even allowed to? return "PyObject ** addr_of_%(name)s;"
:Exceptions:
- `MethodNotDefined`: Subclass does not implement this method
""" """
raise MethodNotDefined() raise MethodNotDefined()
def c_init(self, name, sub): def c_init(self, name, sub):
"""Required: Return c code to initialize the variables that were declared by """
self.c_declare() Required: Return c code to initialize the variables that were declared
by self.c_declare().
Notes
-----
The variable called ``name`` is not necessarily defined yet
where this code is inserted. This code might be inserted in a
class constructor for example, whereas the variable ``name``
might only exist inside certain functions in that class.
TODO: Why should variable initialization fail? Is it even allowed to?
Example: Examples
--------
.. code-block: python .. code-block: python
return "addr_of_%(name)s = NULL;" return "addr_of_%(name)s = NULL;"
:note: The variable called ``name`` is not necessarily defined yet
where this code is inserted. This code might be inserted in a
class constructor for example, whereas the variable ``name``
might only exist inside certain functions in that class.
:todo: Why should variable initialization fail? Is it even allowed to?
""" """
raise MethodNotDefined("c_init", type(self), self.__class__.__name__) raise MethodNotDefined("c_init", type(self), self.__class__.__name__)
def c_extract(self, name, sub, check_input=True): def c_extract(self, name, sub, check_input=True):
"""Required: Return c code to extract a PyObject * instance. """
Required: Return c code to extract a PyObject * instance.
The code returned from this function must be templated using The code returned from this function must be templated using
``%(name)s``, representing the name that the caller wants to ``%(name)s``, representing the name that the caller wants to
...@@ -112,11 +135,25 @@ class CLinkerType(CLinkerObject): ...@@ -112,11 +135,25 @@ class CLinkerType(CLinkerObject):
of py_%(name)s. If the data is improper, set an appropriate of py_%(name)s. If the data is improper, set an appropriate
exception and insert "%(fail)s". exception and insert "%(fail)s".
:todo: Point out that template filling (via sub) is now performed TODO: Point out that template filling (via sub) is now performed
by this function. --jpt by this function. --jpt
Parameters
----------
name : str
The name of the ``PyObject *`` pointer that will
store the value for this Type.
sub : dict string -> string
A dictionary of special codes. Most importantly
sub['fail']. See CLinker for more info on `sub` and ``fail``.
Example: Raises
------
MethodNotDefined
Subclass does not implement this method.
Examples
--------
.. code-block: python .. code-block: python
return "if (py_%(name)s == Py_None)" + \\\ return "if (py_%(name)s == Py_None)" + \\\
...@@ -125,29 +162,17 @@ class CLinkerType(CLinkerObject): ...@@ -125,29 +162,17 @@ class CLinkerType(CLinkerObject):
{ PyErr_SetString(PyExc_ValueError, \\\ { PyErr_SetString(PyExc_ValueError, \\\
'was expecting None'); %(fail)s;}" 'was expecting None'); %(fail)s;}"
:param name: the name of the ``PyObject *`` pointer that will
store the value for this Type
:type name: string
:param sub: a dictionary of special codes. Most importantly
sub['fail']. See CLinker for more info on `sub` and ``fail``.
:type sub: dict string -> string
:Exceptions:
- `MethodNotDefined`: Subclass does not implement this method
""" """
raise MethodNotDefined("c_extract", type(self), raise MethodNotDefined("c_extract", type(self),
self.__class__.__name__) self.__class__.__name__)
def c_extract_out(self, name, sub, check_input=True): def c_extract_out(self, name, sub, check_input=True):
"""Optional: C code to extract a PyObject * instance. """
Optional: C code to extract a PyObject * instance.
Unlike c_extract, c_extract_out has to accept Py_None, Unlike c_extract, c_extract_out has to accept Py_None,
meaning that the variable should be left uninitialized. meaning that the variable should be left uninitialized.
""" """
return """ return """
if (py_%(name)s == Py_None) if (py_%(name)s == Py_None)
...@@ -164,7 +189,8 @@ class CLinkerType(CLinkerObject): ...@@ -164,7 +189,8 @@ class CLinkerType(CLinkerObject):
c_extract_code=self.c_extract(name, sub, check_input)) c_extract_code=self.c_extract(name, sub, check_input))
def c_cleanup(self, name, sub): def c_cleanup(self, name, sub):
"""Return c code to clean up after `c_extract`. """
Return C code to clean up after `c_extract`.
This returns C code that should deallocate whatever `c_extract` This returns C code that should deallocate whatever `c_extract`
allocated or decrease the reference counts. Do not decrease allocated or decrease the reference counts. Do not decrease
...@@ -172,55 +198,64 @@ class CLinkerType(CLinkerObject): ...@@ -172,55 +198,64 @@ class CLinkerType(CLinkerObject):
WRITEME WRITEME
:Parameters: Parameters
- `name`: WRITEME ----------
name : WRITEME
WRITEME WRITEME
- `sub`: WRITEME sub : WRITEME
WRITEME WRITEME
:Exceptions: Raises
- `MethodNotDefined`: Subclass does not implement this method ------
MethodNotDefined
Subclass does not implement this method.
""" """
raise MethodNotDefined() raise MethodNotDefined()
def c_sync(self, name, sub): def c_sync(self, name, sub):
"""Required: Return c code to pack C types back into a PyObject. """
Required: Return C code to pack C types back into a PyObject.
The code returned from this function must be templated using The code returned from this function must be templated using
"%(name)s", representing the name that the caller wants to "%(name)s", representing the name that the caller wants to
call this Variable. The returned code may set "py_%(name)s" call this Variable. The returned code may set "py_%(name)s"
to a PyObject* and that PyObject* will be accessible from to a PyObject* and that PyObject* will be accessible from
Python via variable.data. Do not forget to adjust reference Python via variable.data. Do not forget to adjust reference
counts if "py_%(name)s" is changed from its original value. counts if "py_%(name)s" is changed from its original value.
:Parameters: Parameters
- `name`: WRITEME ----------
name : WRITEME
WRITEME WRITEME
- `sub`: WRITEME sub : WRITEME
WRITEME WRITEME
:Exceptions: Raises
- `MethodNotDefined`: Subclass does not implement this method ------
MethodNotDefined
Subclass does not implement this method.
""" """
raise MethodNotDefined("c_sync", type(self), self.__class__.__name__) raise MethodNotDefined("c_sync", type(self), self.__class__.__name__)
def c_code_cache_version(self): def c_code_cache_version(self):
"""Return a tuple of integers indicating the version of this Type. """
Return a tuple of integers indicating the version of this Type.
An empty tuple indicates an 'unversioned' Type that will not An empty tuple indicates an 'unversioned' Type that will not
be cached between processes. be cached between processes.
The cache mechanism may erase cached modules that have been The cache mechanism may erase cached modules that have been
superceded by newer versions. See `ModuleCache` for details. superceded by newer versions. See `ModuleCache` for details.
""" """
return () return ()
class PureType(object): class PureType(object):
"""Interface specification for variable type instances. """
Interface specification for variable type instances.
A :term:`Type` instance is mainly reponsible for two things: A :term:`Type` instance is mainly reponsible for two things:
...@@ -228,8 +263,10 @@ class PureType(object): ...@@ -228,8 +263,10 @@ class PureType(object):
- filtering a value assigned to a `Variable` so that the value - filtering a value assigned to a `Variable` so that the value
conforms to restrictions imposed by the type (also known as conforms to restrictions imposed by the type (also known as
casting, this is done by `filter`), casting, this is done by `filter`).
""" """
# the type that will be created by call to make_variable. # the type that will be created by call to make_variable.
Variable = graph.Variable Variable = graph.Variable
...@@ -237,7 +274,8 @@ class PureType(object): ...@@ -237,7 +274,8 @@ class PureType(object):
Constant = graph.Constant Constant = graph.Constant
def filter(self, data, strict=False, allow_downcast=None): def filter(self, data, strict=False, allow_downcast=None):
"""Required: Return data or an appropriately wrapped/converted data. """
Required: Return data or an appropriately wrapped/converted data.
Subclass implementation should raise a TypeError exception if Subclass implementation should raise a TypeError exception if
the data is not of an acceptable type. the data is not of an acceptable type.
...@@ -250,8 +288,10 @@ class PureType(object): ...@@ -250,8 +288,10 @@ class PureType(object):
Type-dependent, but for now it means only Python floats can be Type-dependent, but for now it means only Python floats can be
downcasted, and only to floatX scalars. downcasted, and only to floatX scalars.
:Exceptions: Raises
- `MethodNotDefined`: subclass doesn't implement this function. ------
MethodNotDefined
Subclass doesn't implement this function.
""" """
raise MethodNotDefined("filter", type(self), self.__class__.__name__) raise MethodNotDefined("filter", type(self), self.__class__.__name__)
...@@ -264,13 +304,15 @@ class PureType(object): ...@@ -264,13 +304,15 @@ class PureType(object):
# def filter_inplace(value, storage, strict=False, allow_downcast=None) # def filter_inplace(value, storage, strict=False, allow_downcast=None)
def filter_variable(self, other, allow_convert=True): def filter_variable(self, other, allow_convert=True):
"""Convert a symbolic variable into this Type, if compatible. """
Convert a symbolic variable into this Type, if compatible.
For the moment, the only Types compatible with one another are For the moment, the only Types compatible with one another are
TensorType and CudaNdarrayType, provided they have the same TensorType and CudaNdarrayType, provided they have the same
number of dimensions, same broadcasting pattern, and same dtype. number of dimensions, same broadcasting pattern, and same dtype.
If Types are not compatible, a TypeError should be raised. If Types are not compatible, a TypeError should be raised.
""" """
if not isinstance(other, graph.Variable): if not isinstance(other, graph.Variable):
# The value is not a Variable: we cast it into # The value is not a Variable: we cast it into
...@@ -291,7 +333,8 @@ class PureType(object): ...@@ -291,7 +333,8 @@ class PureType(object):
return other return other
def convert_variable(self, var): def convert_variable(self, var):
"""Patch variable so that its type will match self, if possible. """
Patch variable so that its type will match self, if possible.
If the variable can't be converted, this should return None. If the variable can't be converted, this should return None.
...@@ -305,12 +348,16 @@ class PureType(object): ...@@ -305,12 +348,16 @@ class PureType(object):
inverse. inverse.
The default is to not convert anything which is always safe. The default is to not convert anything which is always safe.
""" """
return None return None
def is_valid_value(self, a): def is_valid_value(self, a):
"""Required: Return True for any python object `a` that would be a """
legal value for a Variable of this Type""" Required: Return True for any python object `a` that would be a
legal value for a Variable of this Type.
"""
try: try:
self.filter(a, strict=True) self.filter(a, strict=True)
return True return True
...@@ -318,15 +365,20 @@ legal value for a Variable of this Type""" ...@@ -318,15 +365,20 @@ legal value for a Variable of this Type"""
return False return False
def value_validity_msg(self, a): def value_validity_msg(self, a):
"""Optional: return a message explaining the output of """
is_valid_value""" Optional: Return a message explaining the output of
is_valid_value.
"""
return "none" return "none"
def make_variable(self, name=None): def make_variable(self, name=None):
"""Return a new `Variable` instance of Type `self`. """
Return a new `Variable` instance of Type `self`.
:Parameters: Parameters
- `name`: None or str ----------
name : None or str
A pretty string for printing and debugging. A pretty string for printing and debugging.
""" """
...@@ -336,10 +388,12 @@ is_valid_value""" ...@@ -336,10 +388,12 @@ is_valid_value"""
return self.Constant(type=self, data=value, name=name) return self.Constant(type=self, data=value, name=name)
def __call__(self, name=None): def __call__(self, name=None):
"""Return a new `Variable` instance of Type `self`. """
Return a new `Variable` instance of Type `self`.
:Parameters: Parameters
- `name`: None or str ----------
name : None or str
A pretty string for printing and debugging. A pretty string for printing and debugging.
""" """
...@@ -350,6 +404,7 @@ is_valid_value""" ...@@ -350,6 +404,7 @@ is_valid_value"""
Return True if a and b can be considered exactly equal. Return True if a and b can be considered exactly equal.
a and b are assumed to be valid values of this Type. a and b are assumed to be valid values of this Type.
""" """
return a == b return a == b
...@@ -357,29 +412,38 @@ is_valid_value""" ...@@ -357,29 +412,38 @@ is_valid_value"""
""" """
Return True if a and b can be considered approximately equal. Return True if a and b can be considered approximately equal.
:param a: a potential value for a Variable of this Type.
:param b: a potential value for a Variable of this Type.
:rtype: Bool
This function is used by theano debugging tools to decide This function is used by theano debugging tools to decide
whether two values are equivalent, admitting a certain amount whether two values are equivalent, admitting a certain amount
of numerical instability. For example, for floating-point of numerical instability. For example, for floating-point
numbers this function should be an approximate comparison. numbers this function should be an approximate comparison.
By default, this does an exact comparison. By default, this does an exact comparison.
Parameters
----------
a
A potential value for a Variable of this Type.
b
A potential value for a Variable of this Type.
Returns
-------
bool
""" """
return self.values_eq(a, b) return self.values_eq(a, b)
# def get_shape_info(self, obj): # def get_shape_info(self, obj):
""" """
Optional function. See TensorType().get_shape_info for definition Optional function. See TensorType().get_shape_info for definition.
""" """
# def get_size(self, shape_info): # def get_size(self, shape_info):
""" """
Optional function. See TensorType().get_size for definition Optional function. See TensorType().get_size for definition.
""" """
_nothing = """ _nothing = """
...@@ -387,7 +451,8 @@ _nothing = """ ...@@ -387,7 +451,8 @@ _nothing = """
class Type(object2, PureType, CLinkerType): class Type(object2, PureType, CLinkerType):
"""Convenience wrapper combining `PureType` and `CLinkerType`. """
Convenience wrapper combining `PureType` and `CLinkerType`.
Theano comes with several subclasses of such as: Theano comes with several subclasses of such as:
...@@ -399,8 +464,8 @@ class Type(object2, PureType, CLinkerType): ...@@ -399,8 +464,8 @@ class Type(object2, PureType, CLinkerType):
But you are encouraged to write your own, as described in WRITEME. But you are encouraged to write your own, as described in WRITEME.
The following following code illustrates the use of a Type The following code illustrates the use of a Type instance,
instance, here tensor.fvector: here tensor.fvector:
.. code-block:: python .. code-block:: python
...@@ -411,7 +476,7 @@ class Type(object2, PureType, CLinkerType): ...@@ -411,7 +476,7 @@ class Type(object2, PureType, CLinkerType):
c = tensor.fvector() c = tensor.fvector()
Whenever you create a symbolic variable in theano (technically, Whenever you create a symbolic variable in theano (technically,
`Variable`) it will contain a reference to a Type instance. That `Variable`) it will contain a reference to a Type instance. That
reference is typically constant during the lifetime of the reference is typically constant during the lifetime of the
Variable. Many variables can refer to a single Type instance, as Variable. Many variables can refer to a single Type instance, as
do b and c above. The Type instance defines the kind of value do b and c above. The Type instance defines the kind of value
...@@ -430,10 +495,13 @@ class Type(object2, PureType, CLinkerType): ...@@ -430,10 +495,13 @@ class Type(object2, PureType, CLinkerType):
class SingletonType(Type): class SingletonType(Type):
"""Convenient Base class for a Type subclass with no attributes """
Convenient Base class for a Type subclass with no attributes.
It saves having to implement __eq__ and __hash__.
It saves having to implement __eq__ and __hash__
""" """
__instance = None __instance = None
def __new__(cls): def __new__(cls):
...@@ -473,6 +541,7 @@ class Generic(SingletonType): ...@@ -473,6 +541,7 @@ class Generic(SingletonType):
EXAMPLE of what this means, or when you would use this type. EXAMPLE of what this means, or when you would use this type.
WRITEME WRITEME
""" """
def filter(self, data, strict=False, allow_downcast=None): def filter(self, data, strict=False, allow_downcast=None):
...@@ -523,7 +592,20 @@ class CDataType(Type): ...@@ -523,7 +592,20 @@ class CDataType(Type):
""" """
Represents opaque C data to be passed around. The intent is to Represents opaque C data to be passed around. The intent is to
ease passing arbitrary data between ops C code. ease passing arbitrary data between ops C code.
The constructor builds a type made to represent a C pointer in theano.
Parameters
----------
ctype
The type of the pointer (complete with the `*`).
freefunc
A function to call to free the pointer. This function must have a `void`
return and take a single pointer argument.
""" """
import ctypes import ctypes
if PY3: if PY3:
_cdata_type = ctypes.py_object.from_address( _cdata_type = ctypes.py_object.from_address(
...@@ -534,15 +616,6 @@ class CDataType(Type): ...@@ -534,15 +616,6 @@ class CDataType(Type):
del ctypes del ctypes
def __init__(self, ctype, freefunc=None): def __init__(self, ctype, freefunc=None):
"""
Build a type made to represent a C pointer in theano.
:param ctype: The type of the pointer (complete with the `*`)
:param freefunc: a function to call to free the pointer. This
function must have a `void` return and take a
single pointer argument.
"""
assert isinstance(ctype, string_types) assert isinstance(ctype, string_types)
self.ctype = ctype self.ctype = ctype
if freefunc is not None: if freefunc is not None:
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论