# GSLCodeGenerator class

(Shortest import: `from brian2.codegen.generators import GSLCodeGenerator)`

class brian2.codegen.generators.GSL_generator.GSLCodeGenerator(variables, variable_indices, owner, iterate_all, codeobj_class, name, template_name, override_conditional_write=None, allows_scalar_write=False)

  Bases: `object`

  GSL code generator.

  Notes

  Approach is to first let the already existing code generator for a target language do the bulk of the translating from abstract_code to actual code. This generated code is slightly adapted to render it GSL compatible. The most critical part here is that the vector_code that is normally contained in a loop in the ``main()`` is moved to the function ``_GSL_func`` that is sent to the GSL integrator. The variables used in the vector_code are added to a struct named ``dataholder`` and their values are set from the Brian namespace just before the scalar code block.

  Methods

  `add_gsl_variables_as_non_scalar`(diff_vars) | Add _gsl variables as non-scalar.
  `add_meta_variables`(options) |
  `c_data_type`(dtype) | Get string version of object dtype that is attached to Brian variables.
  `diff_var_to_replace`(diff_vars) | Add differential variable-related strings that need to be replaced to go from normal brian to GSL code
  `find_differential_variables`(code) | Find the variables that were tagged _gsl_{var}_f{ind} and return var, ind pairs.
  `find_function_names`() | Return a list of used function names in the self.variables dictionary
  `find_undefined_variables`(statements) | Find identifiers that are not in `self.variables` dictionary.
  `find_used_variables`(statements, other_variables) | Find all the variables used on the right hand side of the given expressions.
  `get_dimension_code`(diff_num) | Generate code for function that sets the dimension of the ODE system.
  `initialize_array`(varname, values) | Initialize a static array with given floating point values.
  `is_constant_and_cpp_standalone`(var_obj) | Check whether self.cpp_standalone and variable is Constant.
  `is_cpp_standalone`() | Check whether we're running with cpp_standalone.
  `make_function_code`(lines) | Add lines of GSL translated vector code to 'non-changing' _GSL_func code.
  `scale_array_code`(diff_vars, method_options) | Return code for definition of `_GSL_scale_array` in generated code.
  `to_replace_vector_vars`(variables_in_vector) | Create dictionary containing key, value pairs with to be replaced text to translate from conventional Brian to GSL.
  `translate`(code, dtype) | Translates an abstract code block into the target language.
  `translate_scalar_code`(code_lines, ...) | Translate scalar code: if calculated variables are used in the vector_code their value is added to the variable in the _dataholder.
  `translate_vector_code`(code_lines, to_replace) | Translate vector code to GSL compatible code by substituting fragments of code.
  `unpack_namespace`(variables_in_vector, ...[, ...]) | Write code that unpacks Brian namespace to cython/cpp namespace.
  `unpack_namespace_single`(var_obj, in_vector, ...) | Writes the code necessary to pull single variable out of the Brian namespace into the generated code.
  `var_init_lhs`(var, type) | Get string version of the left hand side of an initializing expression
  `write_dataholder`(variables_in_vector) | Return string with full code for _dataholder struct.
  `write_dataholder_single`(var_obj) | Return string declaring a single variable in the `_dataholder` struct.
  `yvector_code`(diff_vars) | Generate code for function dealing with GSLs y vector.

  Details

  add_gsl_variables_as_non_scalar(diff_vars)

    Add _gsl variables as non-scalar.

    In `GSLStateUpdater` the differential equation variables are substituted with GSL tags that describe the information needed to translate the conventional Brian code to GSL compatible code. This function tells Brian that the variables that contain these tags should always be vector variables. If we don’t do this, Brian renders the tag-variables as scalar if no vector variables are used in the right hand side of the expression.

    Parameters:

      diff_vars : dict

      > dictionary with variables as keys and differential equation index as value

  add_meta_variables(options)
  c_data_type(dtype)

    Get string version of object dtype that is attached to Brian variables. c pp_generator already has this function, but the Cython generator does not, but we need it for GSL code generation.

  diff_var_to_replace(diff_vars)

    Add differential variable-related strings that need to be replaced to go from normal brian to GSL code

    From the code generated by Brian’s ‘normal’ generators (cpp_generator or cython_generator a few bits of text need to be replaced to get GSL compatible code. The bits of text related to differential equation variables are put in the replacer dictionary in this function.

    Parameters:

      diff_vars : dict

      > dictionary with variables as keys and differential equation index as value

    Returns:

      to_replace : dict

      > dictionary with strings that need to be replaced as keys and the strings that will replace them as values

  find_differential_variables(code)

    Find the variables that were tagged _gsl_{var}_f{ind} and return var, ind pairs.

    `GSLStateUpdater` tagged differential variables and here we extract the information given in these tags.

    Parameters:

      code : list of strings

      > A list of strings containing gsl tagged variables

    Returns:

      diff_vars : dict

      > A dictionary with variable names as keys and differential equation index as value

  find_function_names()

    Return a list of used function names in the self.variables dictionary

    Functions need to be ignored in the GSL translation process, because the brian generator already sufficiently dealt with them. However, the brian generator also removes them from the variables dict, so there is no way to check whether an identifier is a function after the brian translation process. This function is called before this translation process and the list of function names is stored to be used in the GSL translation.

    Returns:

      function_names : list

      > list of strings that are function names used in the code

  find_undefined_variables(statements)

    Find identifiers that are not in `self.variables` dictionary.

    Brian does not save the `_lio_` variables it uses anywhere. This is problematic for our GSL implementation because we save the lio variables in the `_dataholder` struct (for which we need the datatype of the variables). This function adds the left hand side variables that are used in the vector code to the variable dictionary as `AuxiliaryVariable`s (all we need later is the datatype).

    Parameters:

      statements : list

      > list of statement objects (need to have the dtype attribute)

    Notes

    I keep `self.variables` and `other_variables` separate so I can distinguish what variables are in the Brian namespace and which ones are defined in the code itself.

  find_used_variables(statements, other_variables)

    Find all the variables used on the right hand side of the given expressions.

    Parameters:

      statements : list

      > list of statement objects

    Returns:

      used_variables : dict

      > dictionary of variables that are used as variable name (str), `Variable` pairs.

  get_dimension_code(diff_num)

    Generate code for function that sets the dimension of the ODE system.

    GSL needs to know how many differential variables there are in the ODE system. Since the current approach is to have the code in the vector loop the same for all simulations, this dimension is set by an external function. The code for this set_dimension functon is written here. It is assumed the code will be the same for each target language with the exception of some syntactical differences

    Parameters:

      diff_num : int

      > Number of differential variables that describe the ODE system

    Returns:

      set_dimension_code : str

      > The code describing the target language function in a single string

  initialize_array(varname, values)

    Initialize a static array with given floating point values. E.g. in C++, when called with arguments `array` and `[1.0, 3.0, 2.0]`, this method should return `double array[] = {1.0, 3.0, 2.0}`.

    Parameters:

      varname : str

      > The name of the array variable that should be initialized

      values : list of float

      > The values that should be assigned to the array

    Returns:

      code : str

      > One or more lines of array initialization code.

  is_constant_and_cpp_standalone(var_obj)

    Check whether self.cpp_standalone and variable is Constant.

    This check is needed because in the case of using the cpp_standalone device we do not want to apply our GSL variable conversion (var –> _GSL_dataholder.var), because the cpp_standalone code generation process involves replacing constants with their actual value (‘freezing’). This results in code that looks like (if for example var = 1.2): _GSL_dataholder.1.2 = 1.2 and _GSL_dataholder->1.2. To prevent repetitive calls to get_device() etc. the outcome of is_cpp_standalone is saved.

    Parameters:

      var_obj : `Variable`

      > instance of brian Variable class describing the variable

    Returns:

      is_cpp_standalone : bool

      > whether the used device is cpp_standalone and the given variable is an instance of Constant

  is_cpp_standalone()

    Check whether we’re running with cpp_standalone.

    Test if `get_device()` is instance `CPPStandaloneDevice`.

    Returns:

      is_cpp_standalone : bool

      > whether currently using cpp_standalone device

    See also

    `is_constant_and_cpp_standalone`

      uses the returned value

  make_function_code(lines)

    Add lines of GSL translated vector code to ‘non-changing’ _GSL_func code.

    Adds nonchanging aspects of GSL _GSL_func code to lines of code written somewhere else (`translate_vector_code`). Here these lines are put between the non-changing parts of the code and the target-language specific syntax is added.

    Parameters:

      lines : str

      > Code containing GSL version of equations

    Returns:

      function_code : str

      > code describing `_GSL_func` that is sent to GSL integrator.

  scale_array_code(diff_vars, method_options)

    Return code for definition of `_GSL_scale_array` in generated code.

    Parameters:

      diff_vars : dict

      > dictionary with variable name (str) as key and differential variable index (int) as value

      method_options : dict

      > dictionary containing integrator settings

    Returns:

      code : str

      > full code describing a function returning a array containing doubles with the absolute errors for each differential variable (according to their assigned index in the GSL StateUpdater)

  to_replace_vector_vars(variables_in_vector, ignore=frozenset({}))

    Create dictionary containing key, value pairs with to be replaced text to translate from conventional Brian to GSL.

    Parameters:

      variables_in_vector : dict

      > dictionary with variable name (str), `Variable` pairs of variables occurring in vector code

      ignore : set, optional

      > set of strings with variable names that should be ignored

    Returns:

      to_replace : dict

      > dictionary with strings that need to be replaced i.e. _lio_1 will be _GSL_dataholder._lio_1 (in cython) or _GSL_dataholder->_lio_1 (cpp)

    Notes

    t will always be added because GSL defines its own t. i.e. for cpp: {‘const t = _ptr_array_defaultclock_t[0];’ : ‘’}

  translate(code, dtype)

    Translates an abstract code block into the target language.

  translate_scalar_code(code_lines, variables_in_scalar, variables_in_vector)

    Translate scalar code: if calculated variables are used in the vector_code their value is added to the variable in the _dataholder.

    Parameters:

      code_lines : list

      > list of strings containing scalar code

      variables_in_vector : dict

      > dictionary with variable name (str), `Variable` pairs of variables occurring in vector code

      variables_in_scalar : dict

      > dictionary with variable name (str), `Variable` pairs of variables occurring in scalar code

    Returns:

      scalar_code : str

      > code fragment that should be injected in the main before the loop

  translate_vector_code(code_lines, to_replace)

    Translate vector code to GSL compatible code by substituting fragments of code.

    Parameters:

      code_lines : list

      > list of strings describing the vector_code

      to_replace: dict :

      > dictionary with to be replaced strings (see to_replace_vector_vars and to_replace_diff_vars)

    Returns:

      vector_code : str

      > New code that is now to be added to the function that is sent to the GSL integrator

  unpack_namespace(variables_in_vector, variables_in_scalar, ignore=frozenset({}))

    Write code that unpacks Brian namespace to cython/cpp namespace.

    For vector code this means putting variables in _dataholder (i.e. _GSL_dataholder->var or _GSL_dataholder.var = …) Note that code is written so a variable could occur both in scalar and vector code

    Parameters:

      variables_in_vector : dict

      > dictionary with variable name (str), `Variable` pairs of variables occurring in vector code

      variables_in_scalar : dict

      > dictionary with variable name (str), `Variable` pairs of variables

      >   occurring in scalar code

      ignore : set, optional

      > set of string names of variables that should be ignored

    Returns:

      unpack_namespace_code : str

      > code fragment unpacking the Brian namespace (setting variables in the _dataholder struct in case of vector)

  unpack_namespace_single(var_obj, in_vector, in_scalar)

    Writes the code necessary to pull single variable out of the Brian namespace into the generated code.

    The code created is significantly different between cpp and cython, so I decided to not make this function general over all target languages (i.e. in contrast to most other functions that only have syntactical differences)

  var_init_lhs(var, type)

    Get string version of the left hand side of an initializing expression

    Parameters:

      var : str

      type : str

    Returns:

      code : str

      > For cpp returns type + var, while for cython just var

  write_dataholder(variables_in_vector)

    Return string with full code for _dataholder struct.

    Parameters:

      variables_in_vector : dict

      > dictionary containing variable name as key and `Variable` as value

    Returns:

      code : str

      > code for _dataholder struct

  write_dataholder_single(var_obj)

    Return string declaring a single variable in the `_dataholder` struct.

    Parameters:

      var_obj : `Variable`

    Returns:

      code : str

      > string describing this variable object as required for the `_dataholder` struct (e.g. `double* _array_neurongroup_v`)

  yvector_code(diff_vars)

    Generate code for function dealing with GSLs y vector.

    The values of differential variables have to be transferred from Brian’s namespace to a vector that is given to GSL. The transferring from Brian –> y and back from y –> Brian after integration happens in separate functions. The code for these is written here.

    Parameters:

      diff_vars : dictionary

      > Dictionary containing variable names as keys (str) and differential variable index as value

    Returns:

      yvector_code : str

      > The code for the two functions (`_fill_y_vector` and `_empty_y_vector`) as single string.