Nemo  2.4.1
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)
57 {
58  _sname = name;
59 
60  _macroMap["rep"] = &ParamsParser::rep;
61  _macroMap["seq"] = &ParamsParser::seq;
62  _macroMap["tempseq"] = &ParamsParser::tempseq;
65  _macroMap["runif"] = &ParamsParser::runif;
66  _macroMap["rnorm"] = &ParamsParser::rnorm;
67  _macroMap["rpois"] = &ParamsParser::rpoiss;
68  _macroMap["rlognorm"] = &ParamsParser::rlognorm;
69  _macroMap["rgamma"] = &ParamsParser::rgamma;
70  _macroMap["rbernoul"] = &ParamsParser::rbernoul;
71  _macroMap["rexp"] = &ParamsParser::rexp;
72  _macroMap["matrix"] = &ParamsParser::matrix;
74  _macroMap["smatrix"] = &ParamsParser::sym_matrix;
75  _macroMap["sample"] = &ParamsParser::sample;
76  _macroMap["sort"] = &ParamsParser::sort;
77  _macroMap["round"] = &ParamsParser::round;
78  _macroMap["ceiling"] = &ParamsParser::ceiling;
79  _macroMap["floor"] = &ParamsParser::floor;
80 }
string rexp(const string &argstr)
Definition: paramsparser.cc:1345
string sample(const string &argstr)
Definition: paramsparser.cc:1548
string round(const string &argstr)
Definition: paramsparser.cc:1647
string ceiling(const string &argstr)
Definition: paramsparser.cc:1688
string sort(const string &argstr)
Definition: paramsparser.cc:1605
string rlognorm(const string &argstr)
Definition: paramsparser.cc:1480
string tempseq(const string &argstr)
Definition: paramsparser.cc:786
string rnorm(const string &argstr)
Definition: paramsparser.cc:1153
string matrix(const string &argstr)
Definition: paramsparser.cc:852
const char * _sname
Attached file of stream name.
Definition: paramsparser.h:132
string sym_matrix(const string &argstr)
Definition: paramsparser.cc:985
string concat(const string &argstr)
Macro "c" returns a character-delimited string of atomic arguments.
Definition: paramsparser.cc:598
map< string, string(ParamsParser::*)(const string &)> _macroMap
The macro table, mapping call name to caller.
Definition: paramsparser.h:141
string rbernoul(const string &argstr)
Definition: paramsparser.cc:1286
string seq(const string &argstr)
Definition: paramsparser.cc:724
string runif(const string &argstr)
Definition: paramsparser.cc:1076
string quote(const string &argstr)
Macro "q" returns a quoted string.
Definition: paramsparser.cc:625
string floor(const string &argstr)
Definition: paramsparser.cc:1714
string rep(const string &argstr)
Definition: paramsparser.cc:650
string rpoiss(const string &argstr)
Definition: paramsparser.cc:1227
string rgamma(const string &argstr)
Definition: paramsparser.cc:1404
string diag_matrix(const string &argstr)
Definition: paramsparser.cc:918

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
59 {}

Member Function Documentation

◆ add_inputParam()

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

Referenced by StreamParser::read().

+ Here is the caller graph for this function:

◆ callMacro()

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

References fatal(), and message().

◆ ceiling()

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

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.

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

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.

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

◆ diag_matrix()

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

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).

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

Referenced by SimRunner::expandPreservedMacros().

+ Here is the caller graph for this function:

◆ floor()

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

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
63 {return _inputParams;}

◆ getArguments()

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

References StreamParser::removeSpaceAndComment().

◆ getBlockArgument()

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

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

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

◆ getMacroParamValue()

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

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

◆ getMacroSepParamChar()

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

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

◆ getParameters() [1/2]

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

◆ getParameters() [2/2]

map< string, string > & ParamsParser::getParameters ( const char *  stream_name)
85 {
86 #ifdef _DEBUG_
87  cout<<"ParamsParser::getParameters:"<<endl;
88 #endif
89  if(stream_name == NULL) {
90 
91  if(_sname == NULL)
92 
93  fatal("ParamsParser::getParameters::no stream attached to the parser!\n");
94 
95  else if( !(read(_sname)) ) // read the input text stream and extract parameters and their arguments
96 
97  fatal("ParamsParser::getParameters::failed from file \"%s\"\n",_sname);
98 
99  } else if( !(read(stream_name)) ) // read the input text stream and extract parameters and their arguments
100 
101  fatal("ParamsParser::getParameters::failed from file \"%s\"\n",stream_name);
102 
103  if(stream_name != NULL) _sname = stream_name;
104 
105  // pairs of parameter name & values have been recorder in _inputParams map
106  return _inputParams;
107 }
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
65 {return _parsedParams;}
map< string, vector< string > > _parsedParams
The parsed set of simulation parameters after sequential parameters have been separated.
Definition: paramsparser.h:138

◆ getParsedParameters() [2/2]

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

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.

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

◆ matrix()

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

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.

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

References MACRO_PRESERVE_TAG, and message().

◆ parseMacroFunctionBlock()

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

References fatal().

◆ quote()

string ParamsParser::quote ( const string &  argstr)

Macro "q" returns a quoted string.

Useful to quote result of call to enclosed macro.

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

Referenced by ParamsParser().

+ Here is the caller graph for this function:

◆ rbernoul()

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

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

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.

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

◆ reset_inputParams()

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

Referenced by StreamParser::read().

+ Here is the caller graph for this function:

◆ rexp()

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

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

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

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

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

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

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

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

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

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
61 {_sname = name;}

Referenced by BinaryDataLoader::extractPop().

+ Here is the caller graph for this function:

◆ sort()

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

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

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

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.1 by  doxygen 1.9.1

Catalogued on GSR