Nemo  2.4.2
Simulate forward-in-time genetic evolution in a spatially explicit, individual-based stochastic simulator
ParamsParser Class Referenceabstract

Provides interface to read input parameters from various sources and parses them. More...

#include <paramsparser.h>

+ Inheritance diagram for ParamsParser:
+ Collaboration diagram for ParamsParser:

Public Member Functions

 ParamsParser (const char *name)
 
virtual ~ParamsParser ()
 
void setName (const char *name)
 
map< string, string > get_inputParams ()
 
map< string, vector< string > > & getParsedParameters (const char *stream_name)
 
map< string, vector< string > > & getParsedParameters ()
 
map< string, string > & getParameters (const char *stream_name)
 
map< string, string > & getParameters ()
 
virtual bool read (const char *stream)=0
 Read/parse params & args from a file or a string or an R object. More...
 
void parse ()
 Builds the _parsedParams from the _inputParams. More...
 
string replaceMacro (const string &arg)
 Macros. More...
 
string parseMacroFunctionBlock (const string &in_arg)
 
string callMacro (const string &name, const string &argstr)
 
string expandMacros (const string &arg)
 Public entry point to expand macros in a string, used to expand macros that were preserved by P() once the random seed has been set (see SimRunner::expandPreservedMacros). More...
 
vector< string > getMacroArgs (const string &args, const int min_arg, const size_t max_arg, const string macro_name, const string syntax, bool lastArgIsSeparatorChar=true)
 
string getMacroSepParamChar (const string &sep_in, const string macro_name)
 
string getMacroParamValue (const string &str_in, const string &par_name, const string &macro_name)
 
string quote (const string &argstr)
 Macro "q" returns a quoted string. More...
 
string concat (const string &argstr)
 Macro "c" returns a character-delimited string of atomic arguments. More...
 
string rep (const string &argstr)
 
string seq (const string &argstr)
 
string tempseq (const string &argstr)
 
string matrix (const string &argstr)
 
string diag_matrix (const string &argstr)
 
string sym_matrix (const string &argstr)
 
string runif (const string &argstr)
 
string rnorm (const string &argstr)
 
string rpoiss (const string &argstr)
 
string rbernoul (const string &argstr)
 
string rgamma (const string &argstr)
 
string rlognorm (const string &argstr)
 
string rexp (const string &argstr)
 
string sample (const string &argstr)
 
string sort (const string &argstr)
 
string round (const string &argstr)
 
string ceiling (const string &argstr)
 
string floor (const string &argstr)
 

Static Public Member Functions

static void getBlockArgument (istream &IN, char &c, string &arg)
 
static void getArguments (string &arg_str, vector< string > &arg_vect)
 

Protected Member Functions

void reset_inputParams ()
 
void add_inputParam (string &param, const string &arg)
 

Static Private Member Functions

static size_t matchClosingParen (const string &s)
 Given a string positioned just after an opening '(', returns the index of the matching closing ')', accounting for nested parentheses. More...
 
static bool containsPreserveMacro (const string &s)
 Returns true if 's' contains a P() preserve-macro call, i.e. More...
 

Private Attributes

bool _hasPreservedMacro = false
 Set true by parseMacroFunctionBlock when a P() preserve-macro is encountered while parsing a parameter value; read and reset per-parameter in parse(). More...
 
const char * _sname
 Attached file of stream name. More...
 
map< string, string > _inputParams
 The whole, unparsed set of input parameters. More...
 
map< string, vector< string > > _parsedParams
 The parsed set of simulation parameters after sequential parameters have been separated. More...
 
map< string, string(ParamsParser::*)(const string &)> _macroMap
 The macro table, mapping call name to caller. More...
 

Detailed Description

Provides interface to read input parameters from various sources and parses them.

Constructor & Destructor Documentation

◆ ParamsParser()

ParamsParser::ParamsParser ( const char *  name)
56 {
57  _sname = name;
58 
59  _macroMap["rep"] = &ParamsParser::rep;
60  _macroMap["seq"] = &ParamsParser::seq;
61  _macroMap["tempseq"] = &ParamsParser::tempseq;
64  _macroMap["runif"] = &ParamsParser::runif;
65  _macroMap["rnorm"] = &ParamsParser::rnorm;
66  _macroMap["rpois"] = &ParamsParser::rpoiss;
67  _macroMap["rlognorm"] = &ParamsParser::rlognorm;
68  _macroMap["rgamma"] = &ParamsParser::rgamma;
69  _macroMap["rbernoul"] = &ParamsParser::rbernoul;
70  _macroMap["rexp"] = &ParamsParser::rexp;
71  _macroMap["matrix"] = &ParamsParser::matrix;
73  _macroMap["smatrix"] = &ParamsParser::sym_matrix;
74  _macroMap["sample"] = &ParamsParser::sample;
75  _macroMap["sort"] = &ParamsParser::sort;
76  _macroMap["round"] = &ParamsParser::round;
77  _macroMap["ceiling"] = &ParamsParser::ceiling;
78  _macroMap["floor"] = &ParamsParser::floor;
79 }
string rexp(const string &argstr)
Definition: paramsparser.cc:1346
string sample(const string &argstr)
Definition: paramsparser.cc:1549
string round(const string &argstr)
Definition: paramsparser.cc:1648
string ceiling(const string &argstr)
Definition: paramsparser.cc:1689
string sort(const string &argstr)
Definition: paramsparser.cc:1606
string rlognorm(const string &argstr)
Definition: paramsparser.cc:1481
string tempseq(const string &argstr)
Definition: paramsparser.cc:787
string rnorm(const string &argstr)
Definition: paramsparser.cc:1154
string matrix(const string &argstr)
Definition: paramsparser.cc:853
const char * _sname
Attached file of stream name.
Definition: paramsparser.h:131
string sym_matrix(const string &argstr)
Definition: paramsparser.cc:986
string concat(const string &argstr)
Macro "c" returns a character-delimited string of atomic arguments.
Definition: paramsparser.cc:599
map< string, string(ParamsParser::*)(const string &)> _macroMap
The macro table, mapping call name to caller.
Definition: paramsparser.h:140
string rbernoul(const string &argstr)
Definition: paramsparser.cc:1287
string seq(const string &argstr)
Definition: paramsparser.cc:725
string runif(const string &argstr)
Definition: paramsparser.cc:1077
string quote(const string &argstr)
Macro "q" returns a quoted string.
Definition: paramsparser.cc:626
string floor(const string &argstr)
Definition: paramsparser.cc:1715
string rep(const string &argstr)
Definition: paramsparser.cc:651
string rpoiss(const string &argstr)
Definition: paramsparser.cc:1228
string rgamma(const string &argstr)
Definition: paramsparser.cc:1405
string diag_matrix(const string &argstr)
Definition: paramsparser.cc:919

References ceiling(), concat(), diag_matrix(), floor(), matrix(), quote(), rbernoul(), rep(), rexp(), rgamma(), rlognorm(), rnorm(), round(), rpoiss(), runif(), sample(), seq(), sort(), sym_matrix(), and tempseq().

◆ ~ParamsParser()

virtual ParamsParser::~ParamsParser ( )
inlinevirtual
58 {}

Member Function Documentation

◆ add_inputParam()

void ParamsParser::add_inputParam ( string &  param,
const string &  arg 
)
inlineprotected
113 {_inputParams[param] = arg;}
map< string, string > _inputParams
The whole, unparsed set of input parameters.
Definition: paramsparser.h:134

Referenced by StreamParser::read().

+ Here is the caller graph for this function:

◆ callMacro()

string ParamsParser::callMacro ( const string &  name,
const string &  argstr 
)
437 {
438  string out;
439 #ifdef _DEBUG_
440  message(" ^^^^ calling macro: %s(%s)\n",name.c_str(), argstr.c_str());
441 #endif
442 
443  auto elmnt = _macroMap.find(name);
444 
445  if( elmnt == _macroMap.end())
446  {
447  fatal("macro \"%s(%s)\" could not be mapped to a known function.\n", name.c_str(), argstr.c_str());
448  }
449 
450  out = (this->*(elmnt->second))(argstr);
451 
452 #ifdef _DEBUG_
453  message(" ^^^^ returning: %s\n",out.c_str());
454 #endif
455 
456  return out;
457 }
void fatal(const char *str,...)
Definition: output.cc:98
void message(const char *message,...)
Definition: output.cc:38

References fatal(), and message().

◆ ceiling()

string ParamsParser::ceiling ( const string &  argstr)
1690 {
1691  string syntax = "ceiling(x, sep=\",\")";
1692 
1693  int max_arg = 2, min_arg = 1;
1694 
1695  vector<string> macro_args = getMacroArgs(argstr, min_arg, max_arg, "ceiling", syntax, true);
1696 
1697  vector<string> elmnts = macro_list(macro_args[0]);
1698 
1699  string sep = macro_args.back();
1700 
1701  string out;
1702  for(size_t i = 0; i < elmnts.size(); ++i) {
1703  if(!tstring::isanumber(elmnts[i]))
1704  fatal("ceiling(): all values must be numbers, received \"%s\" in: ceiling(%s)\n", elmnts[i].c_str(), argstr.c_str());
1705 
1706  out += fmt_number(std::ceil(tstring::str2dble(elmnts[i])), 0);
1707  if(i < elmnts.size() - 1) out += sep;
1708  }
1709 
1710  return out;
1711 }
vector< string > getMacroArgs(const string &args, const int min_arg, const size_t max_arg, const string macro_name, const string syntax, bool lastArgIsSeparatorChar=true)
Definition: paramsparser.cc:461
static double str2dble(const string &str)
Converts a string into a double.
Definition: tstring.h:82
static bool isanumber(const string &str)
Check whether the string is a number.
Definition: tstring.h:408

