Skip to content

Commit

Permalink
RANDOM construct: support for NEURON {RANDOM ranvar1, ranvar2, ...} s…
Browse files Browse the repository at this point in the history
…tatement (#1125)

* Support for new RANDOM construct in NMODL, see neuronsimulator/nrn#2627
* Added necessary changes to the parser, visitors, symbol table and code generation
* Added unit tests

Co-authored-by: Pramod S Kumbhar <[email protected]>
  • Loading branch information
nrnhines and pramodk authored Feb 8, 2024
1 parent 9b8aa63 commit 8f7eb99
Show file tree
Hide file tree
Showing 23 changed files with 354 additions and 12 deletions.
23 changes: 23 additions & 0 deletions src/codegen/codegen_coreneuron_cpp_visitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1259,6 +1259,15 @@ void CodegenCoreneuronCppVisitor::print_first_pointer_var_index_getter() {
}


void CodegenCoreneuronCppVisitor::print_first_random_var_index_getter() {
printer->add_newline(2);
print_device_method_annotation();
printer->push_block("static inline int first_random_var_index()");
printer->fmt_line("return {};", info.first_random_var_index);
printer->pop_block();
}


void CodegenCoreneuronCppVisitor::print_num_variable_getter() {
printer->add_newline(2);
print_device_method_annotation();
Expand Down Expand Up @@ -2293,6 +2302,19 @@ void CodegenCoreneuronCppVisitor::print_instance_variable_setup() {
printer->fmt_push_block("static void {}(NrnThread* nt, Memb_list* ml, int type)",
method_name(naming::NRN_PRIVATE_DESTRUCTOR_METHOD));
cast_inst_and_assert_validity();

// delete random streams
if (info.random_variables.size()) {
printer->add_line("int pnodecount = ml->_nodecount_padded;");
printer->add_line("int nodecount = ml->nodecount;");
printer->add_line("Datum* indexes = ml->pdata;");
printer->push_block("for (int id = 0; id < nodecount; id++)");
for (const auto& var: info.random_variables) {
const auto& name = get_variable_name(var->get_name());
printer->fmt_line("nrnran123_deletestream((nrnran123_State*){});", name);
}
printer->pop_block();
}
print_instance_struct_delete_from_device();
printer->add_multi_line(R"CODE(
delete inst;
Expand Down Expand Up @@ -3561,6 +3583,7 @@ void CodegenCoreneuronCppVisitor::print_namespace_end() {

void CodegenCoreneuronCppVisitor::print_common_getters() {
print_first_pointer_var_index_getter();
print_first_random_var_index_getter();
print_net_receive_arg_size_getter();
print_thread_getters();
print_num_variable_getter();
Expand Down
7 changes: 7 additions & 0 deletions src/codegen/codegen_coreneuron_cpp_visitor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,13 @@ class CodegenCoreneuronCppVisitor: public CodegenCppVisitor {
void print_first_pointer_var_index_getter();


/**
* Print the getter method for index position of first RANDOM variable
*
*/
void print_first_random_var_index_getter();


/**
* Print the getter methods for float and integer variables count
*
Expand Down
38 changes: 36 additions & 2 deletions src/codegen/codegen_cpp_visitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "codegen/codegen_helper_visitor.hpp"
#include "codegen/codegen_utils.hpp"
#include "visitors/rename_visitor.hpp"
#include "visitors/visitor_utils.hpp"

namespace nmodl {
namespace codegen {
Expand Down Expand Up @@ -145,7 +146,6 @@ bool CodegenCppVisitor::defined_method(const std::string& name) const {
return function && function->has_any_property(properties);
}


int CodegenCppVisitor::float_variables_size() const {
return codegen_float_variables.size();
}
Expand Down Expand Up @@ -235,7 +235,20 @@ void CodegenCppVisitor::print_global_var_struct_decl() {

void CodegenCppVisitor::print_function_call(const FunctionCall& node) {
const auto& name = node.get_node_name();
auto function_name = name;

// return C++ function name for RANDOM construct function
// e.g. nrnran123_negexp for random_negexp
auto get_renamed_random_function =
[&](const std::string& name) -> std::pair<std::string, bool> {
if (codegen::naming::RANDOM_FUNCTIONS_MAPPING.count(name)) {
return {codegen::naming::RANDOM_FUNCTIONS_MAPPING[name], true};
}
return {name, false};
};
std::string function_name;
bool is_random_function;
std::tie(function_name, is_random_function) = get_renamed_random_function(name);

if (defined_method(name)) {
function_name = method_name(name);
}
Expand Down Expand Up @@ -265,6 +278,12 @@ void CodegenCppVisitor::print_function_call(const FunctionCall& node) {
}
}

// first argument to random functions need to be type casted
// from void* to nrnran123_State*.
if (is_random_function && !arguments.empty()) {
printer->add_text("(nrnran123_State*)");
}

print_vector_elements(arguments, ", ");
printer->add_text(')');
}
Expand Down Expand Up @@ -684,6 +703,15 @@ void CodegenCppVisitor::update_index_semantics() {
index += size;
}

for (auto& var: info.random_variables) {
if (info.first_random_var_index == -1) {
info.first_random_var_index = index;
}
int size = var->get_length();
info.semantics.emplace_back(index, naming::RANDOM_SEMANTIC, size);
index += size;
}

if (info.diam_used) {
info.semantics.emplace_back(index++, naming::DIAM_VARIABLE, 1);
}
Expand Down Expand Up @@ -863,6 +891,12 @@ std::vector<IndexVariableInfo> CodegenCppVisitor::get_int_variables() {
}
}

for (const auto& var: info.random_variables) {
auto name = var->get_name();
variables.emplace_back(make_symbol(name), true);
variables.back().symbol->add_properties(NmodlType::random_var);
}

if (info.diam_used) {
variables.emplace_back(make_symbol(naming::DIAM_VARIABLE));
}
Expand Down
6 changes: 6 additions & 0 deletions src/codegen/codegen_helper_visitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,12 @@ void CodegenHelperVisitor::find_non_range_variables() {
// clang-format on
info.pointer_variables = psymtab->get_variables_with_properties(properties);

/// find RANDOM variables
// clang-format off
properties = NmodlType::random_var;
// clang-format on
info.random_variables = psymtab->get_variables_with_properties(properties);

// find special variables like diam, area
// clang-format off
properties = NmodlType::assigned_definition
Expand Down
6 changes: 6 additions & 0 deletions src/codegen/codegen_info.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -324,9 +324,15 @@ struct CodegenInfo {
/// pointer or bbcore pointer variables
std::vector<SymbolType> pointer_variables;

/// RANDOM variables
std::vector<SymbolType> random_variables;

/// index/offset for first pointer variable if exist
int first_pointer_var_index = -1;

/// index/offset for first RANDOM variable if exist
int first_random_var_index = -1;

/// tqitem index in integer variables
/// note that if tqitem doesn't exist then the default value should be 0
int tqitem_index = 0;
Expand Down
19 changes: 16 additions & 3 deletions src/codegen/codegen_naming.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@

#pragma once

#include <map>
#include <string>
#include <unordered_map>


namespace nmodl {
Expand Down Expand Up @@ -119,6 +119,9 @@ static constexpr char POINTER_SEMANTIC[] = "pointer";
/// semantic type for core pointer variable
static constexpr char CORE_POINTER_SEMANTIC[] = "bbcorepointer";

/// semantic type for RANDOM variable
static constexpr char RANDOM_SEMANTIC[] = "random";

/// semantic type for net send call
static constexpr char NET_SEND_SEMANTIC[] = "netsend";

Expand Down Expand Up @@ -174,7 +177,7 @@ static constexpr char NRN_POINTERINDEX[] = "hoc_nrnpointerindex";
/// commonly used variables in verbatim block and how they
/// should be mapped to new code generation backends
// clang-format off
const std::map<std::string, std::string> VERBATIM_VARIABLES_MAPPING{
static const std::unordered_map<std::string, std::string> VERBATIM_VARIABLES_MAPPING{
{"_nt", "nt"},
{"_p", "data"},
{"_ppvar", "indexes"},
Expand All @@ -183,8 +186,18 @@ static constexpr char NRN_POINTERINDEX[] = "hoc_nrnpointerindex";
{"_cntml_padded", "pnodecount"},
{"_cntml", "nodecount"},
{"_tqitem", "tqitem"}};
// clang-format on

// Functions available in NMODL with RANDOM construct and their mapping to
// C++ functions for Random123 interface.
static std::unordered_map<std::string, std::string> RANDOM_FUNCTIONS_MAPPING{
{"random_setseq", "nrnran123_setseq"},
{"random_setids", "nrnran123_setids"},
{"random_uniform", "nrnran123_uniform"},
{"random_negexp", "nrnran123_negexp"},
{"random_normal", "nrnran123_normal"},
{"random_ipick", "nrnran123_ipick"},
{"random_dpick", "nrnran123_dblpick"}};
// clang-format on
} // namespace naming
} // namespace codegen
} // namespace nmodl
2 changes: 2 additions & 0 deletions src/language/code_generator.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ set(AST_GENERATED_SOURCES
${PROJECT_BINARY_DIR}/src/ast/procedure_block.hpp
${PROJECT_BINARY_DIR}/src/ast/program.hpp
${PROJECT_BINARY_DIR}/src/ast/protect_statement.hpp
${PROJECT_BINARY_DIR}/src/ast/random_var.hpp
${PROJECT_BINARY_DIR}/src/ast/random_var_list.hpp
${PROJECT_BINARY_DIR}/src/ast/range.hpp
${PROJECT_BINARY_DIR}/src/ast/range_var.hpp
${PROJECT_BINARY_DIR}/src/ast/react_var_name.hpp
Expand Down
30 changes: 29 additions & 1 deletion src/language/nmodl.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,14 @@
type: Name
node_name: true

- RandomVar:
brief: "Single variable of type RANDOM. pointer to a nrnran123_State"
members:
- name:
brief: "Name of the a RANDOM variable"
type: Name
node_name: true

- BbcorePointerVar:
members:
- name:
Expand All @@ -415,7 +423,7 @@
- Block:
brief: "Base class for all block scoped nodes"
description: |
NMODL has different local and global block scoped nodes like
NMODL has different local and globals block scoped nodes like
ast::NeuronBlock, ast::ParamBlock, ast::IfStatement etc. Ast::Block
is base class and defines common interface for these nodes.
Expand Down Expand Up @@ -1731,13 +1739,33 @@
separator: ", "
brief: "Represents GLOBAL statement in NMODL"

- RandomVarList:
brief: "Represents RANDOM statement in NMODL"
nmodl: "RANDOM "
members:
- variables:
brief: "Vector of random variables"
type: RandomVar
vector: true
separator: ", "
description: |
Here is an example of RANDOM statement
\code{.mod}
NEURON {
THREADSAFE
POINT_PROCESS NetStim
RANDOM ranvar
\endcode
- Pointer:
nmodl: "POINTER "
members:
- variables:
brief: "Vector of pointer variables"
type: PointerVar
vector: true
add: true
separator: ", "
brief: "Represents POINTER statement in NMODL"

Expand Down
1 change: 1 addition & 0 deletions src/language/node_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
"GlobalVar",
"PointerVar",
"BbcorePointerVar",
"RandomVar",
"ExternVar",
"PrimeName",
"ConstantVar",
Expand Down
2 changes: 2 additions & 0 deletions src/lexer/nmodl_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,8 @@ SymbolType token_symbol(const std::string& key, PositionType& pos, TokenType typ
return Parser::make_PROCEDURE(token, pos);
case Token::PROTECT:
return Parser::make_PROTECT(token, pos);
case Token::RANDOM:
return Parser::make_RANDOM(token, pos);
case Token::RANGE:
return Parser::make_RANGE(token, pos);
case Token::READ:
Expand Down
1 change: 1 addition & 0 deletions src/lexer/token_mapping.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ const static std::map<std::string, TokenType> keywords = {
{"CHARGE", Token::VALENCE},
{"GLOBAL", Token::GLOBAL},
{"POINTER", Token::POINTER},
{"RANDOM", Token::RANDOM},
{"BBCOREPOINTER", Token::BBCOREPOINTER},
{"EXTERNAL", Token::EXTERNAL},
{"INCLUDE", Token::INCLUDE1},
Expand Down
24 changes: 24 additions & 0 deletions src/parser/nmodl.yy
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@
%token <ModToken> PROCEDURE
%token <ModToken> PROTECT
%token <ModToken> RANGE
%token <ModToken> RANDOM
%token <ModToken> REACT1
%token <ModToken> REACTION
%token <ModToken> READ
Expand Down Expand Up @@ -293,6 +294,7 @@
%type <ast::GlobalVarVector> global_var_list
%type <ast::PointerVarVector> pointer_var_list
%type <ast::BbcorePointerVarVector> bbcore_pointer_var_list
%type <ast::RandomVarVector> random_var_list
%type <ast::ExternVarVector> external_var_list
%type <ast::Valence*> valence
%type <ast::ExpressionStatement*> initial_statement
Expand Down Expand Up @@ -1987,6 +1989,11 @@ neuron_statement :
$1.emplace_back(new ast::BbcorePointer($3));
$$ = $1;
}
| neuron_statement RANDOM random_var_list
{
$1.emplace_back(new ast::RandomVarList($3));
$$ = $1;
}
| neuron_statement EXTERNAL external_var_list
{
$1.emplace_back(new ast::External($3));
Expand Down Expand Up @@ -2195,6 +2202,23 @@ bbcore_pointer_var_list : NAME_PTR
;


random_var_list : NAME_PTR
{
$$ = ast::RandomVarVector();
$$.emplace_back(new ast::RandomVar($1));
}
| random_var_list "," NAME_PTR
{
$1.emplace_back(new ast::RandomVar($3));
$$ = $1;
}
| error
{
error(scanner.loc, "random_var_list");
}
;


external_var_list : NAME_PTR
{
$$ = ast::ExternVarVector();
Expand Down
6 changes: 6 additions & 0 deletions src/symtab/symbol_properties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
*/

#include <string>
#include <unordered_map>
#include <vector>

#include "codegen/codegen_naming.hpp"
#include "symtab/symbol_properties.hpp"
#include "utils/string_utils.hpp"

Expand Down Expand Up @@ -159,6 +161,10 @@ std::vector<std::string> to_string_vector(const NmodlType& obj) {
properties.emplace_back("codegen_var");
}

if (has_property(obj, NmodlType::random_var)) {
properties.emplace_back("random_var");
}

return properties;
}

Expand Down
Loading

0 comments on commit 8f7eb99

Please sign in to comment.