Adding support for new functions

For a description of Brian’s function system from the user point of view, see Functions.

The default functions available in Brian are stored in the DEFAULT_FUNCTIONS dictionary. New Function objects can be added to this dictionary to make them available to all Brian code, independent of its namespace.

To add a new implementation for a code generation target, a FunctionImplementation can be added to the Function.implementations dictionary. The key for this dictionary has to be either a CodeGenerator class object, or a CodeObject class object. The CodeGenerator of a CodeObject (e.g. CPPCodeGenerator for CPPStandaloneCodeObject) is used as a fallback if no implementation specific to the CodeObject class exists.

If a function is already provided for the target language (e.g. it is part of a library imported by default), using the same name, all that is needed is to add an empty FunctionImplementation object to mark the function as implemented. For example, exp is a standard function in C++:

DEFAULT_FUNCTIONS['exp'].implementations[CPPCodeGenerator] = FunctionImplementation()

Some functions are implemented but have a different name in the target language. In this case, the FunctionImplementation object only has to specify the new name:

DEFAULT_FUNCTIONS['arcsin'].implementations[CPPCodeGenerator] = FunctionImplementation('asin')

Finally, the function might not exist in the target language at all, in this case the code for the function has to be provided, the exact form of this code is language-specific. In the case of C++, it’s a dictionary of code blocks:

clip_code = {'support_code': '''
        double _clip(const float value, const float a_min, const float a_max)
                if (value < a_min)
                    return a_min;
                if (value > a_max)
                    return a_max;
                return value;
DEFAULT_FUNCTIONS['clip'].implementations[CPPCodeGenerator] = FunctionImplementation('_clip',