References fatal(), tstring::isanumber(), and tstring::str2dble().

Referenced by ParamsParser().

+ Here is the caller graph for this function:

◆ concat()

string ParamsParser::concat ( const string &  argstr)

Macro "c" returns a character-delimited string of atomic arguments.

Can be passed as arguments to other macros.

600 {
601 
602  string syntax="c(... , sep=\",\")";
603  string out;
604 
605  size_t max_arg = INT64_MAX;
606 
607  vector<string> macro_args = getMacroArgs(argstr, 2, max_arg, "c", syntax, true);
608 
609  string sep = macro_args.back();
610 
611  int last = macro_args.size() - 2; //omit separator at last position
612 
613  // stick each element together, un-quoting them, if needed
614  for (int i = 0; i < last; ++i) {
615  out += tstring::removeEnclosingChar(macro_args[i], '"', '"', true) + sep;
616  }
617  // add last element without separator
618  out += tstring::removeEnclosingChar(macro_args[last], '"', '"', true);
619 
620 
621  return out;
622 }
static string removeEnclosingChar(const string &str, const char o, const char c, bool allowMissing=false)
Removes characters enclosing a string.
Definition: tstring.h:354

References tstring::removeEnclosingChar().

Referenced by ParamsParser().

+ Here is the caller graph for this function:

◆ containsPreserveMacro()

bool ParamsParser::containsPreserveMacro ( const string &  s)
staticprivate

Returns true if 's' contains a P() preserve-macro call, i.e.

"P(" where 'P' begins a macro name (at the start of the string or right after a macro-name delimiter). Used to reject nested P(), which cannot be expanded correctly.

257 {
258  // a P() macro call is "P(" where 'P' starts a macro name: at the beginning of the string
259  // or right after a macro-name delimiter (same delimiters as parseMacroFunctionBlock).
260  const string delim = "(){}[], =\t";
261  size_t pos = 0;
262  while((pos = s.find("P(", pos)) != string::npos) {
263  if(pos == 0 || delim.find(s[pos-1]) != string::npos) return true;
264  pos += 2;
265  }
266  return false;
267 }

◆ diag_matrix()

string ParamsParser::diag_matrix ( const string &  argstr)
920 {
921  string syntax = "diag(x, n)";
922 
923  int max_arg = 2, min_arg = 1;
924  string out;
925  string off_diag = "0";
926  size_t nrow;
927 
928  vector<string> macro_args = getMacroArgs(argstr, min_arg, max_arg, "diag", syntax, false);
929 
930  // the size is inferred from splitting the string provided
931  vector<string> elmnts = macro_list(macro_args[0]);
932 
933  if( macro_args.size() == 1) {
934 
935  nrow = elmnts.size();
936 
937  } else {
938  // already checked that it's not >2 arguments passed
939 
940  nrow = size_t(tstring::str2uint(macro_args[1]));
941 
942  // the value may contain several elements that might need to be repeated:
943  if(elmnts.size() > 1 && elmnts.size() != nrow) {
944 
945  fatal("diag(): the number of elements to use for the diag matrix is different from parameter \"n\" in: diag(%s)\n\
946  use quoted rep() if you intend to repeat a pattern, eg: diag(q(rep(..., n1)),n2)\n", syntax.c_str());
947 
948  } else if (elmnts.size() == 1){
949 
950  // build the vector of elements used below
951 
952  for(unsigned int i = 0; i < nrow-1; ++i)
953  elmnts.push_back(elmnts[0]);
954  }
955  }
956 
957  out += "{";
958 
959  for (unsigned int r = 0, c, e = 0; r < nrow; ++r) {
960 
961  out += "\n{";
962 
963  for (c = 0; c < nrow - 1 && e < elmnts.size(); ++c) {
964 
965  if(c == r)
966  out += elmnts[e++] + ",";
967  else
968  out += off_diag + ",";
969  }
970 
971  if(c == r)
972  out += elmnts[e++] + "}";
973  else
974  out += off_diag + "}";
975 
976  }
977 
978  // close the matrix block
979  out += "}";
980 
981  return out;
982 }
static unsigned int str2uint(const string &str)
Converts a string into an unsigned integer.
Definition: tstring.h:49

References fatal(), and tstring::str2uint().

Referenced by ParamsParser().

+ Here is the caller graph for this function:

◆ expandMacros()

string ParamsParser::expandMacros ( const string &  arg)
inline

Public entry point to expand macros in a string, used to expand macros that were preserved by P() once the random seed has been set (see SimRunner::expandPreservedMacros).

83 {return replaceMacro(arg);}
string replaceMacro(const string &arg)
Macros.
Definition: paramsparser.cc:271

Referenced by SimRunner::expandPreservedMacros().

+ Here is the caller graph for this function:

◆ floor()

string ParamsParser::floor ( const string &  argstr)
1716 {
1717  string syntax = "floor(x, sep=\",\")";
1718 
1719  int max_arg = 2, min_arg = 1;
1720 
1721  vector<string> macro_args = getMacroArgs(argstr, min_arg, max_arg, "floor", syntax, true);
1722 
1723  vector<string> elmnts = macro_list(macro_args[0]);
1724 
1725  string sep = macro_args.back();
1726 
1727  string out;
1728  for(size_t i = 0; i < elmnts.size(); ++i) {
1729  if(!tstring::isanumber(elmnts[i]))
1730  fatal("floor(): all values must be numbers, received \"%s\" in: floor(%s)\n", elmnts[i].c_str(), argstr.c_str());
1731 
1732  out += fmt_number(std::floor(tstring::str2dble(elmnts[i])), 0);
1733  if(i < elmnts.size() - 1) out += sep;
1734  }
1735 
1736  return out;
1737 }

References fatal(), tstring::isanumber(), and tstring::str2dble().

Referenced by ParamsParser().

+ Here is the caller graph for this function:

◆ get_inputParams()

map< string, string > ParamsParser::get_inputParams ( )
inline
62 {return _inputParams;}

◆ getArguments()

void ParamsParser::getArguments ( string &  arg_str,
vector< string > &  arg_vect 
)
static
184 {
185  istringstream IN;
186  string arg;
187  int dummy_line = 0;
188  char c;
189 
190  IN.str(arg_str);
191 
192  while(IN.get(c) && IN.good() && !IN.eof()){
193 
194  if(isspace(c)) {
195  StreamParser::removeSpaceAndComment(IN, dummy_line);
196  continue;
197  }
198 
199  if(c == '{' || c == '(' || c == '[' || c == '\"')
200  {
201  getBlockArgument(IN, c, arg); //because it may span more than one line
202  }
203  else //not a block argument
204  {
205  IN.putback(c);
206  IN>>arg; //this stops if a whitespace is found, thus not including macro arguments if a macro
207  }
208 
209 
210  arg_vect.push_back( arg );
211  }
212 }
static void getBlockArgument(istream &IN, char &c, string &arg)
Definition: paramsparser.cc:216
static bool removeSpaceAndComment(istream &IN, int &l_count, bool keepLast=false)
Removes whitespace char on a line until a non-ws or EOL is reached.
Definition: paramsparser.cc:1843

References StreamParser::removeSpaceAndComment().

◆ getBlockArgument()

void ParamsParser::getBlockArgument ( istream &  IN,
char &  c,
string &  arg 
)
static
217 {
218  char e = 0;
219  int dummy_line = 0;
220 
221  switch (start_c) {
222  case '{': e = '}';
223  break;
224  case '(': e = ')';
225  break;
226  case '[': e = ']';
227  break;
228  case '\"': e = '\"';
229  break;
230  default:
231  break;
232  }
233 
234  arg = StreamParser::readUntilCharacter(IN, dummy_line, start_c, (const char)e);
235 
236 // cout<<"added arg to vector: "<<out<<" next char='"<<IN.peek()<<"'\n";
237 }
static string readUntilCharacter(istream &IN, int &l_count, const char start_c, const char end_c)
Definition: paramsparser.cc:1993

References StreamParser::readUntilCharacter().

◆ getMacroArgs()

vector< string > ParamsParser::getMacroArgs ( const string &  args,
const int  min_arg,
const size_t  max_arg,
const string  macro_name,
const string  syntax,
bool  lastArgIsSeparatorChar = true 
)
463 {
464 
465 // cout<<" getMacroArgs:: argstr="<<argstr<<endl;
466 
467  vector<string> macro_args = tstring::splitExcludeEnclosedDelimiters(argstr, ',');
468 
469  if(macro_args.size() > max_arg ){
470  fatal("macro \"%s\" can have max %i arguments: %s\n", macro_name.c_str(), max_arg, syntax.c_str());
471  }
472  else if (macro_args.size() < min_arg) {
473  fatal("macro \"%s\" must have at least %i arguments: %s\n", macro_name.c_str(), min_arg, syntax.c_str());
474  }
475 
476  size_t last_arg = macro_args.size() -1;
477 
478  string sep = ","; // default sep
479 
480  // treat the last argument specially if it is a separator char
481  // or add the default separator char to the arg vector if not specified in input
482  if(lastArgIsSeparatorChar) {
483 
484  // make sure it was specified in input
485  if(macro_args.size() > min_arg) {
486  // check if separator is given in arg (we'll assume it is the last arg...)
487  if(argstr.rfind("sep") != string::npos) {
488 
489  // get the separator char from the last character string
490  sep = getMacroSepParamChar(macro_args[ last_arg ], macro_name);
491 
492  macro_args[ last_arg ] = sep; // we replace the string "sep=..." with the char
493 
494  } else
495  macro_args.push_back(sep); //default
496  } else
497  macro_args.push_back(sep); //default
498  }
499 
500 // auto print = [this](const string& s){cout<<" getMacroArgs:: "<<s<<endl;};
501 //
502 // for_each(macro_args.cbegin(), macro_args.cend(), print);
503 
504  return macro_args;
505 }
string getMacroSepParamChar(const string &sep_in, const string macro_name)
Definition: paramsparser.cc:509
static vector< string > splitExcludeEnclosedDelimiters(const string &str, const char delim=',', const string &encloser="([{\"")
Splits a string into substrings (tokens) delimited by a single character.
Definition: tstring.h:153

