File indexing completed on 2025-07-15 09:14:06
0001
0002
0003
0004
0005
0006 #ifndef YODA_AnalysisObject_h
0007 #define YODA_AnalysisObject_h
0008
0009 #include "YODA/Exceptions.h"
0010 #include "YODA/Utils/StringUtils.h"
0011 #include "YODA/Config/BuildConfig.h"
0012
0013 #ifdef HAVE_HDF5
0014 #include "YODA/Utils/H5Utils.h"
0015 #endif
0016
0017 #include <iomanip>
0018 #include <string>
0019 #include <limits>
0020 #include <map>
0021
0022 namespace YODA {
0023
0024
0025
0026 class AnalysisObject {
0027
0028 public:
0029
0030
0031 typedef std::map<std::string, std::string> Annotations;
0032
0033
0034
0035
0036
0037
0038 AnalysisObject() { }
0039
0040
0041 AnalysisObject(const std::string& type, const std::string& path, const std::string& title="") {
0042 setAnnotation("Type", type);
0043 setPath(path);
0044 setTitle(title);
0045 }
0046
0047
0048 AnalysisObject(const std::string& type, const std::string& path,
0049 const AnalysisObject& ao, const std::string& title="") {
0050 AnalysisObject::operator = (ao);
0051 setAnnotation("Type", type);
0052 setPath(path);
0053 setTitle(title);
0054 }
0055
0056
0057
0058
0059
0060
0061
0062
0063 virtual ~AnalysisObject() { }
0064
0065
0066 virtual AnalysisObject& operator = (const AnalysisObject& ao) noexcept {
0067 for (const std::string& a : ao.annotations()) {
0068 if (a == "Type") continue;
0069 if (a == "Path" && !ao.path().length()) continue;
0070 if (a == "Title" && !ao.title().length()) continue;
0071 setAnnotation(a, ao.annotation(a));
0072 }
0073 return *this;
0074 }
0075
0076
0077 virtual AnalysisObject* newclone() const = 0;
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087 virtual void reset() = 0;
0088
0089
0090
0091
0092
0093
0094
0095 virtual void _renderYODA(std::ostream& os, const int width = 13) const noexcept = 0;
0096
0097
0098 virtual void _renderFLAT(std::ostream& os, const int width = 13) const noexcept = 0;
0099
0100 #ifdef HAVE_HDF5
0101
0102
0103 virtual void _extractLabels(std::vector<std::string>&, std::vector<size_t>&) const noexcept { };
0104
0105
0106 virtual void _extractEdges(std::map<std::string, EdgeHandlerBasePtr>&,
0107 const std::vector<std::string>&) const noexcept { };
0108
0109 #endif
0110
0111
0112 virtual std::string _config() const noexcept { return ""; }
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123 std::vector<std::string> annotations() const {
0124 std::vector<std::string> rtn;
0125 rtn.reserve(_annotations.size());
0126 for (const Annotations::value_type& kv : _annotations) rtn.push_back(kv.first);
0127 return rtn;
0128 }
0129
0130
0131
0132 bool hasAnnotation(const std::string& name) const {
0133 return _annotations.find(name) != _annotations.end();
0134 }
0135
0136
0137
0138 const std::string& annotation(const std::string& name) const {
0139 Annotations::const_iterator v = _annotations.find(name);
0140
0141 if (v == _annotations.end()) {
0142 std::string missing = "YODA::AnalysisObject: No annotation named " + name;
0143 throw AnnotationError(missing);
0144 }
0145 return v->second;
0146 }
0147
0148
0149
0150 const std::string& annotation(const std::string& name, const std::string& defaultreturn) const {
0151 Annotations::const_iterator v = _annotations.find(name);
0152 if (v != _annotations.end()) return v->second;
0153 return defaultreturn;
0154 }
0155
0156
0157
0158
0159
0160 template <typename T>
0161 const T annotation(const std::string& name) const {
0162 std::string s = annotation(name);
0163 return Utils::lexical_cast<T>(s);
0164 }
0165
0166
0167
0168
0169
0170 template <typename T>
0171 const T annotation(const std::string& name, const T& defaultreturn) const {
0172 Annotations::const_iterator v = _annotations.find(name);
0173 if (v != _annotations.end()) return Utils::lexical_cast<T>(v->second);
0174 return defaultreturn;
0175 }
0176
0177
0178
0179
0180
0181 template <typename T>
0182 void setAnnotation(const std::string& name, const T& value) {
0183 if constexpr( std::is_floating_point<T>::value ) {
0184
0185 std::stringstream ss;
0186 ss << std::setprecision(std::numeric_limits<double>::max_digits10) << std::scientific << value;
0187 setAnnotation(name, ss.str());
0188 }
0189 else if constexpr( std::is_same<T, std::string>::value ) {
0190 _annotations[name] = value;
0191 }
0192 else {
0193 _annotations[name] = Utils::lexical_cast<std::string>(value);
0194 }
0195 }
0196
0197
0198
0199 void setAnnotations(const Annotations& anns) {
0200 _annotations = anns;
0201 }
0202
0203
0204
0205
0206
0207 template <typename T>
0208 void addAnnotation(const std::string& name, const T& value) {
0209 setAnnotation(name, value);
0210 }
0211
0212
0213
0214 void rmAnnotation(const std::string& name) {
0215 _annotations.erase(name);
0216 }
0217
0218
0219
0220 void clearAnnotations() {
0221 _annotations.clear();
0222 }
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233 const std::string title() const {
0234 return annotation("Title", "");
0235 }
0236
0237
0238 void setTitle(const std::string& title) {
0239 setAnnotation("Title", title);
0240 }
0241
0242
0243
0244
0245
0246 const std::string path() const {
0247 const std::string p = annotation("Path", "");
0248
0249 if (p.empty()) return p;
0250
0251 return p.find("/") == 0 ? p : ("/"+p);
0252 }
0253
0254
0255
0256
0257 void setPath(const std::string& path) {
0258 const std::string p = (path.find("/") == 0) ? path : "/"+path;
0259
0260
0261
0262 setAnnotation("Path", p);
0263 }
0264
0265
0266
0267
0268 const std::string name() const {
0269 const std::string p = path();
0270 const size_t lastslash = p.rfind("/");
0271 if (lastslash == std::string::npos) return p;
0272 return p.substr(lastslash+1);
0273 }
0274
0275
0276
0277
0278 public:
0279
0280
0281
0282
0283
0284 virtual std::string type() const {
0285 return annotation("Type");
0286 }
0287
0288
0289
0290
0291
0292 virtual size_t dim() const noexcept = 0;
0293
0294
0295 virtual AnalysisObject* mkInert(const std::string& path = "",
0296 const std::string& source = "") const noexcept {
0297 (void)source;
0298 AnalysisObject* rtn = this->newclone();
0299 rtn->setPath(path);
0300 return rtn;
0301 }
0302
0303
0304
0305
0306
0307
0308
0309 virtual size_t lengthContent(bool fixed_length = false) const noexcept = 0;
0310
0311
0312 virtual std::vector<double> serializeContent(bool fixed_length = false) const noexcept = 0;
0313
0314
0315 virtual void deserializeContent(const std::vector<double>& data) = 0;
0316
0317
0318 size_t lengthMeta(const bool skipPath = true,
0319 const bool skipTitle = true) const noexcept {
0320 return 2*(_annotations.size() - skipPath - skipTitle);
0321 }
0322
0323
0324 std::vector<std::string> serializeMeta(const bool skipPath = true,
0325 const bool skipTitle = true) const noexcept {
0326
0327
0328 std::vector<std::string> rtn;
0329 rtn.reserve(2*(_annotations.size() - skipPath - skipTitle));
0330 for (const auto& item : _annotations) {
0331 if (item.first == "Type") continue;
0332 if (skipPath && item.first == "Path") continue;
0333 if (skipTitle && item.first == "Title") continue;
0334 rtn.push_back(item.first);
0335 rtn.push_back(item.second);
0336 }
0337 return rtn;
0338 }
0339
0340
0341 virtual void deserializeMeta(const std::vector<std::string>& data,
0342 const bool resetPath = false, const bool resetTitle = false) {
0343
0344 if (data.empty()) return;
0345 if (data.size() % 2)
0346 throw UserError("Expected even number of annotation elements (key-value pairs)!");
0347
0348 const std::string path = annotation("Path");
0349 const std::string type = annotation("Type");
0350 const std::string title = annotation("Title");
0351 _annotations.clear();
0352 _annotations["Type"] = type;
0353 if (!resetPath) _annotations["Path"] = path;
0354 if (!resetTitle) _annotations["Title"] = title;
0355
0356 auto itr = data.cbegin();
0357 const auto itrEnd = data.cend();
0358 while (itr != itrEnd) {
0359 const std::string key = *itr; ++itr;
0360 const std::string val = *itr; ++itr;
0361 _annotations[key] = val;
0362 }
0363 }
0364
0365
0366
0367 private:
0368
0369
0370 std::map<std::string,std::string> _annotations;
0371
0372 };
0373
0374
0375
0376 using AO = AnalysisObject;
0377
0378
0379 }
0380
0381 #endif