1 /*  _______________________________________________________________________
2 
3     Surfpack: A Software Library of Multidimensional Surface Fitting Methods
4     Copyright (c) 2006, Sandia National Laboratories.
5     This software is distributed under the GNU Lesser General Public License.
6     For more information, see the README file in the top Surfpack directory.
7     _______________________________________________________________________ */
8 
9 #include "surfpack.h"
10 #include "AxesBounds.h"
11 #include "SurfpackParserArgs.h"
12 #include "SurfpackParser.h"
13 #include "SurfpackInterface.h"
14 #include "SurfpackInterpreter.h"
15 #include "SurfData.h"
16 #include "ModelFactory.h"
17 #include "SurfpackModel.h"
18 
19 using std::cerr;
20 using std::cout;
21 using std::endl;
22 using std::ostream;
23 using std::runtime_error;
24 using std::string;
25 using std::vector;
26 using std::ostringstream;
27 ///////////////////////////////////////////////////////////////////////////////
28 /////		SurfpackInterpreter namespace functions			  /////
29 ///////////////////////////////////////////////////////////////////////////////
30 
SurfpackInterpreter()31 SurfpackInterpreter::SurfpackInterpreter() : parser(SurfpackParser::instance())
32 {
33 
34 }
35 
~SurfpackInterpreter()36 SurfpackInterpreter::~SurfpackInterpreter()
37 {
38 
39 }
40 
execute(const string * input_string,const string * output_string)41 void SurfpackInterpreter::execute(const string* input_string,
42   const string* output_string)
43 {
44   if (parser.yyparse(input_string, output_string) == 0) {
45     commandLoop(cout , cerr);
46   } else {
47     cerr << "Command(s) not executed." << endl;
48     cerr << SurfpackParser::cmdstream.str() << endl;
49   }
50 }
51 
commandLoop(ostream & os,ostream & es)52 void SurfpackInterpreter::commandLoop(ostream& os, ostream& es)
53 {
54   const vector<ParsedCommand>& fullCommands = parser.commandList();
55   vector<Command>& commands = parser.comms;
56   for (unsigned i = 0; i < commands.size(); i++) {
57     try {
58       //if (commands[i].isShellCommand()) {
59       //  executeShellCommand(commands[i]);
60       if (commands[i].first == "CreateSample") {
61         execCreateSample(commands[i].second);
62       } else if (commands[i].first== "CreateSurface") {
63         execCreateSurface(commands[i].second);
64       } else if (commands[i].first == "Evaluate") {
65         execEvaluate(commands[i].second);
66       } else if (commands[i].first == "Fitness") {
67         execFitness(commands[i].second);
68       } else if (commands[i].first == "Load") {
69         execLoad(commands[i].second);
70       } else if (commands[i].first == "Save") {
71         execSave(commands[i].second);
72       } else if (commands[i].first == "CreateAxes") {
73         execCreateAxes(commands[i].second);
74       } else {
75         es << "Unrecognized command: " << commands[i].first << endl;
76       }
77     } catch (string& msg) {
78       es << "Error: " << msg;
79       es << "\n  Failed Instruction: " << fullCommands[i].cmdstring << endl;
80     } catch (std::exception& e) {
81       es << "Exception: " << e.what()
82 	 << "\n  Failed Instruction: " << fullCommands[i].cmdstring << endl;
83     } catch (...) {
84       es << "Exception (unknown)\n  FailedInstruction: "
85 	 << fullCommands[i].cmdstring << endl;
86     }
87   }
88 }
89 
getResponseIndex(const ArgList & arglist,const SurfData & sd)90 int getResponseIndex(const ArgList& arglist, const SurfData& sd)
91 {
92   bool valid;
93   bool is_response;
94   unsigned int response_index;
95   string response_name = SurfpackParser::parseIdentifier("response",
96 	arglist,false);
97   if (response_name == "") {
98       response_index =
99       SurfpackParser::parseInteger("response_index",arglist,valid,false);
100       if (!valid) {
101         // Neither response nor response_index specified
102         // Default index is 0
103         return 0;
104       } else {
105         return response_index;
106       }
107   } else {
108     ostringstream os;
109     valid = sd.varIndex(response_name, response_index, is_response);
110     if (!valid) {
111       os << "No response named '" << response_name << "' found." << endl;
112       throw(os.str());
113     } else if (!is_response) {
114       os << "'" << response_name << "' is a predictor variable, but a"
115 	   << " response variable was requested" << endl;
116       throw(os.str());
117     } else {
118       return response_index;
119     }
120   }
121 }
122 
123 ///////////////////////////////////////////////////////////////////////////////
124 /////		SurfpackInterpreter namespace functions			  /////
125 ///////////////////////////////////////////////////////////////////////////////
126 
execLoad(ParamMap & args)127 void SurfpackInterpreter::execLoad(ParamMap& args)
128 {
129   bool valid;
130   string filename = asStr(args["file"]);
131   if (surfpack::hasExtension(filename,".sps") ||
132       surfpack::hasExtension(filename,".bsps")) {
133     execLoadSurface(args);
134   } else if (surfpack::hasExtension(filename,".spd") ||
135 	     surfpack::hasExtension(filename,".bspd") ||
136 	     surfpack::hasExtension(filename,".dat")) {
137     execLoadData(args);
138   } else {
139     throw string("Expected file extension: .sps/.bsps (surface) or "
140 		 ".spd/.bspd/.dat (data)");
141   }
142 }
143 
execLoadData(ParamMap & args)144 void SurfpackInterpreter::execLoadData(ParamMap& args)
145 {
146   try {
147   SurfData* data = 0;
148   string name = asStr(args["name"]);
149   string filename = asStr(args["file"]);
150   bool valid = false;
151   int n_vars = asInt(args["n_predictors"],valid);
152   if (valid) {
153     // n_responses is required if n_vars is present
154     int n_responses = asInt(args["n_responses"]); // fail on error
155     int n_cols_to_skip = asInt(args["n_cols_to_skip"],valid);
156     if (!valid) n_cols_to_skip = 0;
157     data = SurfpackInterface::LoadData(filename,n_vars,n_responses,n_cols_to_skip);
158   } else {
159     data = SurfpackInterface::LoadData(filename);
160   }
161   assert(data);
162   symbolTable.dataVars.insert(SurfDataSymbol(name,data));
163   } catch (...) {
164     cout << "Error caught in execLoadData: Did you forget to specify n_predictors and n_responses?" << endl;
165   }
166 }
167 
168 ///\todo Add support for LoadSurface in interpreter
execLoadSurface(ParamMap & args)169 void SurfpackInterpreter::execLoadSurface(ParamMap& args)
170 {
171   string name = asStr(args["name"]);
172   string filename = asStr(args["file"]);
173   SurfpackModel* model = SurfpackInterface::LoadModel(filename);
174   symbolTable.modelVars.insert(SurfpackModelSymbol(name, model));
175 }
176 
execSaveData(ParamMap & args)177 void SurfpackInterpreter::execSaveData(ParamMap& args)
178 {
179   string data_name = asStr(args["data"]);
180   string filename = asStr(args["file"]);
181   SurfData* sd = symbolTable.lookupData(data_name);
182   // Call SaveData
183   SurfpackInterface::Save(sd, filename);
184 }
185 
186 
execSaveSurface(const SurfpackModel * model,const string & filename)187 void SurfpackInterpreter::execSaveSurface(const SurfpackModel* model,
188 					  const string& filename)
189 {
190   SurfpackInterface::Save(model, filename);
191 }
192 
193 
execSave(ParamMap & args)194 void SurfpackInterpreter::execSave(ParamMap& args)
195 {
196   try {
197     string filename = asStr(args["file"]);
198     // Don't automatically fail if either of these isn't defined
199     bool valid_data;
200     string data_name = asStr(args["data"],valid_data);
201     bool valid_model;
202     string model_name = asStr(args["surface"],valid_model);
203     if (!valid_data) {
204       if (!valid_model) {
205         // Do fail if both are missing
206         throw string("Save command requires either 'surface' or 'data' argument");
207       } else {
208         SurfpackModel* model = symbolTable.lookupModel(model_name);
209 	execSaveSurface(model, filename);
210       }
211     } else {
212       if (valid_model) {
213         // Fail if both are specified
214         throw string("Save command may not have both 'surface' and 'data' arguments");
215       } else {
216         SurfData* sd = symbolTable.lookupData(data_name);
217         sd->write(filename);
218       }
219     }
220   } catch (string& e) {
221     cout << "Error (Save): " << e << endl;
222   } catch (std::exception& e) {
223     cout << "Exception (Save): " << e.what() << endl;
224   } catch (...) {
225     cout << "Exception (Save, unknown)" << endl;
226   }
227 }
228 
229 //int getResponseIndex(const ArgList& arglist, const SurfData& sd)
230 //{
231 //  bool valid;
232 //  bool is_response;
233 //  unsigned int response_index;
234 //  string response_name = SurfpackParser::parseIdentifier("response",
235 //	arglist,false);
236 //  if (response_name == "") {
237 //      response_index =
238 //      SurfpackParser::parseInteger("response_index",arglist,valid,false);
239 //      if (!valid) {
240 //        // Neither response nor response_index specified
241 //        // Default index is 0
242 //        return 0;
243 //      } else {
244 //        return response_index;
245 //      }
246 //  } else {
247 //    ostringstream os;
248 //    valid = sd.varIndex(response_name, response_index, is_response);
249 //    if (!valid) {
250 //      os << "No response named '" << response_name << "' found." << endl;
251 //      throw(os.str());
252 //    } else if (!is_response) {
253 //      os << "'" << response_name << "' is a predictor variable, but a"
254 //	   << " response variable was requested" << endl;
255 //      throw(os.str());
256 //    } else {
257 //      return response_index;
258 //    }
259 //  }
260 //}
261 //
execCreateSurface(ParamMap & args)262 void SurfpackInterpreter::execCreateSurface(ParamMap& args)
263 {
264   // Extract the variable name for this SurfData object
265   string name = asStr(args["name"]);
266   string data = asStr(args["data"]);
267   bool valid = false;
268   SurfData* sd = symbolTable.lookupData(data);
269   // Call CreateSurface
270   SurfpackModelFactory* smf = ModelFactory::createModelFactory(args);
271   SurfpackModel* model = smf->Build(*sd);
272   delete smf;
273   assert(model);
274   symbolTable.modelVars.insert(SurfpackModelSymbol(name,model));
275 }
276 
execCreateSample(ParamMap & args)277 void SurfpackInterpreter::execCreateSample(ParamMap& args)
278 {
279   // Extract the variable name for this SurfData object
280   string name = asStr(args["name"]);
281   string axes = asStr(args["axes"]);
282   bool valid_grid_points;
283   VecUns grid_points = asVecUns(args["grid_points"], valid_grid_points);
284   bool valid_size = false;
285   int n_points = asInt(args["size"],valid_size);
286   AxesBounds* ab = symbolTable.lookupAxes(axes);
287   SurfData* sd = 0;
288   if (valid_size) {
289     if (valid_grid_points) { // both size and grid_points specified
290       throw string("Cannot specify both size and grid_points");
291     } else { // only size specified
292 	// MonteCarlo sample
293       sd = SurfpackInterface::CreateSample(ab,n_points);
294     }
295   } else {
296     if (!grid_points.empty()) { // only grid_points specified
297 	// grid sample
298       sd = SurfpackInterface::CreateSample(ab,grid_points);
299     } else { // neither specified
300       throw string("Must specify either size or grid_points");
301     }
302   }
303   bool valid_functions;
304   VecStr test_functions = asVecStr(args["test_functions"], valid_functions);
305   if (valid_functions) {
306     SurfpackInterface::Evaluate(sd,test_functions);
307   }
308   symbolTable.dataVars.insert(SurfDataSymbol(name,sd));
309 }
310 
execEvaluate(ParamMap & args)311 void SurfpackInterpreter::execEvaluate(ParamMap& args)
312 {
313   // Extract the variable name for this SurfData object
314   string surf_name = asStr(args["surface"]);
315   string data = asStr(args["data"]);
316   SurfpackModel* model = symbolTable.lookupModel(surf_name);
317   SurfData* sd = symbolTable.lookupData(data);
318   // Call Evaluate
319   VecDbl results = (*model)(*sd);
320   sd->addResponse(results,args["label"]);
321 }
322 
execFitness(ParamMap & args)323 void SurfpackInterpreter::execFitness(ParamMap& args)
324 {
325   string surface = asStr(args["surface"]);
326   bool valid_data;
327   string data = asStr(args["data"],valid_data);
328   SurfpackModel* model = symbolTable.lookupModel(surface);
329   SurfData* sd = 0;
330   if (valid_data) {
331     sd = symbolTable.lookupData(data);
332   }
333   string metric = asStr(args["metric"]);
334   // Extract the response index for the input data set
335   bool valid_response_index;
336   int response_index = asInt(args["response_index"],valid_response_index);
337   bool valid_n;
338   int n = asInt(args["n"],valid_n);
339   if (!valid_response_index) { // No response_index was specified, use 0
340     response_index = 0;
341   }
342   double fitness;
343   if (valid_data) {
344     fitness = SurfpackInterface::Fitness(model,sd,metric,response_index,n);
345   } else {
346     fitness = SurfpackInterface::Fitness(model,metric,response_index,n);
347   }
348   cout << metric << " for " << surface;
349   if (data != "") cout << " on " << data;
350   cout << ": " << fitness << endl;
351 }
352 
execCreateAxes(ParamMap & args)353 void SurfpackInterpreter::execCreateAxes(ParamMap& args)
354 {
355   string name = asStr(args["name"]);
356   string bounds = asStr(args["bounds"]);
357   AxesBounds* ab = SurfpackInterface::CreateAxes(bounds);
358   symbolTable.axesVars.insert(AxesBoundsSymbol(name,ab));
359 }
360 //
361 //void SurfpackInterpreter::
362 //  executeShellCommand(ParamMap& args)
363 //{
364 //  system(c.cmdstring.c_str());
365 //}
366 
asInt(const string & arg)367 int SurfpackInterpreter::asInt(const string& arg)
368 {
369   if (arg == "") throw string("Expected integer value");
370   return atoi(arg.c_str());
371 }
372 
asStr(const string & arg)373 std::string SurfpackInterpreter::asStr(const string& arg)
374 {
375   if (arg == "") throw string("Expected string value");
376   return arg;
377 }
378 
asDbl(const string & arg)379 double SurfpackInterpreter::asDbl(const string& arg)
380 {
381   if (arg == "") throw string("Expected double value");
382   return atof(arg.c_str());
383 }
384 
asVecUns(const string & arg)385 VecUns SurfpackInterpreter::asVecUns(const string& arg)
386 {
387   if (arg == "") throw string("Expected vector unsigned");
388   return surfpack::toVec<unsigned>(arg);
389 }
390 
asVecStr(const string & arg)391 VecStr SurfpackInterpreter::asVecStr(const string& arg)
392 {
393   if (arg == "") throw string("Expected vector string");
394   return surfpack::toVec<std::string>(arg);
395 }
396 
asInt(const string & arg,bool & valid)397 int SurfpackInterpreter::asInt(const string& arg, bool& valid)
398 {
399   if (arg == "") {
400     valid = false;
401     return 0;
402   }
403   valid = true;
404   return atoi(arg.c_str());
405 }
406 
asStr(const string & arg,bool & valid)407 std::string SurfpackInterpreter::asStr(const string& arg, bool& valid)
408 {
409   if (arg == "") {
410     valid = false;
411     return "";
412   }
413   valid = true;
414   return arg;
415 }
416 
asDbl(const string & arg,bool & valid)417 double SurfpackInterpreter::asDbl(const string& arg, bool& valid)
418 {
419   if (arg == "") {
420     valid = false;
421     return 0;
422   }
423   valid = true;
424   return atof(arg.c_str());
425 }
426 
asVecUns(const string & arg,bool & valid)427 VecUns SurfpackInterpreter::asVecUns(const string& arg, bool& valid)
428 {
429   if (arg == "") {
430     valid = false;
431     return VecUns();
432   }
433   valid = true;
434   return surfpack::toVec<unsigned>(arg);
435 }
436 
asVecStr(const string & arg,bool & valid)437 VecStr SurfpackInterpreter::asVecStr(const string& arg, bool& valid)
438 {
439   if (arg == "") {
440     valid = false;
441     return VecStr();
442   }
443   valid = true;
444   return surfpack::toVec<std::string>(arg);
445 }
446 //********************************************************************
~SymbolTable()447 SurfpackInterpreter::SymbolTable::~SymbolTable()
448 {
449   for (SurfDataMap::iterator iter = dataVars.begin();
450        iter != dataVars.end();
451        ++iter) {
452     delete iter->second;
453   }
454   for (SurfpackModelMap::iterator iter = modelVars.begin();
455        iter != modelVars.end();
456        ++iter) {
457     delete iter->second;
458   }
459   for (AxesBoundsMap::iterator iter = axesVars.begin();
460        iter != axesVars.end();
461        ++iter) {
462     delete iter->second;
463   }
464 }
465 
466 SurfpackModel*
lookupModel(const std::string name)467 SurfpackInterpreter::SymbolTable::lookupModel(const std::string name)
468 {
469   SurfpackModel* result = modelVars[name];
470   if (result == 0) {
471     cout << "Bad lookup; table size:  " << modelVars.size() << endl;
472     for (SurfpackModelMap::iterator itr = modelVars.begin();
473         itr != modelVars.end(); ++itr) {
474       cout << itr->first << " " << itr->second << endl;
475     }
476 
477     string msg = "Model variable " + name + " not found in symbol table.";
478     throw msg;
479   }
480   return result;
481 }
482 
lookupData(string name)483 SurfData* SurfpackInterpreter::SymbolTable::lookupData(string name)
484 {
485   SurfDataMap::iterator iter = dataVars.find(name);
486   if (iter == dataVars.end()) {
487     string msg = "Data variable " + name + " not found in symbol table.";
488     throw msg;
489   }
490   assert(iter->second);
491   return iter->second;
492 }
493 
lookupAxes(string name)494 AxesBounds* SurfpackInterpreter::SymbolTable::lookupAxes(string name)
495 {
496   AxesBoundsMap::iterator iter = axesVars.find(name);
497   if (iter == axesVars.end()) {
498     string msg = "Axes variable " + name + " not found in symbol table.";
499     throw msg;
500   }
501   assert(iter->second);
502   return iter->second;
503 }
504