References fatal(), and tstring::splitExcludeEnclosedDelimiters().

◆ getMacroParamValue()

string ParamsParser::getMacroParamValue ( const string &  str_in,
const string &  par_name,
const string &  macro_name 
)
547 {
548  vector<string> param_args = tstring::splitExcludeEnclosedDelimiters(str_in, '=');
549 
550  if(param_args[0] != par_name)
551  fatal("expected \"%s\" as input param to macro \"%s\", received \"%s\"\n", par_name.c_str(), macro_name.c_str(), str_in.c_str());
552 
553  return param_args[1];
554 }

References fatal(), and tstring::splitExcludeEnclosedDelimiters().

◆ getMacroSepParamChar()

string ParamsParser::getMacroSepParamChar ( const string &  sep_in,
const string  macro_name 
)
510 {
511 
512  if( tstring::isanumber(sep_in))
513  fatal("last argument \"sep\" of macro \"%s\" must be a character string in \"%s\"\n", macro_name.c_str(), sep_in.c_str());
514 
515  vector<string> sep_args = tstring::splitExcludeEnclosedDelimiters(sep_in, '=');
516 
517  string sep;
518 
519  // check format of sep argument specification: sep="c", or "c"
520  if(sep_args.size() == 0)
521  fatal("wrong format of \"sep\" argument to macro \"%s\" in \"%s\"\n", macro_name.c_str(), sep_in.c_str());
522 
523  if(sep_args[0] == "sep") {
524 
525  if(sep_args.size() > 2){
526  fatal("argument \"sep\" of macro \"%s\" must receive only one value in \"%s\" \n", macro_name.c_str(), sep_in.c_str());
527  }
528 
529  sep = sep_args[1];
530 
531  } else {
532  sep = sep_args[0];
533  }
534 
535  if(sep[0] != '"') {
536  fatal("argument to \"sep\" of macro \"%s\" must be enclosed with two \" in \"%s\" \n", macro_name.c_str(), sep_in.c_str());
537  }
538 
539  sep = tstring::removeEnclosingChar(sep, '"', '"');
540 
541  return sep;
542 }

References fatal(), tstring::isanumber(), tstring::removeEnclosingChar(), and tstring::splitExcludeEnclosedDelimiters().

◆ getParameters() [1/2]

map< string, string >& ParamsParser::getParameters ( )
inline
66 {return _inputParams;}

◆ getParameters() [2/2]

map< string, string > & ParamsParser::getParameters ( const char *  stream_name)
84 {
85 #ifdef _DEBUG_
86  cout<<"ParamsParser::getParameters:"<<endl;
87 #endif
88  if(stream_name == NULL) {
89 
90  if(_sname == NULL)
91 
92  fatal("ParamsParser::getParameters::no stream attached to the parser!\n");
93 
94  else if( !(read(_sname)) ) // read the input text stream and extract parameters and their arguments
95 
96  fatal("ParamsParser::getParameters::failed from file \"%s\"\n",_sname);
97 
98  } else if( !(read(stream_name)) ) // read the input text stream and extract parameters and their arguments
99 
100  fatal("ParamsParser::getParameters::failed from file \"%s\"\n",stream_name);
101 
102  if(stream_name != NULL) _sname = stream_name;
103 
104  // pairs of parameter name & values have been recorder in _inputParams map
105  return _inputParams;
106 }
virtual bool read(const char *stream)=0
Read/parse params & args from a file or a string or an R object.

References fatal().

Referenced by BinaryDataLoader::extractPop().

+ Here is the caller graph for this function:

◆ getParsedParameters() [1/2]

map< string, vector< string > >& ParamsParser::getParsedParameters ( )
inline
64 {return _parsedParams;}
map< string, vector< string > > _parsedParams
The parsed set of simulation parameters after sequential parameters have been separated.
Definition: paramsparser.h:137

◆ getParsedParameters() [2/2]

map< string, vector< string > > & ParamsParser::getParsedParameters ( const char *  stream_name)
111 {
112 #ifdef _DEBUG_
113  cout<<"ParamsParser::getParsedParameters:"<<endl;
114 #endif
115  // read the input parameters from the input text stream
116  getParameters(stream_name);
117 
118  // parse the input text stream
119  parse();
120 
121  return _parsedParams;
122 }
map< string, string > & getParameters()
Definition: paramsparser.h:66
void parse()
Builds the _parsedParams from the _inputParams.
Definition: paramsparser.cc:126

Referenced by SimRunner::run().

+ Here is the caller graph for this function:

◆ matchClosingParen()

size_t ParamsParser::matchClosingParen ( const string &  s)
staticprivate

Given a string positioned just after an opening '(', returns the index of the matching closing ')', accounting for nested parentheses.

Returns string::npos if unbalanced. Used to capture the raw argument of a preserved P() macro.

242 {
243  // 's' starts just after an opening '(' (already consumed), so depth starts at 1.
244  int depth = 1;
245  for(size_t i = 0; i < s.size(); ++i) {
246  if(s[i] == '(') depth++;
247  else if(s[i] == ')') {
248  if(--depth == 0) return i;
249  }
250  }
251  return string::npos;
252 }

◆ matrix()

string ParamsParser::matrix ( const string &  argstr)
854 {
855  string syntax = "matrix(x, nrow, ncol, fill_by=row)";
856 
857  int max_arg = 4, min_arg = 3;
858 
859  vector<string> macro_args = getMacroArgs(argstr, min_arg, max_arg, "matrix", syntax, false);
860 
861  if(macro_args[0][0] != '"' && macro_args[0].back() != '"')
862  fatal("matrix(): first argument must be quoted with \" in: matrix(%s)\n",argstr.c_str());
863 
864  vector<string> elmnts = macro_list(macro_args[0]);
865 
866  unsigned int nrow = tstring::str2uint(macro_args[1]);
867  unsigned int ncol = tstring::str2uint(macro_args[2]);
868 
869  if(elmnts.size() < nrow*ncol)
870  fatal("matrix(): not enough elements provided, got %i, must be rows*columns = %i\n", elmnts.size(), nrow*ncol);
871 
872  if(elmnts.size() > nrow*ncol)
873  fatal("matrix(): too many elements provided, got %i, must be rows*columns = %i\n", elmnts.size(), nrow*ncol);
874 
875  // check filling option -------------
876 
877  // ---- looking for the argument ----
878  auto has_fill_by = [] (const string& s) {return (s.find("fill_by=") != string::npos);};
879 
880  auto argPos = find_if(macro_args.begin(), macro_args.end(), has_fill_by);
881 
882  // Initialize fill mode default
883  string fill_mode = "row";
884 
885  if( argPos != macro_args.end() )
886  fill_mode = getMacroParamValue(*argPos, "fill_by", syntax);
887 
888  if (fill_mode != "row" && fill_mode != "col")
889  fatal("matrix(): invalid value for 'fill_by'. Must be 'row' or 'col'. Received: %s\n", fill_mode.c_str());
890 
891  // start writing the matrix into the output string
892  string out("{");
893 
894  for (unsigned int r = 0; r < nrow; ++r) {
895  out += "\n{";
896 
897  for (unsigned int c = 0; c < ncol - 1; ++c) {
898 
899  // Index calculation: e = row * ncol + col
900  size_t e = (size_t)(fill_mode == "row"? r * ncol + c : c * nrow + r);
901 
902  out += elmnts[e] + ",";
903  }
904  // Last element of the row
905  size_t e_last = (size_t)(fill_mode == "row"? r * ncol + (ncol - 1) :
906  (ncol - 1) * nrow + r);
907  out += elmnts[e_last] + "}";
908 
909  }
910 
911  // close the matrix block
912  out += "}";
913 
914  return out;
915 }
string getMacroParamValue(const string &str_in, const string &par_name, const string &macro_name)
Definition: paramsparser.cc:546

References fatal(), and tstring::str2uint().

Referenced by ParamsParser().

+ Here is the caller graph for this function:

◆ parse()

void ParamsParser::parse ( )

Builds the _parsedParams from the _inputParams.

This defines rules of sequential, matricial params, etc.

