NOMAD Source  Version 4.0.0 Beta
WriteAttributeDefinitionFile.cpp
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------------*/
2 /* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct Search - */
3 /* */
4 /* NOMAD - Version 4.0.0 has been created by */
5 /* Viviane Rochon Montplaisir - Polytechnique Montreal */
6 /* Christophe Tribes - Polytechnique Montreal */
7 /* */
8 /* The copyright of NOMAD - version 4.0.0 is owned by */
9 /* Charles Audet - Polytechnique Montreal */
10 /* Sebastien Le Digabel - Polytechnique Montreal */
11 /* Viviane Rochon Montplaisir - Polytechnique Montreal */
12 /* Christophe Tribes - Polytechnique Montreal */
13 /* */
14 /* NOMAD v4 has been funded by Rio Tinto, Hydro-Québec, NSERC (Natural */
15 /* Sciences and Engineering Research Council of Canada), InnovÉÉ (Innovation */
16 /* en Énergie Électrique) and IVADO (The Institute for Data Valorization) */
17 /* */
18 /* NOMAD v3 was created and developed by Charles Audet, Sebastien Le Digabel, */
19 /* Christophe Tribes and Viviane Rochon Montplaisir and was funded by AFOSR */
20 /* and Exxon Mobil. */
21 /* */
22 /* NOMAD v1 and v2 were created and developed by Mark Abramson, Charles Audet, */
23 /* Gilles Couture, and John E. Dennis Jr., and were funded by AFOSR and */
24 /* Exxon Mobil. */
25 /* */
26 /* Contact information: */
27 /* Polytechnique Montreal - GERAD */
28 /* C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada */
29 /* e-mail: nomad@gerad.ca */
30 /* */
31 /* This program is free software: you can redistribute it and/or modify it */
32 /* under the terms of the GNU Lesser General Public License as published by */
33 /* the Free Software Foundation, either version 3 of the License, or (at your */
34 /* option) any later version. */
35 /* */
36 /* This program is distributed in the hope that it will be useful, but WITHOUT */
37 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
38 /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License */
39 /* for more details. */
40 /* */
41 /* You should have received a copy of the GNU Lesser General Public License */
42 /* along with this program. If not, see <http://www.gnu.org/licenses/>. */
43 /* */
44 /* You can find information on the NOMAD software at www.gerad.ca/nomad */
45 /*---------------------------------------------------------------------------------*/
46 // This executable converts the user-friendly txt files that describe the
47 // parameters, to computer-readable header files.
48 // When a parameter needs to be added or edited, only the txt files need
49 // to be modified.
50 
51 #include <algorithm> // for for_each
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <fstream>
55 #include <iostream>
56 #include <sstream>
57 #include <string>
58 #include <map>
59 
60 // Registered attribute definition names
61 const std::string attributeDefinitionNames[7] = { "displayAttributesDefinition",
62  "evalAttributesDefinition",
63  "cacheAttributesDefinition",
64  "evaluatorControlAttributesDefinition",
65  "evaluatorControlGlobalAttributesDefinition",
66  "pbAttributesDefinition",
67  "runAttributesDefinition" };
68 
69 /// \brief Registered attribute flags and default value
70 /**
71 The order of the registered attribute flags is important for attribute definition in the parameter classes.
72 Default value for the registered flag is given here.
73  */
74 const std::map<std::string, bool> attributeFlagsRegistered {
75  {"RESTART_ATTRIBUTE", false},
76  {"ALGO_COMPATIBILITY_CHECK", false},
77  {"UNIQUE_ENTRY", true} };
78 
79 /// \brief Toupper utility
80 void toUpperCase(std::string& str)
81 {
82  for_each(str.begin(), str.end(), [](char& in){ in = std::toupper(in); });
83 }
84 
85 /// \brief Exception utility
86 class Exception : public std::exception
87 {
88 
89 private:
90 
91  mutable std::string _what; ///< Error message.
92  size_t _line; ///< Line number at which the exception is thrown.
93 
94 public:
95 
96  Exception ( size_t line , const std::string & msg )
97  : _what ( msg ) ,
98  _line ( line ) {}
99 
100  /// Destructor.
101  virtual ~Exception ( void ) {}
102 
103  /// Access to the error message.
104  /**
105  \return A string with the error message.
106  */
107  const char * what ( void ) const noexcept { return _what.c_str(); }
108  size_t getLineNumber ( void ) const noexcept { return _line; }
109 };
110 
111 
112 /// \brief Utility to interpret plural words
113 void duplicateParPlurals(std::string & blockOfStrings )
114 {
115  // Pad with blanks
116  blockOfStrings.insert(0," ");
117  blockOfStrings.append(" ");
118 
119  size_t posBegin = 0;
120 
121  // Loop on ()
122  while ( true )
123  {
124  size_t posPar1 = blockOfStrings.find( "(" , posBegin );
125  if ( posPar1 != std::string::npos )
126  {
127  size_t posBlank = blockOfStrings.rfind( " " , posPar1 );
128  size_t posPar2 = blockOfStrings.find( ")" ,posBegin );
129  if ( posPar2 != std::string::npos && posBlank < posPar2 )
130  {
131  // Word to duplicate
132  std::string word = blockOfStrings.substr(posBlank+1,posPar1-posBlank-1)+" ";
133 
134  // Remove parenthesis
135  blockOfStrings.erase(posPar2,1);
136  blockOfStrings.erase(posPar1,1);
137 
138  // Insert word without parenthesis
139  blockOfStrings.insert(posBlank+1,word);
140 
141  posBegin = posBlank;
142  }
143  else
144  break;
145  }
146  else
147  break;
148 
149  }
150 }
151 
152 
153 /// \brief Utility to read a block of lines
154 std::string readBlockOfLines(std::ifstream & fin,
155  size_t & lineNumber,
156  const std::string & blockDelimiterOpen,
157  const std::string & blockDelimiterClose)
158 
159 {
160  std::string line;
161 
162  std::getline(fin, line);
163  lineNumber++;
164 
165 
166  if ( fin.fail() )
167  throw ( Exception(lineNumber,"Cannot read file") );
168 
169  // The block must be provided between delimiters
170  if (line.find( blockDelimiterOpen ) != 0)
171  {
172  std::string errMsg = " Cannot find opening delimiter ";
173  errMsg = errMsg.append(blockDelimiterOpen) ;
174  throw ( Exception(lineNumber,errMsg) );
175  }
176  std::string blockOfLines = line + " \\n ";
177 
178  // Take the content of line and put it in string
179  // with end of line
180  while ( line.empty() || line.find( blockDelimiterClose ) == std::string::npos )
181  {
182  std::getline(fin, line);
183  lineNumber++;
184 
185  if ( fin.fail() )
186  {
187  std::string errMsg = " Reached end of file without finding end delimiter ";
188  errMsg = errMsg.append(blockDelimiterClose) ;
189  throw ( Exception(lineNumber,errMsg) );
190  }
191 
192  blockOfLines += line + " \\n ";
193 
194  }
195 
196  // Remove block delimiters
197  blockOfLines.erase(0,blockDelimiterOpen.size() );
198  size_t posEnd = blockOfLines.find( blockDelimiterClose );
199  blockOfLines.erase(posEnd);
200 
201  return blockOfLines;
202 }
203 
204 
205 int main(int argc, char *argv[])
206 {
207  // Get directory where the input .txt files are.
208  std::string inputDir, outputDir;
209  if (argc > 1)
210  {
211  std::string s = argv[1];
212  // Ensure directory ends with '/'.
213  if (s[s.size()-1] != '/')
214  {
215  s += '/';
216  }
217  inputDir = s;
218  outputDir = s;
219  }
220 
221  std::ifstream fin;
222  std::ofstream fout;
223  std::string errMsg ;
224 
225  std::istringstream iss;
226  std::ostringstream oss;
227 
228  std::map<std::string,bool> attributeFlags;
229 
230  for ( auto attDefName : attributeDefinitionNames )
231  {
232  std::string attDefFile = inputDir + attDefName + ".txt";
233  std::string attDefHeader = outputDir + attDefName + ".hpp";
234 
235  // Clear input stream
236  iss.str("");
237  iss.clear();
238 
239  // Clear output stream
240  oss.str("");
241  oss.clear();
242  std::string UpperAttDefName = attDefName ;
243  for (auto & c: UpperAttDefName) c = toupper(c);
244 
245  oss << "//////////// THIS FILE MUST BE CREATED BY EXECUTING WriteAttributeDefinitionFile ////////////" << std::endl;
246  oss << "//////////// DO NOT MODIFY THIS FILE MANUALLY ///////////////////////////////////////////////" << std::endl << std::endl;
247 
248  oss << "#ifndef __NOMAD400_"<< UpperAttDefName << "__" << std::endl;
249  oss << "#define __NOMAD400_"<< UpperAttDefName << "__" << std::endl << std::endl;
250  oss << "_definition = {" ;
251 
252  bool flagInFile;
253  try
254  {
255  flagInFile=true;
256 
257  // Default error message for problem opening file
258  errMsg = " Failed to open file " + attDefFile + ".";
259 
260  size_t lineNumber=0;
261  fin.open ( attDefFile );
262 
263  if ( !fin.fail() )
264  {
265  errMsg.clear();
266  }
267  if ( !errMsg.empty() )
268  {
269  throw ( Exception( 0,errMsg ) );
270  }
271 
272  std::string line;
273  bool firstAttribute = true;
274 
275  while ( fin.good() && !fin.eof() )
276  {
277 
278  // Read attribute name
279  if ( firstAttribute )
280  {
281  getline(fin, line);
282  lineNumber++;
283  }
284 
285  // the previous getline may have reached end of file
286  if ( fin.eof() )
287  {
288  continue;
289  }
290 
291  if ( fin.fail() )
292  {
293  errMsg = " Failed to read file " + attDefFile + ".";
294  throw ( Exception(lineNumber,errMsg) );
295  }
296 
297  if ( line.size() > 0 && line.find_first_of("#")== 0 )
298  {
299  if (!firstAttribute)
300  {
301  getline(fin, line);
302  lineNumber++;
303  }
304  continue;
305  }
306 
307  // After the first attribute we need comma separation between attributes
308  if ( ! firstAttribute )
309  oss << "," << std::endl;
310  else
311  oss << std::endl;
312 
313  std::string attributeName;
314  iss.clear();
315  iss.str(line);
316  iss >> attributeName;
317 
318  if ( attributeName.size()==0)
319  {
320  errMsg = " The first word after a comment must be an attribute name. \n An empty line is not valid.";
321  throw ( Exception(lineNumber,errMsg) );
322  }
323  oss << "{ \"" << attributeName << "\", ";
324 
325  // Read attribute type
326  getline(fin, line);
327  lineNumber++;
328 
329  if ( fin.fail() || line.empty() )
330  {
331  errMsg = "Failed to read file " + attDefFile + ".";
332  throw ( Exception(lineNumber,errMsg) );
333  }
334 
335  std::string attributeType;
336  iss.clear();
337  iss.str(line);
338 
339  iss >> attributeType ;
340 
341  if ( attributeType.size()==0 )
342  {
343  errMsg = " The next word after an attribute name must be the attribute type. \n An empty line is not valid.";
344  throw ( Exception(lineNumber,errMsg) );
345  }
346  oss << " \"" << attributeType << "\", " ;
347 
348  // Read attribute default value (can be undefined)
349  getline(fin, line);
350  lineNumber++;
351 
352  if ( fin.fail() || line.empty() )
353  {
354  errMsg = " Failed to read file " + attDefFile + ".";
355  throw ( Exception(lineNumber,errMsg) );
356  }
357 
358  std::string attributeDefault= line;
359 
360 
361  // Special case: attributeType is std::string or NOMAD::ArrayOfString, and attributeDefault
362  // is set to a string meaning no default: set attributeDefault to empty string.
363  if ("std::string" == attributeType || "NOMAD::ArrayOfString" == attributeType)
364  {
365  if ("\"\"" == attributeDefault || "-" == attributeDefault || "N/A" == attributeDefault)
366  {
367  attributeDefault.clear();
368  }
369  }
370 
371  oss << " \"" << attributeDefault << "\", ";
372 
373  // Read attribute short info
374  // The block delimiter string must be "\(" and "\)" in the text
375  // file but the string passed to the function must be preceeded
376  // by the escape symbol "\"
377  // We use raw string literals (R) to avoid escaping of any character. Anything between the delimiters becomes part of the string.
378  std::string attributeShortInfo = readBlockOfLines( fin, lineNumber ,R"f(\()f" , R"f(\))f" );
379  oss << " \"" << attributeShortInfo << "\", " ;
380 
381 
382  // Read attribute help info
383  // The block delimiter string must be "\(" and "\)" in the text
384  // file but the string passed to the function must be preceeded
385  // by the escape symbol "\"
386  // We use raw string literals (R) to avoid escaping of any character. Anything between the delimiters becomes part of the string.
387  std::string attributeHelpInfo = readBlockOfLines( fin , lineNumber , R"f(\()f", R"f(\))f");
388 
389 
390  //Put attributeDefault value as a special line of HelpInfo
391  bool flagEmpty = attributeDefault.empty() || attributeDefault=="\"\"";
392  bool flagNoDefault = attributeDefault=="-";
393  attributeHelpInfo += ". ";
394  if (flagNoDefault)
395  {
396  attributeHelpInfo += "No default value.";
397  }
398  else if (flagEmpty)
399  {
400  attributeHelpInfo += "Default: Empty string.";
401  }
402  else
403  {
404  attributeHelpInfo += "Default: " + attributeDefault;
405  }
406  attributeHelpInfo += "\\n\\n";
407 
408  oss << " \"" << attributeHelpInfo << "\", ";
409 
410  // Read keywords
411  // The block delimiter string must be "\(" and "\)" in the text
412  // file but the string passed to the function must be preceeded
413  // by the escape symbol "\"
414  // We use raw string literals (R) to avoid escaping of any character. Anything between the delimiters becomes part of the string.
415  std::string attributeKeywords = readBlockOfLines( fin , lineNumber , R"f(\()f", R"f(\))f");
416  duplicateParPlurals(attributeKeywords);
417  oss << " \"" << attributeKeywords << "\" ";
418 
419 
420  // Read optional flags for attribute
421  getline(fin, line);
422  lineNumber++;
423  std::string attributeFlagName,attributeFlagValue;
424 
425  // Set the flag value to default
426  attributeFlags = attributeFlagsRegistered ;
427 
428  while ( line.size() > 0 && line.find_first_of("#") != 0 )
429  {
430  iss.clear();
431  iss.str(line);
432  iss >> attributeFlagName >> attributeFlagValue;
433 
434  if ( attributeFlagName.size()==0 || attributeFlagValue.size()==0 )
435  {
436  errMsg = " An attribute flag name and value (bool) is expected (ex. RESTART_ATTRIBUTE yes). \n An empty line or a missing flag value (bool) is not valid.";
437  throw ( Exception(lineNumber,errMsg) );
438  }
439 
440  // Toupper the attribute flag name
441  toUpperCase( attributeFlagName );
442 
443  if ( attributeFlags.find(attributeFlagName) != attributeFlags.end() )
444  {
445  // The flag name is registered --> update the flag value
446 
447  toUpperCase( attributeFlagValue );
448  if ( attributeFlagValue.compare("YES")==0 || attributeFlagValue.compare("TRUE")==0 )
449  attributeFlags[attributeFlagName] = true;
450  else if ( attributeFlagValue.compare("NO")==0 || attributeFlagValue.compare("FALSE")==0 )
451  attributeFlags[attributeFlagName] = false;
452  else
453  {
454  errMsg = " An attribute flag name and value (bool) is expected (ex. RESTART_ATTRIBUTE yes). \n The value must be YES/TRUE or NO/FALSE.";
455  throw ( Exception(lineNumber,errMsg) );
456  }
457  }
458  else
459  {
460  errMsg = " An attribute flag name and value (bool) is expected (ex. RESTART_ATTRIBUTE yes).\n This flag name: " + attributeFlagName + " is not registered.";
461  throw ( Exception(lineNumber,errMsg) );
462  }
463 
464  getline(fin, line);
465  lineNumber++;
466  }
467 
468  // Write the flag in the registered order
469  for ( auto attFlag : attributeFlags )
470  {
471  oss << " , \"" << ((attFlag.second) ? "true":"false") << "\"";
472  }
473  oss << " }";
474 
475  getline(fin, line);
476  lineNumber++;
477 
478  firstAttribute = false;
479 
480  }
481  oss << " };";
482  oss << std::endl << std::endl << "#endif" << std::endl;
483 
484 
485  // input file is closed:
486  fin.close();
487 
488  // write header
489  // Default error message for problem opening file
490  fout.open( attDefHeader );
491 
492  if ( fout.fail() )
493  {
494  errMsg = " Failed to open the header file for writing attribute definition.";
495  throw ( Exception(0,errMsg) );
496  }
497  fout << oss.str() ;
498  fout.close();
499 
500  flagInFile = false;
501 
502  }
503  catch ( Exception & e)
504  {
505  fin.close();
506  std::cerr << "ERROR: Problem handling file for attribute definition: " << ((flagInFile) ? attDefFile:attDefHeader) << " at line " << e.getLineNumber() << ". \n" << e.what() << std::endl << std::endl;
507  return -1;
508  }
509  }
510  return 0;
511 }
512 
Exception::what
const char * what(void) const noexcept
Access to the error message.
Definition: WriteAttributeDefinitionFile.cpp:107
attributeFlagsRegistered
const std::map< std::string, bool > attributeFlagsRegistered
Registered attribute flags and default value.
Definition: WriteAttributeDefinitionFile.cpp:74
Exception::getLineNumber
size_t getLineNumber(void) const noexcept
Definition: WriteAttributeDefinitionFile.cpp:108
attributeDefinitionNames
const std::string attributeDefinitionNames[7]
Definition: WriteAttributeDefinitionFile.cpp:61
toupper
void toupper(std::string &s)
Put a string into upper cases.
Definition: utils.cpp:84
readBlockOfLines
std::string readBlockOfLines(std::ifstream &fin, size_t &lineNumber, const std::string &blockDelimiterOpen, const std::string &blockDelimiterClose)
Utility to read a block of lines.
Definition: WriteAttributeDefinitionFile.cpp:154
Exception
Exception utility.
Definition: WriteAttributeDefinitionFile.cpp:86
duplicateParPlurals
void duplicateParPlurals(std::string &blockOfStrings)
Utility to interpret plural words.
Definition: WriteAttributeDefinitionFile.cpp:113
Exception::Exception
Exception(size_t line, const std::string &msg)
Definition: WriteAttributeDefinitionFile.cpp:96
Exception::_line
size_t _line
Line number at which the exception is thrown.
Definition: WriteAttributeDefinitionFile.cpp:92
Exception::_what
std::string _what
Error message.
Definition: WriteAttributeDefinitionFile.cpp:91
main
int main(int argc, char *argv[])
Definition: WriteAttributeDefinitionFile.cpp:205
Exception::~Exception
virtual ~Exception(void)
Destructor.
Definition: WriteAttributeDefinitionFile.cpp:101
toUpperCase
void toUpperCase(std::string &str)
Toupper utility.
Definition: WriteAttributeDefinitionFile.cpp:80