CASM  1.1.0
A Clusters Approach to Statistical Mechanics
SimpleFormatter.hh
Go to the documentation of this file.
1 #include <functional>
2 #include <string>
3 #include <vector>
4 
5 namespace CASM {
6 
7 namespace simpleformatter {
8 
9 template <typename ObjectType>
10 class DataFormatter;
11 
13  int width = 12;
14  int precision = 8;
15  bool boolalpha = true;
16 };
17 
20 template <typename ObjectType>
21 class BaseDatumEvaluator : public Cloneable {
22  public:
24  virtual std::string const &name() const = 0;
25 
27  virtual void format_value(DataFormatter<ObjectType> &formatter,
28  ObjectType const &object) const = 0;
29 
31  virtual bool is_vector() const = 0;
32 
36  virtual bool is_fixed_size() const = 0;
37 
41  virtual std::vector<std::string> const &component_names() const = 0;
42 
45  ObjectType const &object) const = 0;
46 
48  virtual bool is_map() const = 0;
49 
52  ObjectType const &object) const = 0;
53 };
54 
57 template <typename ObjectType, typename ValueType>
58 class DatumEvaluator : public BaseDatumEvaluator<ObjectType> {
60  public:
62  typedef std::function<ValueType(ObjectType const &object)> ValueF;
63 
65  DatumEvaluator(std::string _name, ValueF _value_f);
66 
68  std::string const &name() const override;
69 
71  ValueType value(ObjectType const &object) const;
72 
75  ObjectType const &object) const override;
76 
78  bool may_be_vectorized() const override { return false; }
79 
83  bool is_fixed_size() const override {
84  throw std::runtime_error{"DatumEvaluator::is_fixed_size: Not implemented"};
85  }
86 
90  std::vector<std::string> const &component_names() const override {
91  throw std::runtime_error{
92  "DatumEvaluator::component_names: Not implemented"};
93  }
94 
98  ObjectType const &object) const override {
99  throw std::runtime_error{
100  "DatumEvaluator::format_vectorized_value: Not implemented"};
101  }
102 
103  private:
104  std::string m_name;
106 };
107 
119 template <typename ObjectType, typename VectorizedValueType>
120 class VectorizedDatumEvaluator : public BaseDatumEvaluator<ObjectType> {
122 
123  public:
125  typedef std::function<VectorizedValueType(ObjectType const &)>
127 
129  typedef std::function<VectorizedValueType(ObjectType const &,
130  std::vector<std::string> &)>
132 
134  VectorizedDatumEvaluator(DynamicVectorizedValueF _dynamic_vectorized_value_f);
135 
138  VectorizedDatumEvaluator(std::vector<std::string> _component_names,
139  FixedVectorizedValueF _vectorized_value_f);
140 
142  bool may_be_vectorized() const override { return true; }
143 
147  bool is_fixed_size() const override { return m_is_fixed_size; }
148 
151  VectorizedValueType vectorized_value(ObjectType const &object) const;
152 
160  std::vector<std::string> const &component_names() const override {
161  return m_component_names;
162  }
163 
177  ObjectType const &object) const override;
178 
179  private:
183  mutable std::vector<std::string> m_component_names;
184 };
185 
186 // /// Make argument expression of form "(arg1, arg2, ..)"
187 // std::string make_args_expression(std::vector<std::string> args) {
188 // std::stringstream ss;
189 // for(Index i=0; i<args.size(); ++i) {
190 // if(i==0) { ss << "(";}
191 // ss << args[i];
192 // if(i+1==args.size()) { ss << ")";}
193 // else {ss << ", ";}
194 // }
195 // return ss.str();
196 // }
197 //
198 // /// Make index expression of form "(i)"
199 // std::string make_index_expression(Index i) {
200 // return std::string {"("} + std::to_string(i) + ")";
201 // }
202 //
203 // /// Make value_names (copy exactly)
204 // std::function<std::vector<std::string> (ValuesType const &)>
205 // make_value_names(std::vector<std::string> value_names) {
206 // return [=](ValuesType const &values) {return value_names;};
207 // }
208 //
209 // /// Make scalar value_names (name -> {name})
210 // std::function<std::vector<std::string> (ValuesType const &)>
211 // make_scalar_value_names(std::string name) {
212 // return [=](ValuesType const &values) {return std::vector<std::string>(1,
213 // name);};
214 // }
215 //
216 // /// Make vector value_names (name -> {name(0), name(1), ...,
217 // name(values.size()-1)}) std::function<std::vector<std::string> (ValuesType
218 // const &)> make_vector_value_names(std::string name) {
219 // return [=](ValuesType const &values) {
220 // std::vector<std::string> value_names;
221 // for(Index i=0; i<values.size(); ++i) {
222 // std::stringstream ss;
223 // ss << name << make_index_expression(i);
224 // value_names.push_back(ss.str());
225 // }
226 // return value_names;
227 // };
228 // }
229 //
230 // /// Make value_names by combining name and each element of args:
231 // ///
232 // /// Ex: "name" + {"Au", "Ag", ...} -> {"name(Au)", "name(Ag)", ...}
233 // std::function<std::vector<std::string> (ValuesType const &)>
234 // make_arg_value_names(
235 // std::string name,
236 // std::vector<std::string> const &args) {
237 // std::vector<std::string> value_names;
238 // for(auto const &arg : args) {
239 // value_names.push_back(name + "(" + arg + ")");
240 // }
241 // return make_value_names(value_names);
242 // }
243 //
244 //
245 // /// Collect information during `enumerate_configurations` function for
246 // optional output struct ConfigQueryData {
247 //
248 // ConfigQueryData(PrimClex const &_primclex,
249 // Configuration const &_configuration):
250 // primclex(_primclex),
251 // configuration(_configuration) {}
252 //
253 // PrimClex const &primclex;
254 // Configuration const &configuration;
255 // };
256 //
257 // /// Pass data and query expression for construction of DatumEvaluator from
258 // DatumEvaluatorDictionary
259 // ///
260 // /// For input `name(args[0], args[1], ...)(index_expression)`
261 // /// - args (comma delimited, excluding leading and trailing whitespace)
262 // /// - acceptable index expressions (begin with 0):
263 // /// - single integer
264 // /// - ranges (Python slice style):
265 // /// - "3:5", position 3 (included) to position 5 (excluded)
266 // /// - ":5", beginning to position 5 (excluded)
267 // /// - "4:", position 4 (inclued) to end
268 // /// - "-2:", second-last position (included) to end
269 // /// - comma-separated integers or ranges (excluding leading and trailing
270 // whitespace):
271 // /// - "1, 3:5, 8:", position 1, 3, 4, 5, and 8 to the end
272 // ///
273 // struct ConfigQueryInputData {
274 //
275 // PrimClex const &primclex;
276 //
277 // std::string expression; // entire query expression
278 // `name(args)(index_expression)` std::string name; // name
279 // parsed from expression std::vector<std::string> args; // args (comma
280 // delimited, excluding leading and trailing whitespace) std::set<Index>
281 // indices; // indices parsed from index_expression
282 // };
283 //
284 // std::set<Index> molecule_name_to_indices(std::string name,
285 // std::vector<std::string> const &molecule_names) {
286 // auto it = std::find(molecule_names.begin(), molecule_names.end(),
287 // input.args[0]); if(it == molecule_names.end()) {
288 // std::stringstream msg;
289 // msg << "Error parsing '" << input.expression << "': Invalid molecule
290 // name. "
291 // << "Expected one of '" << molecule_names << "'." << std::endl;
292 // throw std::runtime_error(msg.str());
293 // }
294 // std::set<Index> indices;
295 // indices.push_back(std::distance(molecule_names.begin(), it));
296 // return indices;
297 // }
298 //
299 // comp_n_name()
300 //
301 // comp_n_description()
302 //
303 // std::unique_ptr<DatumEvaluator<Configuration, Eigen::VectorXd>>
304 // make_comp_n_evaluator(
305 // ConfigQueryInputType const &input) {
306 //
307 // auto molecule_names =
308 // xtal::struc_molecule_name(input.primclex.prim().structure());
309 // if(input.args.size() == 0) {
310 // return notstd::make_unique<DatumEvaluator<Configuration,
311 // Eigen::VectorXd>>(
312 // make_arg_vector_names("comp_n", molecule_names),
313 // comp_n);
314 // }
315 // else if(input.args.size() == 1) {
316 // return notstd::make_unique<DatumEvaluator<Configuration,
317 // Eigen::VectorXd>>(
318 // make_arg_vector_names("comp_n", molecule_names),
319 // comp_n,
320 // molecule_name_to_indices(input.args[0], molecule_names));
321 // }
322 // else {
323 // std::stringstream msg;
324 // msg << "Error parsing '" << input.expression << "': Expected args.size()
325 // <= 1"; throw std::runtime_error(msg.str());
326 // }
327 // }
328 //
329 // notstd::make_unique<DatumEvaluator<Configuration, Eigen::VectorXd>>(
330 // comp_n
331 //
332 //
333 
361 template <typename ObjectType>
363  public:
365 
366  virtual ~DataFormatter() {}
367 
370  virtual std::string formatter_type() const = 0;
371 
372  // --- Setup DataFormatter by inserting DatumEvaluators &
373  // DatumFormatterOptions ---
374 
375  // /// Push back BaseDatumEvaluator<DataObject>
376  // /// - Will be evaluated sequentially by `operator()`.
377  // /// - Will be given default formatter options
378  // void push_back(BaseDatumEvaluatorPtr evaluator_ptr);
379  //
380  // /// Push back BaseDatumEvaluator<DataObject>
381  // /// - Will be evaluated sequentially by `operator()`.
382  // /// - Will be given default formatter options
383  // void push_back(std::pair<BaseDatumEvaluatorPtr, DatumFormatterOptions>
384  // evstd::unique_ptr<BaseDatumEvaluator<ObjectType>> evaluator_ptr);
385  //
386  // /// Push back BaseDatumEvaluator<DataObject>. Will be evaluated
387  // sequentially by `operator()`. template<typename ...Args> void
388  // push_back(std::unique_ptr<BaseDatumEvaluator<ObjectType>> evaluator_ptr,
389  // Args &&... args);
390 
394  virtual void init() = 0;
395 
396  // --- Specialize these to control how a formatter formats data ---
397 
398  virtual void format(std::string const &value_name, bool const &value) = 0;
399  virtual void format(std::string const &value_name, long const &value) = 0;
400  virtual void format(std::string const &value_name, double const &value) = 0;
401  virtual void format(std::string const &value_name,
402  std::string const &value) = 0;
403  virtual void format(std::string const &value_name,
404  Eigen::MatrixXl const &value) = 0;
405  virtual void format(std::string const &value_name,
406  Eigen::MatrixXd const &value) = 0;
407  virtual void format(std::string const &value_name,
408  jsonParser const &value) = 0;
409 
411  virtual void operator()(ObjectType const &object) = 0;
412 
413  // --- Error handling ---
414 
416  std::vector<std::string> const &errors() const;
417 
420  int insert_error(std::string what);
421 
422  private:
423  std::vector<std::unique_ptr<BaseDatumEvaluator<ObjectType>>> m_evaluators;
424  std::vector<std::string> m_errors;
425 };
426 
428 template <typename ObjectType, typename ValueType>
430  ValueF _value_f)
431  : m_name(_name), m_value_f(_value_f) {}
432 
434 template <typename ObjectType, typename ValueType>
436  return m_name;
437 }
438 
440 template <typename ObjectType, typename ValueType>
442  ObjectType const &object) const {
443  return m_value_f(object);
444 }
445 
447 template <typename ObjectType, typename ValueType>
449  DataFormatter<ObjectType> &formatter, ObjectType const &object) const {
450  formatter.format(this->name(), this->value(object));
451 }
452 
454 template <typename ObjectType, typename VectorizedValueType>
457  DynamicVectorizedValueF _dynamic_vectorized_value_f)
458  : m_dynamic_vectorized_value_f(_dynamic_vectorized_value_f),
459  m_is_fixed_size(false) {}
460 
462 template <typename ObjectType, typename VectorizedValueType>
464  VectorizedDatumEvaluator(std::vector<std::string> _component_names,
465  VectorizedValueF _fixed_vectorized_value_f)
466  : m_fixed_vectorized_value_f(_fixed_vectorized_value_f),
467  m_is_fixed_size(true),
468  m_component_names(_component_names) {}
469 
471 template <typename ObjectType, typename ValueType, typename VectorizedValueType>
472 VectorizedValueType VectorizedDatumEvaluator<
473  ObjectType, ValueType,
474  VectorizedValueType>::vectorized_value(ObjectType const &object) const {
475  if (this->is_fixed_size()) {
476  return m_fixed_vectorized_value_f(object);
477  } else {
478  return m_vectorized_value_f(object, m_component_names);
479  }
480 }
481 
484 template <typename ObjectType, typename ValueType, typename VectorizedValueType>
487  ObjectType const &object) const {
488  // these could throw:
489  // (reminder: if dynamic, also sets m_component_names)
490  auto _vectorized_value = this->vectorized_value(object);
491 
492  if (_vectorized_value.size() != m_component_names.size()) {
493  std::stringstream msg;
494  msg << "Error in DatumEvaluator: component_names.size() != "
495  "vectorized_value.size() ";
496  msg << m_component_names.size() << " != " << _vectorized_value.size();
497  throw std::runtime_error(msg.str());
498  }
499 
500  // this should not throw:
501  auto it = std::begin(_vectorized_value);
502  auto end = std::end(_vectorized_value);
503  auto name_it = m_component_names().begin();
504  for (; it != end; ++it, ++name_it) {
505  formatter.format(*name_it, *it);
506  }
507 }
508 
511 template <typename ObjectType>
513  std::unique_ptr<BaseDatumEvaluator<ObjectType>> evaluator_ptr) {
514  m_evaluators.push_back(std::move(evaluator_ptr));
515 }
516 
519 template <typename ObjectType>
520 template <typename... Args>
522  std::unique_ptr<BaseDatumEvaluator<ObjectType>> evaluator_ptr,
523  Args &&...args) {
524  push_back(std::move(evaluator_ptr));
525  push_back(std::forward<Args>(args)...);
526 }
527 
529 std::vector<std::string> const &errors() const { return m_errors; }
530 
531 // template<typename ObjectType>
532 // void DataFormatter<ObjectType>::operator()(ObjectType const &object) {
533 // for(auto const &evaluator_ptr : m_evaluators) {
534 // try {
535 // evaluator_ptr->format_value(*this, object);
536 // }
537 // catch (std::exception &e) {
538 //
539 // int error_index = this->insert_error(e.what());
540 // std::string error_key = "error_" + std::to_string(error_index);
541 // this->format(_name, error_key);
542 //
543 // auto value_names = evaluator_ptr->value_names();
544 // for(auto const &_value_name : value_names) {
545 // this->format(_value_name, error_key);
546 // }
547 // }
548 // }
549 // }
550 
551 // template<typename ObjectType>
552 // void DataFormatter<ObjectType>::operator()(ObjectType const &object) {
553 // for(auto const &evaluator_ptr : m_evaluators) {
554 // try {
555 // evaluator_ptr->format_vectorized_value(*this, object);
556 // }
557 // catch (std::exception &e) {
558 //
559 // int error_index = this->insert_error(e.what());
560 // std::string error_key = "error_" + std::to_string(error_index);
561 //
562 // auto _component_names = evaluator_ptr->component_names();
563 // for(auto const &_component_name : _component_names) {
564 // this->format(_component_name, error_key);
565 // }
566 // }
567 // }
568 // }
569 
572 int error_index insert_error(std::string what) {
573  // handle errors by:
574  // - catching exception
575  // - insert error message into this->errors() (no duplicates)
576  // - format a vector of string {"error_$i", "error_$i", ...}, where $i
577  // indicates the
578  // position of the error message in this->errors() so error messages can be
579  // printed
580 
581  auto it = std::find(m_errors.begin(), m_errors.end(), what);
582  int error_index{0};
583  if (it == m_errors.end()) {
584  error_index = m_errors.size();
585  m_errors.push_back(what);
586  } else {
587  error_index = std::distance(m_errors.begin(), it);
588  }
589  return error_index;
590 }
591 
592 } // namespace simpleformatter
593 } // namespace CASM
void push_back(const BaseDatumFormatter< DataObject > &new_formatter, const std::string &args)
virtual void format_mapped_value(DataFormatter< ObjectType > &formatter, ObjectType const &object) const =0
Format each value generated by this evaluator for the object
virtual void format_vectorized_value(DataFormatter< ObjectType > &formatter, ObjectType const &object) const =0
Format each value generated by this evaluator for the object
virtual bool is_vector() const =0
Return true if value may be vectorized.
virtual bool is_map() const =0
Return true if value may be mapped.
virtual std::vector< std::string > const & component_names() const =0
virtual void format_value(DataFormatter< ObjectType > &formatter, ObjectType const &object) const =0
Format each value generated by this evaluator for the object
virtual std::string const & name() const =0
Name of the evaluated value.
virtual void format(std::string const &value_name, bool const &value)=0
virtual void format(std::string const &value_name, double const &value)=0
virtual void format(std::string const &value_name, Eigen::MatrixXl const &value)=0
int insert_error(std::string what)
std::vector< std::string > const & errors() const
Access error messages from caught exceptions that occur during evaluation.
virtual void operator()(ObjectType const &object)=0
Evaluate all DatumEvaluators and format results.
virtual void format(std::string const &value_name, jsonParser const &value)=0
std::vector< std::string > m_errors
virtual void format(std::string const &value_name, long const &value)=0
virtual void format(std::string const &value_name, Eigen::MatrixXd const &value)=0
std::vector< std::unique_ptr< BaseDatumEvaluator< ObjectType > > > m_evaluators
virtual std::string formatter_type() const =0
virtual void format(std::string const &value_name, std::string const &value)=0
void format_vectorized_value(DataFormatter< ObjectType > &formatter, ObjectType const &object) const override
void format_value(DataFormatter< ObjectType > &formatter, ObjectType const &object) const override
Format each value generated by this evaluator for the object
DatumEvaluator(std::string _name, ValueF _value_f)
Construct a non-vectorizable DatumEvaluator.
bool may_be_vectorized() const override
Return true if value may be vectorized. This always returns false.
std::string const & name() const override
Name of the evaluated value.
ValueType value(ObjectType const &object) const
Value.
std::function< ValueType(ObjectType const &object)> ValueF
Function that evaluates the value.
std::vector< std::string > const & component_names() const override
void format_vectorized_value(DataFormatter< ObjectType > &formatter, ObjectType const &object) const override
std::function< VectorizedValueType(ObjectType const &, std::vector< std::string > &)> DynamicVectorizedValueF
Function that evaluates the vectorized value and sets component names.
std::vector< std::string > const & component_names() const override
bool may_be_vectorized() const override
Return true if value may be vectorized. This always returns true.
VectorizedDatumEvaluator(DynamicVectorizedValueF _dynamic_vectorized_value_f)
Construct a vectorizable, variable size, DatumEvaluator.
VectorizedValueType vectorized_value(ObjectType const &object) const
Vectorized value.
std::function< VectorizedValueType(ObjectType const &)> FixedVectorizedValueF
Function that evaluates the vectorized value and sets component names.
VectorizedDatumEvaluator(std::vector< std::string > _component_names, FixedVectorizedValueF _vectorized_value_f)
#define CLONEABLE(T)
int error_index insert_error(std::string what)
std::vector< std::string > const & errors() const
Access error messages from caught exceptions that occur during evaluation.
Main CASM namespace.
Definition: APICommand.hh:8
Eigen::MatrixXd MatrixXd
GenericDatumFormatter< std::string, DataObject > name()
Iterator find(Iterator begin, Iterator end, const T &value, BinaryCompare q)
Equivalent to std::find(begin, end, value), but with custom comparison.
Definition: algorithm.hh:16
Matrix< long int, Dynamic, Dynamic > MatrixXl
Definition: eigen.hh:14