127 {
128 #ifdef _DEBUG_
129  cout<<"ParamsParser::parse:"<<endl;
130 #endif
131 
132  // empty container map of parameters parsed into key - value(s) pairs
133  _parsedParams.clear();
134 
135  // local holder of the arguments read in the input stream, contains whole lines from input
136  vector< string > argvect;
137  string arg;
138 
139  // go through all parameters previously read in the input text stream and parse param values into multiple values
140  map<string, string>::iterator param = _inputParams.begin();
141 
142  while(param != _inputParams.end()) {
143 
144  // first, check and replace macros:
145  _hasPreservedMacro = false;
146  param->second = replaceMacro(param->second);
147 
148  argvect.clear();
149 
150  if( _hasPreservedMacro ) {
151  // a P() preserve-macro left un-expanded content in this value; it will be expanded
152  // after the random seed has been set (see SimRunner::expandPreservedMacros). Tag the
153  // value and keep it whole: getArguments would split the exposed macro on spaces/commas.
154  argvect.push_back( string(1, MACRO_PRESERVE_TAG) + param->second );
155  }
156  else if((param->first == "stats") || (param->first == "stat") )
157 
158  argvect.push_back(param->second); //this one cannot be a sequential parameter
159 
160  else { //other params:
161 
162  getArguments(param->second, argvect);
163 
164  }
165 
166  _parsedParams[param->first] = argvect;
167 
168 #ifdef _DEBUG_
169  message(" %s (", param->first.c_str());
170  unsigned int nb=argvect.size() ;
171  for(unsigned int i=0 ;i<nb; ++i){
172  cout<<argvect[i]<<" ";
173  }
174  message("| %i args)\n", nb);
175 #endif
176 
177  param++;
178  }
179 }
bool _hasPreservedMacro
Set true by parseMacroFunctionBlock when a P() preserve-macro is encountered while parsing a paramete...
Definition: paramsparser.h:128
static void getArguments(string &arg_str, vector< string > &arg_vect)
Definition: paramsparser.cc:183
#define MACRO_PRESERVE_TAG
Sentinel char prepended to a parameter value whose macro(s) were preserved by the P() macro and must ...
Definition: paramsparser.h:42

References MACRO_PRESERVE_TAG, and message().

◆ parseMacroFunctionBlock()

string ParamsParser::parseMacroFunctionBlock ( const string &  in_arg)
298 {
299  string front, tail, rest, out_arg;
300  string name;
301 
302 // cout<<"parseMacroFunctionBlock <"<< in_arg <<">\n";
303 
304  size_t opar_pos, cpar_pos, first_macro_ch;
305 
306  // extract the name of the macro, first find the opening parenthesis
307  opar_pos = in_arg.find_first_of('(', 1);
308 
309  //cut the string at the opening par to look for the macro name in the front part
310  front = in_arg.substr(0, opar_pos);
311 
312  //cut the string after the opening par to look for macro arguments and more macros in the rest
313  rest = in_arg.substr(opar_pos+1, in_arg.size() - opar_pos - 1);
314 
315  //a macro name can only start after the last delimiter in front of it
316  first_macro_ch = front.find_last_of("(){}[], =\t");
317  // '=' is included because arguments to macros can be named and assigned a call to a nested macro
318  // eg: tempseq(at=seq(),seq=seq())
319 
320  //the open par may not be part of a macro, or there might not be any delim in front, check this:
321  if(first_macro_ch == string::npos)
322  first_macro_ch = 0; // no delim before name, start at first pos in string
323  else
324  first_macro_ch++; //skip the last delimiter
325 
326  // check if we have a macro name in front and extract it
327  if(opar_pos > first_macro_ch)
328  {
329  name = in_arg.substr(first_macro_ch, opar_pos - first_macro_ch);
330  // keep what was in front of the macro name;
331  front = in_arg.substr(0, first_macro_ch);
332  }
333  else // first_macro_ch == opar_pos; no name, no macro, skip
334  { // this corresponds to cases where multiple blocks are provided in input:
335  // param_name (... macro1(...),...) (... macro2(...), ...)
336  // the second block causes problems if we lose the brackets on the way
337 
338  name = "";
339 
340  // keep what was in front of the false macro block, including the opening '(';
341  front = in_arg.substr(0, first_macro_ch+1);
342  }
343 
344  out_arg += front;
345 
346  // P(): preserve the enclosed expression un-expanded. Stochastic macros (rexp, rnorm, ...)
347  // draw from the RNG; expanding them here, at parse time, uses the temporary time-based seed
348  // because the input random_seed is not applied until init_components. P() defers expansion
349  // until after the seed is set (see Param::set and SimRunner::expandPreservedMacros). We strip
350  // the "P( )" wrapper, leave the inner content raw, and keep parsing the tail so that sibling
351  // macros and further P() (e.g. inside temporal "(@g0 P(...), @g10 P(...))" blocks) are handled.
352  if(name == "P")
353  {
354  _hasPreservedMacro = true;
355 
356  size_t pclose = matchClosingParen(rest); // index in 'rest' of P's matching ')'
357 
358  if(pclose == string::npos)
359  fatal("Error while parsing argument string for macros: P() closing bracket not found in \"%s\"\n", rest.c_str());
360 
361  string inner = rest.substr(0, pclose); // raw, un-expanded content of P()
362 
363  // P() cannot be nested: an inner P() would be stripped without expanding its own macros,
364  // silently leaving an un-expanded macro string as the parameter value. Reject it clearly.
365  if( containsPreserveMacro(inner) )
366  fatal("the P() preserve-macro cannot be nested (found a P() inside \"P(%s)\"); "
367  "wrap the whole expression in a single P() instead.\n", inner.c_str());
368 
369  string ptail = rest.substr(pclose + 1); // remainder after P's ')'
370 
371  // still expand any macros located outside (after) the P() block
372  if(ptail.find_first_of('(', 1) != string::npos)
373  ptail = parseMacroFunctionBlock(ptail);
374 
375  out_arg += inner + ptail;
376 
377  return out_arg;
378  }
379  // before reading the arguments of the macro function call, check for nested macros, recursively
380  if(rest.find_first_of('(', 1) != string::npos)
381  {
382  //recursion
383  //replace the macro name by the result of the call to the nested macro in the macro_args vect
384  rest = ( parseMacroFunctionBlock(rest) );
385 
386  }
387  //no more nested block, close recursion and return arguments
388 
389 // cout<< " processing: "<<rest<<endl;
390 
391  // find the limit of the macro args
392  cpar_pos = rest.find_first_of(')');
393 
394  if ( cpar_pos != string::npos)
395  {
396  // record what is left after the macro args, excluding the closing macro ')'
397  if( cpar_pos < rest.size()-1 ){
398 
399  tail = rest.substr(cpar_pos+1, rest.size() - cpar_pos - 1);
400  }
401  else
402  tail = "";
403  }
404  else
405  {
406  fatal("Error while parsing argument string \"%s\" for macros, closing bracket not found\n", (rest+tail).c_str());
407  }
408 
409  rest = rest.substr(0, cpar_pos); // this is the string containing the args to the macro
410 
411  if(name == "")
412  {
413 
414 // cout<< " not calling macro: name =\"\"; arg string is <"<<rest<<">"<<"\n";
415 
416  out_arg += rest +")" + tail; //need to put back the closing ')' because not a macro
417 
418  }
419  else
420  {
421 
422 // cout<< " calling macro: "<<name<<"("<<rest<<")"<<"\n";
423 
424  // call the macro and paste the result into the output string
425  out_arg += callMacro(name, rest) + tail;
426 
427  }
428 
429 // cout<< " returning "<<out_arg<<endl;
430  // return the processed string
431  return out_arg;
432 }
static size_t matchClosingParen(const string &s)
Given a string positioned just after an opening '(', returns the index of the matching closing ')',...
Definition: paramsparser.cc:241
static bool containsPreserveMacro(const string &s)
Returns true if 's' contains a P() preserve-macro call, i.e.
Definition: paramsparser.cc:256
string parseMacroFunctionBlock(const string &in_arg)
Definition: paramsparser.cc:297
string callMacro(const string &name, const string &argstr)
Definition: paramsparser.cc:436

References fatal().

◆ quote()

string ParamsParser::quote ( const string &  argstr)

Macro "q" returns a quoted string.

Useful to quote result of call to enclosed macro.

627 {
628 
629  string syntax="q(... , sep=\",\")";
630  string out;
631 
632  size_t max_arg = INT64_MAX;
633 
634  vector<string> macro_args = getMacroArgs(argstr, 1, max_arg, "q", syntax, true);
635 
636  string sep = macro_args.back();
637 
638  int last = macro_args.size() - 2; //omit separator at last position
639 
640  for (int i = 0; i < last; ++i) {
641  out += macro_args[i] + sep;
642  }
643  // add last element without separator
644  out += macro_args[last];
645 
646  return "\"" + out + "\"";
647 }

Referenced by ParamsParser().

+ Here is the caller graph for this function:

◆ rbernoul()

