def perform(self, node, inputs, output_storage): """ Required: Calculate the function on the inputs and put the variables in the output storage. Return None. :Parameters: `node` : Apply instance contains the symbolic inputs and outputs `inputs` : list sequence of inputs (immutable) `output_storage` : list list of mutable 1-element lists (do not change the length of these lists) The `output_storage` list might contain data. If an element of output_storage is not None, it has to be of the right type, for instance, for a TensorVariable, it has to be a Numpy ndarray, with the right number of dimensions, and the correct dtype. Its shape and stride pattern, can be arbitrary. It not is guaranteed that it was produced by a previous call to impl. It could be allocated by another Op impl is free to reuse it as it sees fit, or to discard it and allocate new memory. :Exceptions: - `MethodNotDefined`: the subclass does not override this method """ raise utils.MethodNotDefined("perform", type(self), self.__class__.__name__)
def make_all(self, profiler, input_storage, output_storage): # By convention, subclasses of LocalLinker should implement this function! # # This function should return a tuple of 5 things # 1. function to run the program # 2. input storage # 3. output storage # 4. thunks: list of nodes' functions in the order they will be run by the function in (1) # 5. order: list of nodes, in the order they will be run by the function in (1) raise utils.MethodNotDefined("make_all", type(self), self.__class__.__name__)
def make_node(self, *inputs): """ Required: return an Apply instance representing the application of this Op to the provided inputs. All subclasses should over-ride this function. :Exceptions: - `MethodNotDefined`: the subclass does not override this method """ raise utils.MethodNotDefined("make_node", type(self), self.__class__.__name__)
def c_support_code(self): """Optional: Return utility code for use by a `Variable` or `Op` to be included at global scope prior to the rest of the code for this class. QUESTION: How many times will this support code be emitted for a graph with many instances of the same type? :Exceptions: - `MethodNotDefined`: Subclass does not implement this method """ raise utils.MethodNotDefined("c_support_code", type(self), self.__class__.__name__)
def c_compile_args(self): """Optional: Return a list of compile args recommended to compile the code returned by other methods in this class. Example: return ['-ffast-math'] Compiler arguments related to headers, libraries and search paths should be provided via the functions `c_headers`, `c_libraries`, `c_header_dirs`, and `c_lib_dirs`. :Exceptions: - `MethodNotDefined`: Subclass does not implement this method """ raise utils.MethodNotDefined("c_compile_args", type(self), self.__class__.__name__)
def transform(self, node): """Transform a subgraph whose output is `node`. Subclasses should implement this function so that it returns one of two kinds of things: - False to indicate that no optimization can be applied to this `node`; or - <list of variables> to use in place of `node`'s outputs in the greater graph. :type node: an Apply instance """ raise utils.MethodNotDefined("transform", type(self), self.__class__.__name__)
def c_support_code_apply(self, node, name): """Optional: Return utility code for use by an `Op` that will be inserted at global scope, that can be specialized for the support of a particular `Apply` node. :param node: an Apply instance in the graph being compiled :param node_id: a string or number that serves to uniquely identify this node. Symbol names defined by this support code should include the node_id, so that they can be called from the c_code, and so that they do not cause name collisions. :Exceptions: - `MethodNotDefined`: Subclass does not implement this method """ raise utils.MethodNotDefined("c_support_code_apply", type(self), self.__class__.__name__)
def c_lib_dirs(self): """Optional: Return a list of library search paths required by code returned by this class. For example: return ['/usr/local/lib', '/opt/weirdpath/build/libs']. Provide search paths for libraries, in addition to those in any relevant environment variables (e.g. LD_LIBRARY_PATH). Hint: for unix compilers, these are the things that get '-L' prefixed in the compiler cmdline. :Exceptions: - `MethodNotDefined`: Subclass does not implement this method """ raise utils.MethodNotDefined("c_lib_dirs", type(self), self.__class__.__name__)
def c_libraries(self): """Optional: Return a list of libraries required by code returned by this class. For example: return ['gsl', 'gslcblas', 'm', 'fftw3', 'g2c']. The compiler will search the directories specified by the environment variable LD_LIBRARY_PATH in addition to any returned by `c_lib_dirs`. Hint: for unix compilers, these are the things that get '-l' prefixed in the compiler cmdline. :Exceptions: - `MethodNotDefined`: Subclass does not implement this method """ raise utils.MethodNotDefined("c_libraries", type(self), self.__class__.__name__)
def c_header_dirs(self): """Optional: Return a list of header search paths required by code returned by this class. For example: return ['/usr/local/include', '/opt/weirdpath/src/include']. Provide search paths for headers, in addition to those in any relevant environment variables. Hint: for unix compilers, these are the things that get '-I' prefixed in the compiler cmdline. :Exceptions: - `MethodNotDefined`: Subclass does not implement this method """ raise utils.MethodNotDefined("c_header_dirs", type(self), self.__class__.__name__)
def c_headers(self): """Optional: Return a list of header files required by code returned by this class. For example: return ['<iostream>', '<math.h>', '/full/path/to/header.h'] These strings will be prefixed with "#include " and inserted at the beginning of the c source code. Strings in this list that start neither with '<' nor '"' will be enclosed in double-quotes. :Exceptions: - `MethodNotDefined`: Subclass does not implement this method """ raise utils.MethodNotDefined("c_headers", type(self), self.__class__.__name__)
def c_no_compile_args(self): """Optional: Return a list of incompatible gcc compiler arguments. We will remove those arguments from the command line of gcc. So if another Op adds a compile arg in the graph that is incompatible with this Op, the incompatible arg will not be used. Useful for instance to remove -ffast-math. EXAMPLE WRITEME :Exceptions: - `MethodNotDefined`: the subclass does not override this method """ raise utils.MethodNotDefined("c_no_compile_args", type(self), self.__class__.__name__)
def make_thunk(self): """ This function must return a triplet (function, input_variables, output_variables) where function is a thunk that operates on the returned variables. If inplace is True, the input_variables and output_variables lists will be the same as the inputs and outputs of the graph provided to the L{Linker}. Else, independent variables will be returned. Example:: x, y = Variable(Double), Variable(Double) e = x + y env = Env([x, y], [e]) fn, (new_x, new_y), (new_e, ) = MyLinker(env).make_thunk(inplace) new_x.data = 1.0 new_y.data = 2.0 fn() print new_e.data # 3.0 print e.data # 3.0 iff inplace == True (else unknown) """ raise utils.MethodNotDefined("make_thunk", type(self), self.__class__.__name__)
def c_code_cleanup(self, node, name, inputs, outputs, sub): """Optional: Return C code to run after c_code, whether it failed or not. QUESTION: is this function optional? This is a convenient place to clean up things allocated by c_code(). :Parameters: `node` : Apply instance WRITEME `name` : WRITEME WRITEME `inputs` : list of strings There is a string for each input of the function, and the string is the name of a C `PyObject` variable pointing to that input. `outputs` : list of strings Each string is the name of a `PyObject` pointer where the Op should store its variables. This pointer could be NULL, or contain an object of the right Type (in the Theano sense) to store the output of the computation. For instance, for a TensorVariable, it will be a Numpy ndarray with the right number of dimensions, and the right dtype. However, its shape, or stride pattern, could not be adequate. It could be unchanged from the end of the previous execution, or allocated by another Op, or by the Mode. `sub` : dict of strings extra symbols defined in `CLinker` sub symbols (such as 'fail'). WRITEME WRITEME :Exceptions: - `MethodNotDefined`: the subclass does not override this method """ raise utils.MethodNotDefined('%s.c_code_cleanup' \ % self.__class__.__name__)
def c_code(self, node, name, inputs, outputs, sub): """Required: Return the C implementation of an Op. Returns C code that does the computation associated to this `Op`, given names for the inputs and outputs. :Parameters: `node` : Apply instance WRITEME `name` : WRITEME WRITEME `inputs` : list of strings There is a string for each input of the function, and the string is the name of a C `PyObject` variable pointing to that input. `outputs` : list of strings Each string is the name of a `PyObject` pointer where the Op should store its variables. As of version 0.4.0, this pointer could be NULL, or contain an object allocated during a previous call to the same function, unchanged from the end of the previous execution. In a future version, there will be no guarantee on where that object will be created (it could be allocated during a previous execution, or by another Op, by the Mode, etc.). It will still be of an appropriate Type (in the Theano sense) to store the output of the computation: for instance, for a TensorVariable, it will be a Numpy ndarray with the right number of dimensions, and the right dtype. However, its shape, or stride pattern, could not be adequate. `sub` : dict of strings extra symbols defined in `CLinker` sub symbols (such as 'fail'). WRITEME :Exceptions: - `MethodNotDefined`: the subclass does not override this method """ raise utils.MethodNotDefined('%s.c_code' \ % self.__class__.__name__)