1 /*  _______________________________________________________________________
2 
3     DAKOTA: Design Analysis Kit for Optimization and Terascale Applications
4     Copyright 2014-2020 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
5     This software is distributed under the GNU Lesser General Public License.
6     For more information, see the README file in the top Dakota directory.
7     _______________________________________________________________________ */
8 
9 // Results database supporting definitions
10 //  * Data type definitions for keys and meta data
11 //  * Free helper functions to create and manage data entries
12 
13 #ifndef DAKOTA_RESULTS_TYPES_H
14 #define DAKOTA_RESULTS_TYPES_H
15 
16 #include <map>
17 #include <vector>
18 #include <algorithm>
19 #include <boost/tuple/tuple.hpp>
20 #include "dakota_data_types.hpp"
21 #include <boost/any.hpp>
22 #include <boost/variant.hpp>
23 #include <iostream>
24 
25 namespace Dakota {
26 
27 // TODO: Using a tokenized string "instance::execution::result_key" or
28 // a list of keys might be more flexible going forward, instead of tuple.
29 
30 // -----------
31 // Results Key
32 // -----------
33 
34 /// Data type for results key (instance name / id, unique run, label),
35 /// where data_key is a valid colon-delimited string from ResultsNames
36 /// tuple<method_name, method_id, execution_number, data_key>
37 typedef
38 boost::tuple<std::string, std::string, size_t, std::string> ResultsKeyType;
39 
40 
41 // -----------
42 // Results Data
43 // -----------
44 
45 // NOTE: the ResultsDataType varies by underlying database
46 
47 
48 // ----------------
49 // Results Metadata
50 // ----------------
51 
52 /// Data type for metadata key
53 typedef std::string MetaDataKeyType;
54 
55 /// Data type for metadata value
56 typedef std::vector<std::string> MetaDataValueType;
57 
58 /// A single MetaData entry is map<string, vector<string> >  Example:
59 ///   pair( "Column labels", ["Mean", "Std Dev", "Skewness", "Kurtosis"] )
60 typedef std::map<MetaDataKeyType, MetaDataValueType> MetaDataType;
61 
62 
63 // --------------
64 // Other Typedefs
65 // --------------
66 
67 // TODO: This can probably go away
68 //typedef std::pair<std::string, size_t> StringSizetPair;
69 
70 /// Iterator unique ID: <method_name, method_id, exec_num>
71 typedef boost::tuple<std::string, std::string, size_t> StrStrSizet;
72 
73 /// Make a full ResultsKeyType from the passed iterator_id and data_name
74 ResultsKeyType make_key(const StrStrSizet& iterator_id,
75 			const std::string& data_name);
76 
77 /// create MetaDataValueType from the passed strings
78 MetaDataValueType
79 make_metadatavalue(StringMultiArrayConstView labels);
80 
81 /// create MetaDataValueType from the passed strings
82 MetaDataValueType
83 make_metadatavalue(StringMultiArrayConstView cv_labels,
84 		   StringMultiArrayConstView div_labels,
85 		   StringMultiArrayConstView drv_labels,
86 		   const StringArray& resp_labels);
87 
88 /// create MetaDataValueType from the passed strings
89 MetaDataValueType
90 make_metadatavalue(const StringArray& resp_labels);
91 
92 /// create MetaDataValueType from the passed strings
93 MetaDataValueType
94 make_metadatavalue(const std::string&);
95 
96 /// create MetaDataValueType from the passed strings
97 MetaDataValueType
98 make_metadatavalue(const std::string&, const std::string&);
99 
100 /// create MetaDataValueType from the passed strings
101 MetaDataValueType
102 make_metadatavalue(const std::string&, const std::string&,
103 		   const std::string&);
104 
105 /// create MetaDataValueType from the passed strings
106 MetaDataValueType
107 make_metadatavalue(const std::string&, const std::string&,
108 		   const std::string&, const std::string&);
109 
110 
111 
112 // Inline definitions of helper functions
113 
114 inline MetaDataValueType
make_metadatavalue(StringMultiArrayConstView labels)115 make_metadatavalue(StringMultiArrayConstView labels)
116 {
117   MetaDataValueType mdv;
118   for (size_t i=0; i<labels.size(); ++i)
119     mdv.push_back(labels[i]);
120   return mdv;
121 }
122 
123 
124 inline MetaDataValueType
make_metadatavalue(StringMultiArrayConstView cv_labels,StringMultiArrayConstView div_labels,StringMultiArrayConstView dsv_labels,StringMultiArrayConstView drv_labels,const StringArray & resp_labels)125 make_metadatavalue(StringMultiArrayConstView cv_labels,
126 		   StringMultiArrayConstView div_labels,
127 		   StringMultiArrayConstView dsv_labels,
128 		   StringMultiArrayConstView drv_labels,
129 		   const StringArray& resp_labels)
130 {
131   // could use iterators for some of these
132   MetaDataValueType mdv;
133   for (size_t i=0; i<cv_labels.size(); ++i)
134     mdv.push_back(cv_labels[i]);
135   for (size_t i=0; i<div_labels.size(); ++i)
136     mdv.push_back(div_labels[i]);
137   for (size_t i=0; i<dsv_labels.size(); ++i)
138     mdv.push_back(dsv_labels[i]);
139   for (size_t i=0; i<drv_labels.size(); ++i)
140     mdv.push_back(drv_labels[i]);
141   for (size_t i=0; i<resp_labels.size(); ++i)
142     mdv.push_back(resp_labels[i]);
143 
144   return mdv;
145 }
146 
147 inline MetaDataValueType
make_metadatavalue(const StringArray & resp_labels)148 make_metadatavalue(const StringArray& resp_labels)
149 {
150   // could use iterators for some of these
151   MetaDataValueType mdv;
152   for (size_t i=0; i<resp_labels.size(); ++i)
153     mdv.push_back(resp_labels[i]);
154 
155   return mdv;
156 }
157 
158 inline MetaDataValueType
make_metadatavalue(const std::string & s1)159 make_metadatavalue(const std::string& s1)
160 {
161   MetaDataValueType mdv;
162   mdv.push_back(s1);
163   return mdv;
164 }
165 
166 inline MetaDataValueType
make_metadatavalue(const std::string & s1,const std::string & s2)167 make_metadatavalue(const std::string& s1, const std::string& s2)
168 {
169   MetaDataValueType mdv;
170   mdv.push_back(s1);
171   mdv.push_back(s2);
172   return mdv;
173 }
174 
175 inline MetaDataValueType
make_metadatavalue(const std::string & s1,const std::string & s2,const std::string & s3)176 make_metadatavalue(const std::string& s1, const std::string& s2,
177 		   const std::string& s3)
178 {
179   MetaDataValueType mdv;
180   mdv.push_back(s1);
181   mdv.push_back(s2);
182   mdv.push_back(s3);
183   return mdv;
184 }
185 
186 inline MetaDataValueType
make_metadatavalue(const std::string & s1,const std::string & s2,const std::string & s3,const std::string & s4)187 make_metadatavalue(const std::string& s1, const std::string& s2,
188 		   const std::string& s3, const std::string& s4)
189 {
190   MetaDataValueType mdv;
191   mdv.push_back(s1);
192   mdv.push_back(s2);
193   mdv.push_back(s3);
194   mdv.push_back(s4);
195   return mdv;
196 }
197 
make_key(const StrStrSizet & iterator_id,const std::string & data_name)198 inline ResultsKeyType make_key(const StrStrSizet& iterator_id,
199 			       const std::string& data_name)
200 {
201   return ResultsKeyType(iterator_id.get<0>(),
202 			iterator_id.get<1>(),
203 			iterator_id.get<2>(),
204 			data_name);
205 }
206 
207 // The following structs and typedefs are used to insert
208 // results into the results database using the
209 // ResultsManager interface.
210 //
211 // The first set of items are for specifying dimension
212 // scales, which are labels (strings or reals) for each
213 // axis of a set of data (vector or matrix, currently).
214 //
215 // Dimension scales are of type multimap<int, boost::variant>
216 // (typedef'ed to DimScaleMap), with the integer indicating the
217 // dimenions of the dataset that the scale is associated with,
218 // and the boost::variant containing the scale
219 // itself, either a RealScale or a StringScale. These latter
220 // types are structs that contain a label, which is like a
221 // heading for the scale, the items in the scale, and a
222 // ScaleScope enum, which determines whether the scale is
223 // SHARED among multiple responses or is unique to a particular
224 // response (UNHSARED).
225 
226 /// Enum to specify whether a scale shared among responses
227 enum class ScaleScope {SHARED, UNSHARED};
228 
229 // RealScale and StringScale avoid making copies of data to
230 // save memory, which may be important for large results.
231 // For HDF5, the scales are immediately written to disk, and so
232 // it's not necessary for the client to preserve objects in
233 // memory after using a RealScale or StringScale in a call
234 // to ResultsManager.insert(...).
235 
236 /// Data structure for storing real-valued dimension scale
237 struct RealScale {
238 
239   /// Constructor that takes a RealVector
RealScaleDakota::RealScale240   RealScale(const std::string &label, const RealVector &in_items,
241           ScaleScope scope = ScaleScope::UNSHARED) :
242           label(label), scope(scope) {
243     items = RealVector(Teuchos::View, *const_cast<RealVector*>(&in_items));
244     numCols = items.length();
245     isMatrix = false;
246   }
247 
248   /// Constructor that takes a RealArray
RealScaleDakota::RealScale249   RealScale(const std::string &label, const RealArray &in_items,
250           ScaleScope scope = ScaleScope::UNSHARED) :
251           label(label), scope(scope) {
252     items = RealVector(Teuchos::View, const_cast<Real*>(in_items.data()),
253         in_items.size());
254     numCols = items.length();
255     isMatrix = false;
256   }
257 
258   /// Constructor that takes a pointer to Real and length
RealScaleDakota::RealScale259   RealScale(const std::string &label, const Real *in_items, const int len,
260           ScaleScope scope = ScaleScope::UNSHARED) :
261           label(label), scope(scope) {
262     items = RealVector(Teuchos::View,
263         const_cast<Real*>(in_items), len);
264     numCols = items.length();
265     isMatrix = false;
266   }
267 
268   /// Constructor that takes an initializer_list.
RealScaleDakota::RealScale269   RealScale(const std::string & in_label,
270         std::initializer_list<Real> in_items,
271         ScaleScope in_scope = ScaleScope::UNSHARED) {
272     label = in_label;
273     int len = in_items.size();
274     items = RealVector(len);
275     // make a copy. Typically initializer_lists should be short, so this
276     // is excusable.
277     std::copy(in_items.begin(), in_items.end(), &items[0]);
278     scope = in_scope;
279     numCols = len;
280     isMatrix = false;
281   }
282 
283   /// Constructor that takes a RealVectorArray
RealScaleDakota::RealScale284   RealScale(const std::string & in_label,
285         const RealVectorArray &in_items,
286         ScaleScope in_scope = ScaleScope::UNSHARED) {
287     label = in_label;
288     int num_rows = in_items.size();
289     numCols = in_items[0].length(); // assume all "rows" are the same length
290     items = RealVector(num_rows*numCols);
291     // impossible to avoid making a copy in this case.
292     for(int i = 0; i < num_rows; ++i)
293       for(int j = 0; j < numCols; ++j)
294         items[j*num_rows+i] = in_items[i][j]; // deliberately transposed. See AttachScaleVisitor in ResultsDBHDF5.hpp.
295     scope = in_scope;
296     isMatrix = true;
297   }
298 
299   // Name of the scale
300   std::string label;
301   // Scope of the scale (whether it is shared among responses)
302   ScaleScope scope;
303   // Items in the scale; column-major when isMatrix is true
304   RealVector items;
305   /// Number of columns; equals length of scale when 1D
306   int numCols;
307   /// 2d or 1d?
308   bool isMatrix;
309 };
310 
311 /// Data structure for storing int-valued dimension scale
312 struct IntegerScale {
313 
314   /// Constructor that takes an IntVector
IntegerScaleDakota::IntegerScale315   IntegerScale(const std::string &label, const IntVector &in_items,
316           ScaleScope scope = ScaleScope::UNSHARED) :
317           label(label), scope(scope) {
318     items = IntVector(Teuchos::View, *const_cast<IntVector*>(&in_items));
319     numCols = items.length();
320     isMatrix = false;
321   }
322 
323   /// Constructor that takes an IntArray
IntegerScaleDakota::IntegerScale324   IntegerScale(const std::string &label, const IntArray &in_items,
325           ScaleScope scope = ScaleScope::UNSHARED) :
326           label(label), scope(scope) {
327     items = IntVector(Teuchos::View, const_cast<int*>(in_items.data()),
328         in_items.size());
329     numCols = items.length();
330     isMatrix = false;
331   }
332 
333   /// Constructor that takes a pointer to int and length
IntegerScaleDakota::IntegerScale334   IntegerScale(const std::string &label, const int *in_items, const int len,
335           ScaleScope scope = ScaleScope::UNSHARED) :
336           label(label), scope(scope) {
337     items = IntVector(Teuchos::View,
338         const_cast<int*>(in_items), len);
339     numCols = items.length();
340     isMatrix = false;
341   }
342 
343   /// Constructor that takes an initializer_list.
IntegerScaleDakota::IntegerScale344   IntegerScale(const std::string & in_label,
345         std::initializer_list<int> in_items,
346         ScaleScope in_scope = ScaleScope::UNSHARED) {
347     label = in_label;
348     int len = in_items.size();
349     items = IntVector(len);
350     // make a copy. Typically initializer_lists should be short, so this
351     // is excusable.
352     std::copy(in_items.begin(), in_items.end(), &items[0]);
353     scope = in_scope;
354     numCols = len;
355     isMatrix = false;
356   }
357 
358   // Name of the scale
359   std::string label;
360   // Scope of the scale (whether it is shared among responses)
361   ScaleScope scope;
362   // Items in the scale
363   IntVector items;
364   /// Number of columns; equals length of scale when 1D
365   int numCols;
366   /// 2d or 1d?
367   bool isMatrix;
368 };
369 
370 
371 
372 /// Data structure for storing string-valued dimension scale
373 struct StringScale {
374   /// Constructor that takes a C-style array of C-strings
StringScaleDakota::StringScale375   StringScale(const std::string& in_label, const char * const in_items[],
376           const int &len, ScaleScope in_scope = ScaleScope::UNSHARED) {
377     label = in_label;
378     items.resize(len);
379     std::copy(in_items, in_items + len, items.begin());
380     scope = in_scope;
381     numCols = len;
382     isMatrix = false;
383   }
384 
385   /// Constructor that takes and initializer list of string literals
StringScaleDakota::StringScale386   StringScale(const std::string & in_label,
387         std::initializer_list<const char *> in_items,
388         ScaleScope in_scope = ScaleScope::UNSHARED) {
389     label = in_label;
390     items.resize(in_items.size());
391     std::copy(in_items.begin(), in_items.end(), items.begin());
392     scope = in_scope;
393     numCols = items.size();
394     isMatrix = false;
395   }
396 
397   /// Constructor that takes a vector of strings
StringScaleDakota::StringScale398   StringScale(const std::string& in_label, const std::vector<String> &in_items,
399           ScaleScope in_scope = ScaleScope::UNSHARED) {
400     label = in_label;
401     scope = in_scope;
402     items.resize(in_items.size());
403     std::transform(in_items.begin(), in_items.end(), items.begin(),
404       [](const String &s) { return s.c_str();});
405     numCols = items.size();
406     isMatrix = false;
407   }
408 
409   /// Constructor that takes a vector of C-style strings
StringScaleDakota::StringScale410   StringScale(const std::string & in_label,
411         std::vector<const char *> in_items,
412         ScaleScope in_scope = ScaleScope::UNSHARED) {
413     label = in_label;
414     items.resize(in_items.size());
415     std::copy(in_items.begin(), in_items.end(), items.begin());
416     scope = in_scope;
417     numCols = items.size();
418     isMatrix = false;
419   }
420 
421   /// Constructor that takes a StringMultiArrayConstView
StringScaleDakota::StringScale422    StringScale(const std::string & in_label,
423         const StringMultiArrayConstView in_items,
424         ScaleScope in_scope = ScaleScope::UNSHARED) {
425     label = in_label;
426     for( const auto & s: in_items)
427       items.push_back(s.c_str());
428     scope = in_scope;
429     numCols = items.size();
430     isMatrix = false;
431   }
432 
433   /// Constructor that takes indexes into a StringArray
StringScaleDakota::StringScale434   StringScale(const std::string& in_label, const std::vector<String> &in_items,
435           const size_t first, const size_t num,
436           ScaleScope in_scope = ScaleScope::UNSHARED) {
437     label = in_label;
438     scope = in_scope;
439     items.resize(num);
440     for(int i = first, j = 0; i < first+num; ++i, ++j)
441       items[j] = in_items[i].c_str();
442     numCols = items.size();
443     isMatrix = false;
444   }
445 
446 
447   /// Constructor that takes a vector<vector<const char *> > to produce a 2D scale
StringScaleDakota::StringScale448   StringScale(const std::string & in_label,
449       std::vector<std::vector<const char *> > in_items,
450       ScaleScope in_scope = ScaleScope::UNSHARED) {
451     label = in_label;
452     int num_rows = in_items.size();
453     numCols = in_items[0].size(); // TODO: error checking to confirm a "square matrix"
454     items.resize(num_rows*numCols);
455     int offset = 0;
456     for(auto &v : in_items) {
457       std::copy(v.begin(), v.end(), items.begin() + offset);
458       offset += numCols;
459     }
460     scope = in_scope;
461     isMatrix = true;
462   }
463 
464 
465 
466   /// Scale label
467   std::string label;
468   /// Scale scope (whether the scaled is shared among responses)
469   ScaleScope scope;
470   /// Pointers to the strings that make up the scale
471   std::vector<const char *> items;
472   /// Number of columns; equals length of scale when 1D
473   int numCols;
474   /// 2d or 1d?
475   bool isMatrix;
476 };
477 
478 /// Datatype to communicate scales (stored in boost::variant) and their
479 /// associated dimension (the int) to the ResultsManager instance.
480 typedef std::multimap<int, boost::variant<StringScale, RealScale, IntegerScale> > DimScaleMap;
481 
482 
483 // HDF5 objects can have key:value metadata attached to them. These
484 // are called attributes. We support integer, real, and string valued
485 // metadata  using these type defintions.
486 
487 /// Data structure for a single Real, String, or int valued attribute
488 template <typename T>
489 struct ResultAttribute {
490   /// Construct an attribute
ResultAttributeDakota::ResultAttribute491   ResultAttribute(const String &label, const T &value) :
492     label(label), value(value) {};
493   /// Key for the attribute
494   String label;
495   /// Value for the attribute
496   T value;
497 };
498 
499 /// Datatype to communcate metadata (attributes) to the ResultsManager
500 /// instance.
501 typedef std::vector<boost::variant< ResultAttribute<int>,
502                                     ResultAttribute<String>,
503                                     ResultAttribute<Real> > > AttributeArray;
504 
505 /// enum for setting type on allocted matrix for Results Output
506 enum class ResultsOutputType { REAL, INTEGER, UINTEGER, STRING};
507 
508 struct VariableParametersField {
VariableParametersFieldDakota::VariableParametersField509   VariableParametersField(const String &in_name, ResultsOutputType in_type,
510       const SizetArray &in_dims = SizetArray()) : name(in_name), dims(in_dims), type(in_type) {};
511   String name;
512   SizetArray dims;
513   ResultsOutputType type;
514 };
515 
516 }  // namespace Dakota
517 
518 #endif  // DAKOTA_RESULTS_TYPES_H
519