string ParamsParser::rbernoul ( const string &  argstr)
1288 {
1289  string syntax = "rbernoul(n, p=0.5, sep=\",\")";
1290 
1291  int max_arg = 3, min_arg = 1;
1292  double p = 0.5;
1293  unsigned int num_deviates;
1294 
1295  vector<string> macro_args = getMacroArgs(argstr, min_arg, max_arg, "rbernoul", syntax, true);
1296 
1297  // get and check the number of deviates we need to draw
1298  if(!tstring::isanumber(macro_args[0]))
1299  fatal("rbernoul(): first argument must be a positive integer in: rbernoul(%s)\n", argstr.c_str());
1300 
1301  num_deviates = tstring::str2uint(macro_args[0]);
1302 
1303  if(!(num_deviates > 0))
1304  fatal("rbernoul(): first argument must be a positive integer in: rbernoul(%s)\n", argstr.c_str());
1305 
1306 
1307  // get the mean value, if present
1308  // we omit last arg macro_args[2] which is always the separator character
1309  if(macro_args.size() == 3){
1310 
1311  vector<string> param_args = tstring::splitExcludeEnclosedDelimiters(macro_args[1], '=');
1312 
1313  if(param_args[0] == "p") {
1314 
1315  p = tstring::str2dble(param_args[1]);
1316 
1317  } else if(param_args.size() == 1) {
1318 
1319  // the string "mean=" can be omitted by user
1320 
1321  p = tstring::str2dble(param_args[0]);
1322 
1323  } else {
1324 
1325  fatal("rbernoul() syntax is: %s\n",syntax.c_str());
1326  }
1327  }
1328 
1329  string sep = macro_args.back();
1330 
1331  // compute the random deviates
1332  string out;
1333 
1334  auto draw = [p](){return tstring::int2str(RAND::Bernoulli(p));};
1335 
1336  for(unsigned int i = 0; i < num_deviates -1; ++i)
1337  out += draw() + sep;
1338 
1339  out += draw();
1340 
1341  return out;
1342 }
static double Bernoulli(double p)
Definition: Uniform.h:439
static string int2str(const int i)
Writes an integer value into a string.
Definition: tstring.h:93

References RAND::Bernoulli(), fatal(), tstring::int2str(), tstring::isanumber(), tstring::splitExcludeEnclosedDelimiters(), tstring::str2dble(), and tstring::str2uint().

Referenced by ParamsParser().

+ Here is the caller graph for this function:

◆ read()

virtual bool ParamsParser::read ( const char *  stream)
pure virtual

Read/parse params & args from a file or a string or an R object.

Params and their args are put in the _inputParams.

Implemented in StreamParser, BinaryFileParser, and FileParser.

◆ rep()

string ParamsParser::rep ( const string &  argstr)
652 {
653 
654  string syntax="rep(x, n, each=1, sep=\",\")";
655 
656  int max_arg = 4;
657 
658  vector<string> macro_args = getMacroArgs(argstr, 2, max_arg, "rep", syntax, true);
659 
660 // auto print = [this](const string& s){cout<<" "<<s<<endl;};
661 //
662 // for_each(macro_args.cbegin(), macro_args.cend(), print);
663 
664  auto num_args = macro_args.size();
665 
666  // ---- get the string to repeat ----
667  string what = macro_args[0];
668 
669  //removing enclosing "" if added:
670  what = tstring::removeEnclosingChar(what, '"', '"', true);
671 
672  // ---- the second argument is the number of repetition ----
673  if ( !tstring::isanumber(macro_args[1]) ) {
674  fatal("rep(): second argument must be a number in: rep(x, n, each=1, sep=\",\")\n");
675  }
676 
677  int num = tstring::str2int(macro_args[1]);
678 
679  // ---- looking for the "each" argument ----
680  auto has_each = [] (const string& s) {return (s.find("each") != string::npos);};
681 
682  auto argPos = find_if(macro_args.begin(), macro_args.end(), has_each);
683 
684  string arg;
685 
686  if( argPos != macro_args.end() )
687  arg = getMacroParamValue(*argPos, "each", syntax);
688  else
689  arg = "1"; // default value if argument is absent, mean "each" must be named
690 
691  int each = tstring::str2int(arg);
692 
693  // the separator char has been set at the back by default
694  string sep;
695 
696  sep = macro_args[num_args-1];
697 
698 
699  // processing the input in case where "each" has been specified
700  vector<string> elmnts;
701 
702  if(argPos != macro_args.end())
703  elmnts = tstring::split(tstring::removeEnclosingChar(macro_args[0], '"', '"', true), ',');
704  else
705  elmnts.push_back(what);
706 
707  string out;
708 
709  for(int i = 0; i < num; ++i) {
710  for(auto e = 0; e < elmnts.size(); ++e) {
711  for(int j = 0; j < each; ++j) {
712  out += elmnts[e] + sep;
713  }
714  }
715  }
716  // remove last separator, only if more than one element was concatenated
717  if(sep == ",")
718  out = tstring::removeLastCharOf(out, ',');
719 
720  return out;
721 }
static int str2int(const string &str)
Converts a string into an integer.
Definition: tstring.h:71
static vector< string > split(const string &str, const char delim, bool splitOnce=false)
splits a string into substrings (tokens) delimited by a single character.
Definition: tstring.h:126
static string removeLastCharOf(const string &str, const char c)
Removes the last of a character found in a string.
Definition: tstring.h:335

References fatal(), tstring::isanumber(), tstring::removeEnclosingChar(), tstring::removeLastCharOf(), tstring::split(), and tstring::str2int().

Referenced by ParamsParser().

+ Here is the caller graph for this function:

◆ replaceMacro()

string ParamsParser::replaceMacro ( const string &  arg)

Macros.

272 {
273  // we now need to check if a macro is part of the argument string
274  // this is detected if the arg string holds a "(" as in "macro_name( "
275  // or "(" is within the whole string as in "macro_name(arg1"
276  // or "(" is within a block argument, we skip the first char to account for that last case
277 
278  string out_arg;
279 
280  if( arg.find_first_of('(', 1) != string::npos )
281  {
282  // there might be a macro, get it
283 
284  out_arg = parseMacroFunctionBlock(arg);
285 
286  }
287  else // no macro
288  {
289  out_arg = arg;
290  }
291 
292  return out_arg;
293 }

◆ reset_inputParams()

void ParamsParser::reset_inputParams ( )
inlineprotected
112 {_inputParams.clear();}

Referenced by StreamParser::read().

+ Here is the caller graph for this function:

◆ rexp()

string ParamsParser::rexp ( const string &  argstr)
1347 {
1348  string syntax = "rexp(n, mean=1, sep=\",\")";
1349 
1350  int max_arg = 3, min_arg = 1;
1351  double mean=1.0;
1352  unsigned int num_deviates;
1353 
1354  vector<string> macro_args = getMacroArgs(argstr, min_arg, max_arg, "rexp", syntax, true);
1355 
1356  // get and check the number of deviates we need to draw
1357  if(!tstring::isanumber(macro_args[0]))
1358  fatal("rexp(): first argument must be a positive integer in: rexp(%s)\n", argstr.c_str());
1359 
1360  num_deviates = tstring::str2uint(macro_args[0]);
1361 
1362  if(!(num_deviates > 0))
1363  fatal("rexp(): first argument must be a positive integer in: rexp(%s)\n", argstr.c_str());
1364 
1365 
1366  // get the mean value, if present
1367  // we omit last arg macro_args[2] which is always the separator character
1368  if(macro_args.size() == 3){
1369 
1370  vector<string> param_args = tstring::splitExcludeEnclosedDelimiters(macro_args[1], '=');
1371 
1372  if(param_args[0] == "mean") {
1373 
1374  mean = tstring::str2dble(param_args[1]);
1375 
1376  } else if(param_args.size() == 1) {
1377 
1378  // the string "mean=" can be omitted by user
1379 
1380  mean = tstring::str2dble(param_args[0]);
1381 
1382  } else {
1383 
1384  fatal("rexp() syntax is: %s\n",syntax.c_str());
1385  }
1386  }
1387 
1388  string sep = macro_args.back();
1389 
1390  // compute the random deviates
1391  string out;
1392 
1393  auto draw = [mean](){return tstring::dble2str(RAND::Exponential(mean));};
1394 
1395  for(unsigned int i = 0; i < num_deviates -1; ++i)
1396  out += draw() + sep;
1397 
1398  out += draw();
1399 
1400  return out;
1401 }
static double Exponential(double mu)
Definition: Uniform.h:457
static string dble2str(const double d)
Writes a floating-point value into a string.
Definition: tstring.h:113

References tstring::dble2str(), RAND::Exponential(), fatal(), tstring::isanumber(), tstring::splitExcludeEnclosedDelimiters(), tstring::str2dble(), and tstring::str2uint().

Referenced by ParamsParser().

+ Here is the caller graph for this function:

◆ rgamma()

string ParamsParser::rgamma ( const string &  argstr)
1406 {
1407  string syntax = "rgamma(n, a, b, sep=\",\")";
1408 
1409  // a and b params are mandatory, with no default
1410 
1411  int max_arg = 4, min_arg = 3;
1412  double a = 0.0, b = 1.0;
1413  unsigned int num_deviates;
1414 
1415  vector<string> macro_args = getMacroArgs(argstr, min_arg, max_arg, "rgamma", syntax, true);
1416 
1417  // get and check the number of deviates we need to draw
1418  if(!tstring::isanumber(macro_args[0]))
1419  fatal("rgamma(): first argument must be a positive integer in: rgamma(%s)\n", argstr.c_str());
1420 
1421  num_deviates = tstring::str2uint(macro_args[0]);
1422 
1423  if(!(num_deviates > 0))
1424  fatal("rgamma(): first argument must be a positive integer in: rgamma(%s)\n", argstr.c_str());
1425 
1426 
1427  // omit last arg which is always the separator character
1428 
1429  for (unsigned int i = 1; i < macro_args.size()-1; ++i) {
1430 
1431  vector<string> param_args = tstring::splitExcludeEnclosedDelimiters(macro_args[i], '=');
1432 
1433  if(param_args[0] == "a") {
1434 
1435  a = tstring::str2dble(param_args[1]);
1436 
1437  } else if(param_args[0] == "b") {
1438 
1439  b = tstring::str2dble(param_args[1]);
1440 
1441  } else if(param_args.size() == 1) {
1442 
1443  // the strings "a=" or "b=" can be omitted by the user
1444  // we assume meaning by position
1445 
1446  if(i == 1)
1447  a = tstring::str2dble(param_args[0]);
1448  else if (i == 2)
1449  b = tstring::str2dble(param_args[0]);
1450 
1451  } else {
1452 
1453  fatal("rgamma() syntax is: %s.\n",syntax.c_str());
1454  }
1455  }
1456 
1457  if(a < 0)
1458  fatal("rgamma(): shape parameter \"a\" must be positive in %s.\n",syntax.c_str());
1459 
1460  if(b < 0)
1461  fatal("rgamma(): rate parameter \"b\" must be positive in %s.\n",syntax.c_str());
1462 
1463 
1464  string sep = macro_args.back();
1465 
1466  // compute the random deviates
1467  string out;
1468 
1469  auto draw = [a, b](){return tstring::dble2str(RAND::Gamma(a,b));};
1470 
1471  for(unsigned int i = 0; i < num_deviates -1; ++i)
1472  out += draw() + sep;
1473 
1474  out += draw();
1475 
1476  return out;
1477 }
static double Gamma(double a, double b)
Definition: Uniform.h:395

References tstring::dble2str(), fatal(), RAND::Gamma(), tstring::isanumber(), tstring::splitExcludeEnclosedDelimiters(), tstring::str2dble(), and tstring::str2uint().

Referenced by ParamsParser().

+ Here is the caller graph for this function:

◆ rlognorm()

string ParamsParser::rlognorm ( const string &  argstr)
1482 {
1483  string syntax = "rlognorm(n, mean, sd, sep=\",\")";
1484 
1485  // a and b params are mandatory, with no default
1486 
1487  int max_arg = 4, min_arg = 3;
1488  double a = 0.0, b = 1.0;
1489  unsigned int num_deviates;
1490 
1491  vector<string> macro_args = getMacroArgs(argstr, min_arg, max_arg, "rlognorm", syntax, true);
1492 
1493  // get and check the number of deviates we need to draw
1494  if(!tstring::isanumber(macro_args[0]))
1495  fatal("rlognorm(): first argument must be a positive integer in: rlognorm(%s)\n", argstr.c_str());
1496 
1497  num_deviates = tstring::str2uint(macro_args[0]);
1498 
1499  if(!(num_deviates > 0))
1500  fatal("rlognorm(): first argument must be a positive integer in: rlognorm(%s)\n", argstr.c_str());
1501 
1502 
1503  // omit last arg which is always the separator character
1504 
1505  for (unsigned int i = 1; i < macro_args.size()-1; ++i) {
1506 
1507  vector<string> param_args = tstring::splitExcludeEnclosedDelimiters(macro_args[i], '=');
1508 
1509  if(param_args[0] == "mean") {
1510 
1511  a = tstring::str2dble(param_args[1]);
1512 
1513  } else if(param_args[0] == "sd") {
1514 
1515  b = tstring::str2dble(param_args[1]);
1516 
1517  } else if(param_args.size() == 1) {
1518 
1519  // the strings "mean=" or "sd=" can be omitted by the user
1520  // we assume meaning by position
1521 
1522  if(i == 1)
1523  a = tstring::str2dble(param_args[0]);
1524  else if (i == 2)
1525  b = tstring::str2dble(param_args[0]);
1526 
1527  } else {
1528 
1529  fatal("rlognorm() syntax is: %s\n",syntax.c_str());
1530  }
1531  }
1532 
1533  string sep = macro_args.back();
1534 
1535  // compute the random deviates
1536  string out;
1537 
1538  auto draw = [a, b](){return tstring::dble2str(RAND::LogNormal(a,b));};
1539 
1540  for(unsigned int i = 0; i < num_deviates -1; ++i)
1541  out += draw() + sep;
1542 
1543  out += draw();
1544  return out;
1545 }
static double LogNormal(double zeta, double sigma)
Definition: Uniform.h:367

References tstring::dble2str(), fatal(), tstring::isanumber(), RAND::LogNormal(), tstring::splitExcludeEnclosedDelimiters(), tstring::str2dble(), and tstring::str2uint().

Referenced by ParamsParser().

+ Here is the caller graph for this function:

◆ rnorm()

string ParamsParser::rnorm ( const string &  argstr)
1155 {
1156  string syntax = "rnorm(n, mean=0, sd=1, sep=\",\")";
1157 
1158  int max_arg = 4, min_arg = 1;
1159  double mean = 0.0, sd = 1.0;
1160  unsigned int num_deviates;
1161 
1162  vector<string> macro_args = getMacroArgs(argstr, min_arg, max_arg, "rnorm", syntax, true);
1163 
1164 
1165 // auto print = [this](const string& s){cout<<" getMacroArgs:: "<<s<<endl;};
1166 //
1167 // for_each(macro_args.cbegin(), macro_args.cend(), print);
1168 
1169  // get and check the number of deviates we need to draw
1170  if(!tstring::isanumber(macro_args[0]))
1171  fatal("rnorm(): first argument must be a positive integer in: rnorm(%s)\n", argstr.c_str());
1172 
1173  num_deviates = tstring::str2uint(macro_args[0]);
1174 
1175  if(!(num_deviates > 0))
1176  fatal("rnorm(): first argument must be a positive integer in: rnorm(%s)\n", argstr.c_str());
1177 
1178  // get the mean and sd values, if present
1179  if(macro_args.size()-1 > 1){
1180 
1181  // omit last arg which is always the separator character
1182 
1183  for (unsigned int i = 1; i < macro_args.size()-1; ++i) {
1184 
1185  vector<string> param_args = tstring::splitExcludeEnclosedDelimiters(macro_args[i], '=');
1186 
1187  if(param_args[0] == "mean") {
1188 
1189  mean = tstring::str2dble(param_args[1]);
1190 
1191  } else if(param_args[0] == "sd") {
1192 
1193  sd = tstring::str2dble(param_args[1]);
1194 
1195  } else if(param_args.size() == 1) {
1196 
1197  // the "mean=" and "sd=" can be omitted
1198 
1199  if(i == 1)
1200  mean = tstring::str2dble(param_args[0]);
1201  else if (i == 2)
1202  sd = tstring::str2dble(param_args[0]);
1203 
1204  } else {
1205 
1206  fatal("rnorm() syntax is: %s\n",syntax.c_str());
1207  }
1208 
1209  }
1210  }
1211 
1212  string sep = macro_args.back();
1213 
1214  // compute the random deviates
1215  string out;
1216  auto draw = [mean, sd](){return tstring::dble2str(mean + RAND::Gaussian(sd));};
1217 
1218  for(unsigned int i = 0; i < num_deviates -1; ++i)
1219  out += draw() + sep;
1220 
1221  out += draw();
1222 
1223  return out;
1224 }
static double Gaussian(double sigma)
Definition: Uniform.h:271

References tstring::dble2str(), fatal(), RAND::Gaussian(), tstring::isanumber(), tstring::splitExcludeEnclosedDelimiters(), tstring::str2dble(), and tstring::str2uint().

Referenced by ParamsParser().

+ Here is the caller graph for this function:

◆ round()

string ParamsParser::round ( const string &  argstr)
1649 {
1650  string syntax = "round(x, digit=0, sep=\",\")";
1651 
1652  int max_arg = 3, min_arg = 1;
1653 
1654  vector<string> macro_args = getMacroArgs(argstr, min_arg, max_arg, "round", syntax, true);
1655 
1656  vector<string> elmnts = macro_list(macro_args[0]);
1657 
1658  // optional named argument "digit" (default 0; may be negative, e.g. round to tens)
1659  int digit = 0;
1660  auto has_digit = [] (const string& s) {return (s.find("digit") != string::npos);};
1661  auto argPos = find_if(macro_args.begin(), macro_args.end(), has_digit);
1662 
1663  if(argPos != macro_args.end()) {
1664  string d = getMacroParamValue(*argPos, "digit", syntax);
1665  if(!tstring::isanumber(d))
1666  fatal("round(): argument \"digit\" must be an integer, received \"%s\" in: round(%s)\n", d.c_str(), argstr.c_str());
1667  digit = tstring::str2int(d);
1668  }
1669 
1670  string sep = macro_args.back();
1671 
1672  double factor = std::pow(10.0, digit);
1673 
1674  string out;
1675  for(size_t i = 0; i < elmnts.size(); ++i) {
1676  if(!tstring::isanumber(elmnts[i]))
1677  fatal("round(): all values must be numbers, received \"%s\" in: round(%s)\n", elmnts[i].c_str(), argstr.c_str());
1678 
1679  double r = std::round(tstring::str2dble(elmnts[i]) * factor) / factor;
1680  out += fmt_number(r, digit > 0 ? digit : 0);
1681  if(i < elmnts.size() - 1) out += sep;
1682  }
1683 
1684  return out;
1685 }

References fatal(), tstring::isanumber(), tstring::str2dble(), and tstring::str2int().

Referenced by ParamsParser().

+ Here is the caller graph for this function:

◆ rpoiss()

string ParamsParser::rpoiss ( const string &  argstr)
1229 {
1230  string syntax = "rpois(n, mean=1, sep=\",\")";
1231 
1232  int max_arg = 3, min_arg = 1;
1233  double mean = 1.0;
1234  unsigned int num_deviates;
1235 
1236  vector<string> macro_args = getMacroArgs(argstr, min_arg, max_arg, "rpois", syntax, true);
1237 
1238  // get and check the number of deviates we need to draw
1239  if(!tstring::isanumber(macro_args[0]))
1240  fatal("rpois(): first argument must be a positive integer in: rpois(%s)\n", argstr.c_str());
1241 
1242  num_deviates = tstring::str2uint(macro_args[0]);
1243 
1244  if(!(num_deviates > 0))
1245  fatal("rpois(): first argument must be a positive integer in: rpois(%s)\n", argstr.c_str());
1246 
1247 
1248  // get the mean value, if present
1249  // we omit last arg macro_args[2] which is always the separator character
1250  if(macro_args.size() == 3){
1251 
1252  vector<string> param_args = tstring::splitExcludeEnclosedDelimiters(macro_args[1], '=');
1253 
1254  if(param_args[0] == "mean") {
1255 
1256  mean = tstring::str2dble(param_args[1]);
1257 
1258  } else if(param_args.size() == 1) {
1259 
1260  // the string "mean=" can be omitted by user
1261 
1262  mean = tstring::str2dble(param_args[0]);
1263 
1264  } else {
1265 
1266  fatal("rpois() syntax is: %s\n",syntax.c_str());
1267  }
1268  }
1269 
1270  string sep = macro_args.back();
1271 
1272  // compute the random deviates
1273  string out;
1274 
1275  auto draw = [mean](){return tstring::dble2str(RAND::Poisson(mean));};
1276 
1277  for(unsigned int i = 0; i < num_deviates -1; ++i)
1278  out += draw() + sep;
1279 
1280  out += draw();
1281 
1282  return out;
1283 }
static double Poisson(double mean)
From the Numerical Recieps.
Definition: Uniform.h:229

References tstring::dble2str(), fatal(), tstring::isanumber(), RAND::Poisson(), tstring::splitExcludeEnclosedDelimiters(), tstring::str2dble(), and tstring::str2uint().

Referenced by ParamsParser().

+ Here is the caller graph for this function:

◆ runif()

string ParamsParser::runif ( const string &  argstr)
1078 {
1079  string syntax = "runif(n, min=0, max=1, sep=\",\")";
1080 
1081  int max_arg = 4, min_arg = 1;
1082  double min = 0.0, max = 1.0;
1083  unsigned int num_deviates;
1084 
1085  vector<string> macro_args = getMacroArgs(argstr, min_arg, max_arg, "runif", syntax, true);
1086 
1087  // get and check the number of deviates we need to draw
1088  if(!tstring::isanumber(macro_args[0]))
1089  fatal("runif(): first argument must be a positive integer in: runif(%s)\n", argstr.c_str());
1090 
1091  num_deviates = tstring::str2uint(macro_args[0]);
1092 
1093  if(!(num_deviates > 0))
1094  fatal("runif(): first argument must be a positive integer in: runif(%s)\n", argstr.c_str());
1095 
1096 
1097 // map<string, double> dev_param; dev_param["min"] = 0.0; dev_param["max"] = 1.0;
1098 //
1099 // auto get_param_value = [&](const string& str_in){
1100 // vector<string> param_args = tstring::splitExcludeEnclosedDelimiters(str_in, '=');
1101 //
1102 // };
1103 
1104  // get the min and max values, if present
1105  if(macro_args.size()-1 > 1){
1106 
1107  // omit last arg which is always the separator character
1108 
1109  for (unsigned int i = 1; i < macro_args.size()-1; ++i) {
1110 
1111  vector<string> param_args = tstring::splitExcludeEnclosedDelimiters(macro_args[i], '=');
1112 
1113  if(param_args[0] == "min") {
1114 
1115  min = tstring::str2dble(param_args[1]);
1116 
1117  } else if(param_args[0] == "max") {
1118 
1119  max = tstring::str2dble(param_args[1]);
1120 
1121  } else if(param_args.size() == 1) {
1122 
1123  // the "min=" and "max=" can be omitted
1124 
1125  if(i == 1)
1126  min = tstring::str2dble(param_args[0]);
1127  else if (i == 2)
1128  max = tstring::str2dble(param_args[0]);
1129 
1130  }else {
1131 
1132  fatal("runif() syntax is: %s\n",syntax.c_str());
1133  }
1134  }
1135  }
1136 
1137  string sep = macro_args.back();
1138 
1139  // compute the random deviates
1140  string out;
1141 
1142  auto draw = [min, max](){return tstring::dble2str((max-min)*RAND::Uniform() + min);};
1143 
1144  for(unsigned int i = 0; i < num_deviates -1; ++i)
1145  out += draw() + sep;
1146 
1147  out += draw();
1148 
1149  return out;
1150 }
static double Uniform()
Generates a random number from [0.0, 1.0[ uniformly distributed.
Definition: Uniform.h:125

References tstring::dble2str(), fatal(), tstring::isanumber(), tstring::splitExcludeEnclosedDelimiters(), tstring::str2dble(), tstring::str2uint(), and RAND::Uniform().

Referenced by ParamsParser().

+ Here is the caller graph for this function:

◆ sample()

string ParamsParser::sample ( const string &  argstr)
1550 {
1551  string syntax = "sample(n, x, replace=false, sep=\",\")";
1552 
1553  int max_arg = 4, min_arg = 2;
1554 
1555  vector<string> macro_args = getMacroArgs(argstr, min_arg, max_arg, "sample", syntax, true);
1556 
1557  // first argument: number of elements to draw
1558  if(!tstring::isanumber(macro_args[0]))
1559  fatal("sample(): first argument \"n\" must be a positive integer in: sample(%s)\n", argstr.c_str());
1560 
1561  unsigned int n = tstring::str2uint(macro_args[0]);
1562 
1563  // second argument: the quoted, comma-separated list to sample from
1564  vector<string> elmnts = macro_list(macro_args[1]);
1565 
1566  if(elmnts.size() == 1 && elmnts[0].empty())
1567  fatal("sample(): second argument \"x\" must be a non-empty list in: sample(%s)\n", argstr.c_str());
1568 
1569  // optional named argument "replace" (default false)
1570  bool replace = false;
1571  auto has_replace = [] (const string& s) {return (s.find("replace") != string::npos);};
1572  auto argPos = find_if(macro_args.begin(), macro_args.end(), has_replace);
1573 
1574  if(argPos != macro_args.end())
1575  replace = macro_str2bool(getMacroParamValue(*argPos, "replace", syntax), "sample", syntax);
1576 
1577  // the separator char has been set at the back of macro_args by getMacroArgs
1578  string sep = macro_args.back();
1579 
1580  if(!replace && n > elmnts.size())
1581  fatal("sample(): cannot draw %u elements without replacement from a list of %u in: sample(%s)\n",
1582  n, (unsigned int)elmnts.size(), argstr.c_str());
1583 
1584  // draw the indices of the sampled elements
1585  vector<int> idx(n);
1586 
1587  if(n > 0) {
1588  if(!replace)
1589  RAND::Sample(0, (int)elmnts.size(), n, idx.data(), false);
1590  else
1591  for(unsigned int i = 0; i < n; ++i)
1592  idx[i] = RAND::Uniform((unsigned int)elmnts.size());
1593  }
1594 
1595  string out;
1596  for(unsigned int i = 0; i < n; ++i) {
1597  out += elmnts[ idx[i] ];
1598  if(i < n - 1) out += sep;
1599  }
1600 
1601  return out;
1602 }
static void Sample(const int from, const int to, const unsigned int num, int *result, bool replace)
Creates a sample of integers within range [from, to), with or without replacement.
Definition: Uniform.h:723

References fatal(), tstring::isanumber(), RAND::Sample(), tstring::str2uint(), and RAND::Uniform().

Referenced by ParamsParser().

+ Here is the caller graph for this function:

◆ seq()

string ParamsParser::seq ( const string &  argstr)
726 {
727  string syntax="seq(from, to, by, sep=\",\")";
728 
729  int max_arg = 4;
730 
731  vector<string> macro_args = getMacroArgs(argstr, 3, max_arg, "seq", syntax, true);
732 
733  string sep = macro_args[ 3 ];
734 
735  for (int i = 0; i < 3; ++i) {
736 
737  if(!tstring::isanumber(macro_args[i]))
738  fatal("seq(): argument %i must be a number in: seq(%s)\n", i+1, argstr.c_str());
739 
740  }
741 
742  // now create the sequence of numbers:
743  string out;
744 
745  int index = 0;
746  double current = tstring::str2dble(macro_args[0]);
747  double to = tstring::str2dble(macro_args[1]);
748  double i = tstring::str2dble(macro_args[2]);
749 
750  double sign = 1.0; // indicate whether the sequence is increasing (+1.0) or decreasing (-1.0)
751 
752  // check if the sequence is decreasing
753  if(current > to) {
754 
755  sign = -1.0;
756 
757  if(i > 0)
758  fatal("seq(): third argument \"by\" must be a negative number when from > to in: seq(%s).\n", argstr.c_str());
759 
760 // i *= sign; // must be negative when decrement
761  }
762 
763  // check the sign of the increment if increasing sequence
764  if(current < to && i < 0) {
765 
766  fatal("seq(): third argument \"by\" must be a positive number when from < to in: seq(%s).\n", argstr.c_str());
767 
768 // i *= -1.0; //make it positive
769  }
770  // loop until reaching "to"
771  while(sign*(current-to) < 1.0e-15) { // to avoid precision errors, it's a workaround, setting epsilon to a fixed value
772 
773  out += tstring::dble2str(current);
774 
775  current += i;
776 
777  // check next value to place the separator thus avoiding adding a separator after the last value
778  if(sign*(current-to) < 1.0e-15)
779  out += sep;
780  };
781 
782  return out;
783 }

References tstring::dble2str(), fatal(), tstring::isanumber(), and tstring::str2dble().

Referenced by ParamsParser().

+ Here is the caller graph for this function:

◆ setName()

void ParamsParser::setName ( const char *  name)
inline
60 {_sname = name;}

Referenced by BinaryDataLoader::extractPop().

+ Here is the caller graph for this function:

◆ sort()

string ParamsParser::sort ( const string &  argstr)
1607 {
1608  string syntax = "sort(x, ascend=true, sep=\",\")";
1609 
1610  int max_arg = 3, min_arg = 1;
1611 
1612  vector<string> macro_args = getMacroArgs(argstr, min_arg, max_arg, "sort", syntax, true);
1613 
1614  vector<string> elmnts = macro_list(macro_args[0]);
1615 
1616  // all values must be numbers (strict-numeric sort)
1617  for(const auto& e : elmnts)
1618  if(!tstring::isanumber(e))
1619  fatal("sort(): all values must be numbers, received \"%s\" in: sort(%s)\n", e.c_str(), argstr.c_str());
1620 
1621  // optional named argument "ascend" (default true)
1622  bool ascend = true;
1623  auto has_ascend = [] (const string& s) {return (s.find("ascend") != string::npos);};
1624  auto argPos = find_if(macro_args.begin(), macro_args.end(), has_ascend);
1625 
1626  if(argPos != macro_args.end())
1627  ascend = macro_str2bool(getMacroParamValue(*argPos, "ascend", syntax), "sort", syntax);
1628 
1629  string sep = macro_args.back();
1630 
1631  // sort the original token strings by their numeric value, preserving their representation
1632  std::sort(elmnts.begin(), elmnts.end(), [ascend] (const string& a, const string& b) {
1633  double da = tstring::str2dble(a), db = tstring::str2dble(b);
1634  return ascend ? (da < db) : (da > db);
1635  });
1636 
1637  string out;
1638  for(size_t i = 0; i < elmnts.size(); ++i) {
1639  out += elmnts[i];
1640  if(i < elmnts.size() - 1) out += sep;
1641  }
1642 
1643  return out;
1644 }

References fatal(), and tstring::isanumber().

Referenced by ParamsParser().

+ Here is the caller graph for this function:

◆ sym_matrix()

string ParamsParser::sym_matrix ( const string &  argstr)
987 {
988  string syntax = "smatrix(x, nrow, diag=0)";
989 
990  // first arg is row-oriented
991  int max_arg = 3, min_arg = 2;
992  string out;
993  size_t nrow;
994 
995  vector<string> macro_args = getMacroArgs(argstr, min_arg, max_arg, "smatrix", syntax, false);
996 
997  // the size is inferred from splitting the string provided
998  vector<string> upper = macro_list(macro_args[0]);
999 
1000  if(!tstring::isanumber(macro_args[1]))
1001  fatal("smatrix(): secong argument \"nrow\" is not a number in: smatrix(%s)\n", argstr.c_str());
1002  else
1003  nrow = tstring::str2int(macro_args[1]);
1004 
1005  size_t num_el = nrow*(nrow-1)/2;
1006 
1007  //fill "upper" if only one value was passed, that value will be copied
1008  if( upper.size() == 1) {
1009  string val = upper[0];
1010  upper.assign(num_el, val);
1011  }
1012 
1013  // check size
1014  if( upper.size() != nrow*(nrow-1)/2 )
1015  fatal("smatrix(): number of elements (%i) passed doesn't match with the number of rows (%i) specified in: smatrix(%s)\n", upper.size(), nrow, argstr.c_str());
1016 
1017  // look for diagonal elements
1018  auto is_diag = [] (const string& s) {return (s.find("diag") != string::npos);};
1019 
1020  vector<string>::const_iterator diagPos = find_if(macro_args.begin(), macro_args.end(), is_diag);
1021 
1022  vector<string> diag;
1023  string diag_arg;
1024 
1025  if( diagPos != macro_args.end() ) // user specified the diagonal elements
1026  {
1027  diag_arg = *diagPos;
1028  //remove the front string "diag=" and get the argument value
1029  diag_arg = getMacroParamValue(diag_arg, "diag", syntax);
1030 
1031  diag = macro_list(diag_arg);
1032 
1033  if(diag.size() == 1) {
1034  string val = diag[0];
1035  diag.assign(nrow, val);
1036  }
1037  else if (diag.size() != nrow) {
1038  fatal("smatrix(): number of elements to \"diag\" doesn't match with the matrix size in: smatrix(%s)\n", argstr.c_str());
1039  }
1040 
1041  } else
1042  diag.assign(nrow, "0");
1043 
1044  // create the matrix
1045 
1046  TMatrix mat(nrow, nrow);
1047 
1048  for (unsigned int r = 0, c, e = 0, d = 0; r < nrow ; ++r) {
1049 
1050  for (c = r; c < nrow && e < upper.size(); ++c) {
1051 
1052  if(c == r)
1053  mat.set(r, c, tstring::str2dble(diag[d++]));
1054  else
1055  mat.set(r, c, tstring::str2dble(upper[e++]));
1056  }
1057 
1058  // catch the last diagonal element of the matrix, after having copied all off-diagonal elements
1059  if(c == r)
1060  mat.set(r, c, tstring::str2dble(diag[d++]));
1061  }
1062 
1063  // fill the lower triangle:
1064  for (unsigned int r = nrow-1; r > 0 ; --r) {
1065 
1066  for(unsigned int c = 0; c < r; ++c)
1067 
1068  mat.set(r, c, mat.get(c,r));
1069 
1070  }
1071 
1072  return mat.to_string();
1073 }
A class to handle matrix in params, coerces matrix into a vector of same total size.
Definition: tmatrix.h:48

References fatal(), TMatrix::get(), tstring::isanumber(), TMatrix::set(), tstring::str2dble(), tstring::str2int(), and TMatrix::to_string().

Referenced by ParamsParser().

+ Here is the caller graph for this function:

◆ tempseq()

string ParamsParser::tempseq ( const string &  argstr)
788 {
789  string syntax = "tempseq(at, seq) ";
790 
791  int max_arg = 2, min_arg = 2;
792 
793  vector<string> macro_args = getMacroArgs(argstr, min_arg, max_arg, "tempseq", syntax, false);
794 
795  //get arg values by name:
796  string arg;
797  vector<string>::const_iterator argPos;
798 
799 
800  // look for a named argument
801 
802  // check if arg "at" is named ( at="..." )
803  auto has_at = [] (const string& s) {return (s.find("at") != string::npos);};
804 
805  argPos = find_if(macro_args.begin(), macro_args.end(), has_at);
806 
807  if( argPos != macro_args.end() )
808  arg = getMacroParamValue(*argPos, "at", syntax);
809  else
810  arg = macro_args[0]; // default assignment by position
811 
812  vector<string> at_time = macro_list(arg);
813 
814  if(at_time[0] != "0")
815  fatal("tempseq(): argument \"at\" must start with value \'0\' (for parameter's initial value at generation 0) in: tempseq(%s).\n",argstr.c_str());
816 
817  // check if arg "seq" is named:
818  auto has_seq = [] (const string& s) {return (s.find("seq") != string::npos);};
819 
820  argPos = find_if(macro_args.begin(), macro_args.end(), has_seq);
821 
822  if( argPos != macro_args.end() )
823  arg = getMacroParamValue(*argPos, "seq", syntax);
824  else
825  arg = macro_args[1]; // default assignment by position
826 
827  vector<string> values = macro_list(arg);
828 
829  //------- process input and build output string ---------
830  size_t num_gen = at_time.size();
831  size_t num_val = values.size();
832 
833  if(num_val < num_gen)
834  fatal("tempseq(): argument \"seq\" contains less values than \"at\" in: tempseq(%s).\n",argstr.c_str());
835 
836  if(num_val > num_gen)
837  fatal("tempseq(): argument \"seq\" contains more values than \"at\" in: tempseq(%s)\n",argstr.c_str());
838 
839  string out = "(";
840 
841  for(auto i = 0; i < num_gen-1; ++i) {
842 
843  out += "@g" + at_time[i] + " " + values[ i % num_val] + ", ";
844  }
845 
846  out += "@g" + at_time[num_gen-1] + " " + values[ (num_gen-1) % num_val] + ")";
847 
848  return out;
849 }

References fatal().

Referenced by ParamsParser().

+ Here is the caller graph for this function:

Member Data Documentation

◆ _hasPreservedMacro

bool ParamsParser::_hasPreservedMacro = false
private

Set true by parseMacroFunctionBlock when a P() preserve-macro is encountered while parsing a parameter value; read and reset per-parameter in parse().

◆ _inputParams

map< string, string > ParamsParser::_inputParams
private

The whole, unparsed set of input parameters.

◆ _macroMap

map< string, string (ParamsParser::* )(const string& )> ParamsParser::_macroMap
private

The macro table, mapping call name to caller.

◆ _parsedParams

map< string, vector< string > > ParamsParser::_parsedParams
private

The parsed set of simulation parameters after sequential parameters have been separated.

◆ _sname

const char* ParamsParser::_sname
private

Attached file of stream name.


The documentation for this class was generated from the following files:

Generated for Nemo v2.4.2 by  doxygen 1.9.1

Catalogued on GSR