Tomographer  v3.0
Tomographer C++ Framework Documentation
ezmatio.h
Go to the documentation of this file.
1 /* This file is part of the Tomographer project, which is distributed under the
2  * terms of the MIT license.
3  *
4  * The MIT License (MIT)
5  *
6  * Copyright (c) 2016 ETH Zurich, Institute for Theoretical Physics, Philippe Faist
7  * Copyright (c) 2017 Caltech, Institute for Quantum Information and Matter, Philippe Faist
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining a copy
10  * of this software and associated documentation files (the "Software"), to deal
11  * in the Software without restriction, including without limitation the rights
12  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13  * copies of the Software, and to permit persons to whom the Software is
14  * furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be included in
17  * all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25  * SOFTWARE.
26  */
27 
28 #ifndef _TOMOGRAPHER_TOOLS_EZMATIO_H
29 #define _TOMOGRAPHER_TOOLS_EZMATIO_H
30 
31 #include <cstdint>
32 #include <cerrno>
33 
34 #include <complex>
35 #include <string>
36 #include <vector>
37 #include <algorithm>
38 #include <iostream>
39 #include <stdexcept>
40 #include <sstream>
41 #include <initializer_list>
42 #include <utility>
43 
44 extern "C" {
45 # include <matio.h>
46 }
47 
48 #include <Eigen/Core>
49 
52 #include <tomographer/tools/fmt.h>
54 
55 
63 namespace Tomographer {
64 // namespace doc in doc/doxdocs/namespaces.cxx
65 namespace MAT {
66 
67 
70 class Exception : public std::exception
71 {
72  std::string p_heading;
73  std::string p_message;
74  std::string p_final;
75 public:
76  Exception(std::string msg) : p_message(msg) { update_final(); }
77  Exception(std::string heading, std::string msg) : p_heading(heading), p_message(msg) { update_final(); }
78  virtual ~Exception() noexcept { }
79 
80  virtual const char * what() const noexcept { return p_final.c_str(); }
81 
82 protected:
83  inline void setHeading(const std::string heading) {
84  p_heading = heading;
85  update_final();
86  }
87  inline void setMessage(const std::string message) {
88  p_message = message;
89  update_final();
90  }
91 private:
92  inline void update_final() {
93  p_final = p_heading + p_message;
94  }
95 };
96 
99 class VarError : public Exception
100 {
101 public:
102  VarError(std::string msg) : Exception("", msg) { }
103  VarError(std::string varname, std::string msg) : Exception(heading(varname), msg) { }
104  virtual ~VarError() noexcept { }
105 
106  void setVarName(std::string varname) { setHeading(heading(varname)); }
107 
108 private:
109  static std::string heading(std::string varname) { return "Variable " + varname + ": "; }
110 };
111 
113 class VarReadError : public VarError
114 {
115 public:
116  VarReadError(const std::string varname)
117  : VarError(varname, "Can't read variable")
118  {
119  }
120  virtual ~VarReadError() noexcept { }
121 };
122 
124 class VarTypeError : public VarError
125 {
126 public:
127  VarTypeError(const std::string varname, const std::string msg)
128  : VarError(varname, msg)
129  {
130  }
131  virtual ~VarTypeError() noexcept { }
132 };
133 
135 class VarMatTypeError : public VarError {
136 public:
137  VarMatTypeError(const std::string msg)
138  : VarError(msg)
139  {
140  }
141  VarMatTypeError(const std::string varname, const std::string msg)
142  : VarError(varname, msg)
143  {
144  }
145  virtual ~VarMatTypeError() noexcept { }
146 };
147 
149 class FileOpenError : public Exception
150 {
151 public:
152  FileOpenError(const std::string fname, const std::string errmsg = std::string())
153  : Exception(heading(fname), "Error opening file" + (errmsg.size() ? ": "+errmsg : ""))
154  {
155  }
156  virtual ~FileOpenError() noexcept { }
157 
158  void setFileName(const std::string fname) {
159  setHeading(heading(fname));
160  }
161 
162 private:
163  static std::string heading(std::string fname) { return "File `"+fname+"`: "; }
164 };
165 
166 
168 class InvalidIndexError : public Exception {
169 public:
170  InvalidIndexError(const std::string msg) : Exception("Invalid index: ", msg) { }
171  virtual ~InvalidIndexError() noexcept { }
172 };
173 
174 
175 
176 
177 
178 class Var;
179 
180 
192 class File
193 {
194 public:
200  File(const std::string fname)
201  {
202  errno = 0;
203  p_matfp = Mat_Open(fname.c_str(), MAT_ACC_RDONLY);
204  if ( p_matfp == NULL ) {
205  throw FileOpenError(fname, strerror(errno));
206  }
207  }
208  File(const File& other) = delete;
209 
215  File(File&& other)
216  {
217  // move constructor. Steal the other object's MAT file handle
218  p_matfp = other.p_matfp;
219  other.p_matfp = NULL;
220  }
221 
222  ~File()
223  {
224  if ( p_matfp != NULL ) {
225  Mat_Close(p_matfp);
226  }
227  }
228 
238  inline Var var(const std::string varname, bool load_data = true);
239 
240 
246  inline std::vector<Var> getVarInfoList();
247 
253  mat_t * getMatPtr()
254  {
255  return p_matfp;
256  }
257 
263  File& operator=(File&& other)
264  {
265  // move assignment operator. Steal the other object's MAT file handle
266  p_matfp = other.p_matfp;
267  other.p_matfp = NULL;
268  return *this;
269  }
270  File& operator=(const File& other) = delete;
271 
272 private:
273  mat_t *p_matfp;
274 };
275 
276 
282 template<typename It, typename ValueType = typename std::iterator_traits<It>::value_type>
283 ValueType getNumEl(It begin, It end)
284 {
285  ValueType n = 1;
286  for (It it = begin; it != end; ++it) {
287  n *= (*it);
288  }
289  return n;
290 }
291 
292 
306 class DimList : public std::vector<int>
307 {
308 public:
310  DimList() : std::vector<int>() { }
311 
317  template<typename VectorType>
318  DimList(VectorType&& dims)
319  : std::vector<int>(std::forward<VectorType>(dims))
320  {
321  }
335  : std::vector<int>(init)
336  {
337  }
343  template<class It>
344  DimList(It b, It e) : std::vector<int>(b, e)
345  {
346  }
347 
352  inline int numel() const { return getNumEl(begin(), end()); }
353 
359  inline int ndims() const { return (int)size(); }
360 
364  inline bool matchesWanted(const DimList& wanted) const
365  {
366  if (size() != wanted.size()) {
367  return false;
368  }
369  for (std::size_t k = 0; k < size(); ++k) {
370  if (wanted[k] >= 0 && this->operator[](k) != wanted[k]) {
371  return false;
372  }
373  }
374  return true;
375  }
376 
382  DimList& operator<<(int dim) {
383  push_back(dim);
384  return *this;
385  }
391  DimList& operator<<(const std::vector<int>& moredims) {
392  insert(end(), moredims.begin(), moredims.end());
393  return *this;
394  }
395 };
396 
398 inline std::ostream& operator<<(std::ostream& out, const DimList& dlist)
399 {
400  out << "[";
401  for (DimList::const_iterator it = dlist.begin(); it != dlist.end(); ++it) {
402  if (it != dlist.begin()) {
403  out << " ";
404  }
405  if (*it == -1) {
406  // usually meant for arbitrary size requirement. In any case, it is not a physical
407  // array size.
408  out << '*';
409  } else {
410  out << *it;
411  }
412  }
413  out << "]";
414  return out;
415 }
416 
439 template<bool IsRowMajor_ = false>
440 class IndexList : public std::vector<int>
441 {
442 public:
444  static constexpr bool IsRowMajor = IsRowMajor_;
447 
453  IndexList(const std::vector<int>& dims = std::vector<int>(), int linearindex = -1)
454  : std::vector<int>(dims.size()), p_dims(dims)
455  {
456  if (getNumEl(dims.begin(), dims.end()) <= 0) {
457  throw InvalidIndexError("zero-sized array given by dimension list");
458  }
459  if (linearindex >= 0) {
460  setLinearIndex(linearindex);
461  }
462  }
469  // the reason we dont have template<typename... VectorArgs> for std::vector<>
470  // constructor is that g++ 4.6 if I remember correctly can't unpack arguments into a
471  // fixed number of arguments (TODO: CHECK THIS!)
472  template<typename VectorIntInitializer>
473  IndexList(const std::vector<int>& dims, VectorIntInitializer&& index)
474  : std::vector<int>(std::forward<VectorIntInitializer>(index)), p_dims(dims)
475  {
476  if (getNumEl(dims.begin(), dims.end()) <= 0) {
477  throw InvalidIndexError("zero-sized array given by dimension list");
478  }
479  }
480 
488  TOMOGRAPHER_ENABLED_IF(IsRowMajor)
489  void setLinearIndex(int linearindex)
490  {
491  const int ndims = (int)p_dims.size();
492  for (int k = ndims-1; k >= 0; --k) {
493  this->at(k) = linearindex % p_dims[k];
494  linearindex /= p_dims[k]; // integer division
495  }
496  }
504  TOMOGRAPHER_ENABLED_IF(!IsRowMajor)
505  void setLinearIndex(int linearindex)
506  {
507  const int ndims = (int)p_dims.size();
508  for (int k = 0; k < ndims; ++k) {
509  this->at(k) = linearindex % p_dims[k];
510  linearindex /= p_dims[k]; // integer division
511  // std::cout << "k = " << k << "; p_dims = " << p_dims << "; at(k) = " << this->at(k)
512  // << "; linearindex=" << linearindex << "\n";
513  }
514  }
515 
520  TOMOGRAPHER_ENABLED_IF(IsRowMajor)
521  int linearIndex() const
522  {
523  int linindex = 0;
524  for (int k = 0; k < (int)p_dims.size(); ++k) {
525  linindex *= p_dims[k];
526  linindex += this->at(k);
527  }
528  return linindex;
529  }
534  TOMOGRAPHER_ENABLED_IF(!IsRowMajor)
535  int linearIndex() const
536  {
537  int linindex = 0;
538  for (int k = (int)p_dims.size()-1; k >= 0; --k) {
539  linindex *= p_dims[k];
540  linindex += this->at(k);
541  }
542  return linindex;
543  }
544 
547  inline const std::vector<int> & index() const
548  {
549  return *this;
550  }
551 
556  inline const std::vector<int> & dims() const
557  {
558  return p_dims;
559  }
560 
568  IndexList& operator<<(int ind) {
569  push_back(ind);
570  return *this;
571  }
572 
581  IndexList& operator<<(const std::vector<int>& moredims) {
582  insert(end(), moredims.begin(), moredims.end());
583  return *this;
584  }
585 
586 
587 
588  // for internal use:
589 
590  template<bool IsRowMajor2 = false>
591  static const std::vector<int> & forward_index(const IndexList<IsRowMajor2> & index)
592  {
593  return index;
594  }
595  template<bool IsRowMajor2 = false>
596  static std::vector<int> && forward_index(IndexList<IsRowMajor2> && index)
597  {
598  return std::move(index);
599  }
600 
601 private:
602  const std::vector<int> p_dims;
603 };
604 
605 
607 template<bool IsRowMajor>
608 inline std::ostream& operator<<(std::ostream& str, const IndexList<IsRowMajor> & indexlist)
609 {
610  str << "[";
611  for (std::size_t j = 0; j < indexlist.size(); ++j) {
612  str << indexlist[j];
613  if (j < indexlist.size()) {
614  str << ", ";
615  } else {
616  str << ";";
617  }
618  }
619  return str << "==" << indexlist.linearIndex() << "]";
620 }
621 
622 
626 template<bool IsRowMajor_ = false, typename IntType_ = int>
628 {
629 public:
630  static constexpr bool IsRowMajor = IsRowMajor_;
631  typedef IntType_ IntType;
633 
634 private:
635  const std::vector<IntType> p_dims;
636  const IntType p_numel;
637 
638  std::vector<IntType> p_index;
639  IntType p_linearIndex;
640 
641 public:
643  : p_dims(dims),
644  p_numel(getNumEl(dims.begin(), dims.end())),
645  p_index(dims.size(), 0),
646  p_linearIndex(0)
647  {
648  if (p_numel <= 0) {
650  ss << "Invalid dimensions: " << p_dims;
651  throw InvalidIndexError(ss.str());
652  }
653  }
654 
655  inline const std::vector<IntType>& index() const
656  {
657  return p_index;
658  }
659 
660  inline IntType linearIndex() const
661  {
662  return p_linearIndex;
663  }
664 
665  inline IntType numel() const
666  {
667  return p_numel;
668  }
669 
670 
671  TOMOGRAPHER_ENABLED_IF(IsRowMajor)
672  IntType increment()
673  {
674  for (int k = p_dims.size() - 1; k >= 0; --k) {
675  p_index[k]++;
676  if (p_index[k] < p_dims[k]) {
677  // if this increment succeeded and stays in range, ok and stop.
678  break;
679  } else {
680  // otherwise continue the loop and increment the next value, while resetting
681  // this one to zero.
682  p_index[k] = 0;
683  }
684  }
685  return ++p_linearIndex;
686  }
687 
688  TOMOGRAPHER_ENABLED_IF(!IsRowMajor)
689  IntType increment()
690  {
691  for (int k = 0; k < (int)p_dims.size(); ++k) {
692  p_index[k]++;
693  if (p_index[k] < p_dims[k]) {
694  // if this increment succeeded and stays in range, ok and stop.
695  break;
696  } else {
697  // otherwise continue the loop and increment the next value, while resetting
698  // this one to zero.
699  p_index[k] = 0;
700  }
701  }
702  return ++p_linearIndex;
703  }
704 
705  IntType operator++() {
706  return increment();
707  }
708 
709  bool valid() const
710  {
711  return Tools::isPositive<IntType>(p_linearIndex) && p_linearIndex < p_numel;
712  }
713 
714 
715  // for internal use:
716 
717  template<bool IsRowMajor2 = false, typename IntType2 = int>
718  static const std::vector<IntType2> &
719  forward_index(const IndexListIterator<IsRowMajor2,IntType2> & index)
720  {
721  return index.p_index;
722  }
723  template<bool IsRowMajor2 = false, typename IntType2 = int>
724  static std::vector<IntType2> &&
725  forward_index(IndexListIterator<IsRowMajor2,IntType2> && index)
726  {
727  return std::move(index.p_index);
728  }
729 
730 };
731 
732 
734 template<bool IsRowMajor, typename IntType>
735 inline std::ostream& operator<<(std::ostream& str, const IndexListIterator<IsRowMajor, IntType> & indexlistit)
736 {
737  std::vector<int> indexlist{indexlistit.index()};
738 
739  str << "[";
740  for (std::size_t j = 0; j < indexlist.size(); ++j) {
741  str << indexlist[j];
742  if (j < indexlist.size()) {
743  str << ", ";
744  } else {
745  str << ";";
746  }
747  }
748  return str << "==" << indexlistit.linearIndex() << "]";
749 }
750 
751 
752 
753 
754 
801 template<typename T, typename Enabled = void>
803 {
804 public:
810  typedef T RetType;
811 
818  static inline void checkShape(const Var & var)
819  {
820  (void)var; // silence "unused parameter" warnings
821  }
822 
837  static inline RetType decodeValue(const Var & var);
838 };
839 
840 
841 namespace tomo_internal {
842 
843  template<typename T, typename Res = void>
844  struct enable_if_is_type { typedef T check_type; typedef Res type; };
845 
846  // has_params_member<T>::value is true if T has a type member named Params,
847  // i.e. typename T::Params, else it is false.
848  template<typename T, typename Enabled = void>
849  struct has_params_member {
850  enum { value = 0 };
851  };
852  // if T has no Params member, following will fail by SFINAE (the default arguemnt of
853  // parameter #2 always stays int)
854  template<typename T>
855  struct has_params_member<T, typename enable_if_is_type<typename T::Params>::type >
856  {
857  enum { value = 1 };
858  };
859 }; // namespace tomo_internal
860 
861 
862 
863 class Var;
864 
870 template<typename T>
871 inline typename VarValueDecoder<T>::RetType value(const Var& var)
872 {
875 }
876 
885 template<typename T, TOMOGRAPHER_ENABLED_IF_TMPL( tomo_internal::has_params_member<VarValueDecoder<T> >::value )>
886 inline typename VarValueDecoder<T>::RetType value(const Var& var,
887  const typename VarValueDecoder<T>::Params & params)
888 {
889  VarValueDecoder<T>::checkShape(var, params);
890  return VarValueDecoder<T>::decodeValue(var, params);
891 }
892 
893 
894 
911 class Var
912 {
913 private:
914  struct VarData {
915  VarData() : refcount(0), p_matvar(NULL) { }
916  int refcount;
917  matvar_t * p_matvar;
918  std::string p_varname;
919  };
920  VarData *p_vardata;
921 
922  Var(matvar_t * varinfo) // take over the struct ownership
923  {
924  if (varinfo == NULL) {
925  throw VarReadError("<unknown>");
926  }
927  p_vardata = new VarData;
928  p_vardata->refcount++;
929  p_vardata->p_matvar = varinfo;
930  p_vardata->p_varname = std::string(varinfo->name);
931  }
932 
933 public:
944  Var(File & matf, const std::string& varname, bool load_data = true)
945  {
946  p_vardata = new VarData;
947  p_vardata->refcount++;
948  if (load_data) {
949  p_vardata->p_matvar = Mat_VarRead(matf.getMatPtr(), varname.c_str());
950  } else {
951  p_vardata->p_matvar = Mat_VarReadInfo(matf.getMatPtr(), varname.c_str());
952  }
953  if (p_vardata->p_matvar == NULL) {
954  delete p_vardata;
955  p_vardata = NULL;
956  throw VarReadError(varname);
957  }
958  p_vardata->p_varname = varname;
959  }
960 
962  Var(const Var& copy)
963  {
964  p_vardata = copy.p_vardata;
965  p_vardata->refcount++;
966  }
967 
969  Var(Var&& other)
970  {
971  // steal the data
972  p_vardata = other.p_vardata;
973  other.p_vardata = NULL;
974  }
975 
976  ~Var() {
977  if (p_vardata != NULL) {
978  p_vardata->refcount--;
979  if (!p_vardata->refcount) {
980  Mat_VarFree(p_vardata->p_matvar);
981  delete p_vardata;
982  }
983  }
984  }
985 
992  static Var takeOver(matvar_t * varinfo)
993  {
994  return Var(varinfo);
995  }
996 
1001  inline const std::string & varName() const
1002  {
1003  tomographer_assert(p_vardata != NULL);
1004  return p_vardata->p_varname;
1005  }
1006 
1011  inline int ndims() const
1012  {
1013  tomographer_assert(p_vardata != NULL);
1014  return p_vardata->p_matvar->rank;
1015  }
1020  inline DimList dims() const
1021  {
1022  tomographer_assert(p_vardata != NULL);
1023  return DimList(&p_vardata->p_matvar->dims[0],
1024  &p_vardata->p_matvar->dims[p_vardata->p_matvar->rank]);
1025  }
1030  inline int numel() const
1031  {
1032  tomographer_assert(p_vardata != NULL);
1033  return dims().numel();
1034  }
1043  inline bool isComplex() const
1044  {
1045  tomographer_assert(p_vardata != NULL);
1046  return p_vardata->p_matvar->isComplex;
1047  }
1052  inline bool isSquareMatrix() const
1053  {
1054  tomographer_assert(p_vardata != NULL);
1055  return p_vardata->p_matvar->rank == 2 && p_vardata->p_matvar->dims[0] == p_vardata->p_matvar->dims[1];
1056  }
1057 
1063  inline bool hasData() const
1064  {
1065  tomographer_assert(p_vardata != NULL);
1066  return (p_vardata->p_matvar->data != NULL);
1067  }
1068 
1108  template<typename T>
1109  inline typename VarValueDecoder<T>::RetType value() const
1110  {
1111  return Tomographer::MAT::value<T>(*this);
1112  }
1123  template<typename T, TOMOGRAPHER_ENABLED_IF_TMPL( tomo_internal::has_params_member<VarValueDecoder<T> >::value )>
1124  inline typename VarValueDecoder<T>::RetType value(const typename VarValueDecoder<T>::Params & params)
1125  {
1126  return Tomographer::MAT::value<T>(*this, params);
1127  }
1128 
1134  const matvar_t * getMatvarPtr() const
1135  {
1136  tomographer_assert(p_vardata != NULL);
1137  return p_vardata->p_matvar;
1138  }
1139 
1143  Var& operator=(Var&& other)
1144  {
1145  // steal the data
1146  p_vardata = other.p_vardata;
1147  other.p_vardata = NULL;
1148  return *this;
1149  }
1151  Var& operator=(const Var& copy)
1152  {
1153  p_vardata = copy.p_vardata;
1154  p_vardata->refcount++;
1155  return *this;
1156  }
1157 };
1158 
1159 
1160 // ---------------
1161 
1162 
1163 inline Var File::var(const std::string varname, bool load_data)
1164 {
1165  return Var(*this, varname, load_data);
1166 }
1167 
1169 {
1170  std::vector<Var> varlist;
1171 
1172  Mat_Rewind(p_matfp);
1173  matvar_t * p = NULL;
1174  while ( (p = Mat_VarReadNextInfo(p_matfp)) != NULL ) {
1175  varlist.push_back(Var::takeOver(p));
1176  }
1177 
1178  return varlist;
1179 }
1180 
1181 
1182 template<typename T, typename Enabled>
1183 // static
1185 {
1186  throw std::runtime_error(std::string("Not Implemented: Please specialize MAT::VarValueDecoder<> for ")
1187  + typeid(T).name() + " to decode variable " + var.varName());
1188 }
1189 
1190 
1191 
1192 
1193 
1194 // =============================================================================
1195 // Some basic utilities for dealing with MATLAB variables
1196 // =============================================================================
1197 
1198 
1199 
1211 template<int MatTypeId = -1> struct MatType { };
1213 template<> struct MatType<MAT_T_DOUBLE> { typedef double Type; };
1215 template<> struct MatType<MAT_T_SINGLE> { typedef float Type; };
1217 template<> struct MatType<MAT_T_INT64> { typedef int64_t Type; };
1219 template<> struct MatType<MAT_T_INT32> { typedef int32_t Type; };
1221 template<> struct MatType<MAT_T_INT16> { typedef int16_t Type; };
1223 template<> struct MatType<MAT_T_INT8> { typedef int8_t Type; };
1225 template<> struct MatType<MAT_T_UINT64> { typedef uint64_t Type; };
1227 template<> struct MatType<MAT_T_UINT32> { typedef uint32_t Type; };
1229 template<> struct MatType<MAT_T_UINT16> { typedef uint16_t Type; };
1231 template<> struct MatType<MAT_T_UINT8> { typedef uint8_t Type; };
1232 
1233 
1240 #define MAT_SWITCH_REAL_TYPE(typ, ...) \
1241  do { switch (typ) { \
1242  case MAT_T_DOUBLE: { typedef typename MatType<MAT_T_DOUBLE>::Type Type; { __VA_ARGS__; } break; } \
1243  case MAT_T_SINGLE: { typedef typename MatType<MAT_T_SINGLE>::Type Type; { __VA_ARGS__; } break; } \
1244  case MAT_T_INT64: { typedef typename MatType<MAT_T_INT64>::Type Type; { __VA_ARGS__; } break; } \
1245  case MAT_T_INT32: { typedef typename MatType<MAT_T_INT32>::Type Type; { __VA_ARGS__; } break; } \
1246  case MAT_T_INT16: { typedef typename MatType<MAT_T_INT16>::Type Type; { __VA_ARGS__; } break; } \
1247  case MAT_T_INT8: { typedef typename MatType<MAT_T_INT8>::Type Type; { __VA_ARGS__; } break; } \
1248  case MAT_T_UINT64: { typedef typename MatType<MAT_T_UINT64>::Type Type; { __VA_ARGS__; } break; } \
1249  case MAT_T_UINT32: { typedef typename MatType<MAT_T_UINT32>::Type Type; { __VA_ARGS__; } break; } \
1250  case MAT_T_UINT16: { typedef typename MatType<MAT_T_UINT16>::Type Type; { __VA_ARGS__; } break; } \
1251  case MAT_T_UINT8: { typedef typename MatType<MAT_T_UINT8>::Type Type; { __VA_ARGS__; } break; } \
1252  default: \
1253  throw VarMatTypeError( streamstr("Uknown/unsupported encoded type from matio: " \
1254  <<(typ)) ); \
1255  } \
1256  } while (false)
1257 
1264 #define MAT_SWITCH_COMPLEX_TYPE(typ, ...) \
1265  do { switch (typ) { \
1266  case MAT_T_DOUBLE: { typedef std::complex<typename MatType<MAT_T_DOUBLE>::Type> Type; { __VA_ARGS__; } break; } \
1267  case MAT_T_SINGLE: { typedef std::complex<typename MatType<MAT_T_SINGLE>::Type> Type; { __VA_ARGS__; } break; } \
1268  default: \
1269  throw VarMatTypeError( streamstr("Uknown/unsupported encoded type from matio: " \
1270  <<(typ)) ); \
1271  } \
1272  } while (false)
1273 
1274 
1282 #define MAT_SWITCH_TYPE(matvar_ptr, ...) \
1283  do { \
1284  if (!(matvar_ptr)->isComplex) { \
1285  switch ((matvar_ptr)->data_type) { \
1286  case MAT_T_DOUBLE: { typedef typename MatType<MAT_T_DOUBLE>::Type Type; { __VA_ARGS__; } break; } \
1287  case MAT_T_SINGLE: { typedef typename MatType<MAT_T_SINGLE>::Type Type; { __VA_ARGS__; } break; } \
1288  case MAT_T_INT64: { typedef typename MatType<MAT_T_INT64>::Type Type; { __VA_ARGS__; } break; } \
1289  case MAT_T_INT32: { typedef typename MatType<MAT_T_INT32>::Type Type; { __VA_ARGS__; } break; } \
1290  case MAT_T_INT16: { typedef typename MatType<MAT_T_INT16>::Type Type; { __VA_ARGS__; } break; } \
1291  case MAT_T_INT8: { typedef typename MatType<MAT_T_INT8>::Type Type; { __VA_ARGS__; } break; } \
1292  case MAT_T_UINT64: { typedef typename MatType<MAT_T_UINT64>::Type Type; { __VA_ARGS__; } break; } \
1293  case MAT_T_UINT32: { typedef typename MatType<MAT_T_UINT32>::Type Type; { __VA_ARGS__; } break; } \
1294  case MAT_T_UINT16: { typedef typename MatType<MAT_T_UINT16>::Type Type; { __VA_ARGS__; } break; } \
1295  case MAT_T_UINT8: { typedef typename MatType<MAT_T_UINT8>::Type Type; { __VA_ARGS__; } break; } \
1296  default: \
1297  throw VarMatTypeError( streamstr("Uknown/unsupported encoded type from matio: " \
1298  << (matvar_ptr)->data_type) ); \
1299  } \
1300  } else { \
1301  switch ((matvar_ptr)->data_type) { \
1302  case MAT_T_DOUBLE: { typedef std::complex<typename MatType<MAT_T_DOUBLE>::Type> Type; { __VA_ARGS__; } break; } \
1303  case MAT_T_SINGLE: { typedef std::complex<typename MatType<MAT_T_SINGLE>::Type> Type; { __VA_ARGS__; } break; } \
1304  default: \
1305  throw VarMatTypeError( streamstr("Uknown/unsupported encoded type from matio: " \
1306  << (matvar_ptr)->data_type) ); \
1307  } \
1308  } \
1309  } while (false)
1310 
1311 
1312 
1313 
1314 // =============================================================================
1315 // now, let's define some ways to get variable values.
1316 // =============================================================================
1317 
1318 
1319 
1323 template<typename T>
1325 #ifdef TOMOGRAPHER_PARSED_BY_DOXYGEN
1326  _IS_NUMERIC_TYPE
1327 #else
1328  typename std::enable_if<(std::numeric_limits<T>::is_specialized ||
1329  Tools::isComplex<T>::value)>::type
1330 #endif
1331  >
1332 {
1333 public:
1335  typedef T RetType;
1336 
1338  static inline void checkShape(const Var & var)
1339  {
1340  if (var.isComplex() && !Tools::isComplex<T>::value) {
1341  throw VarTypeError(var.varName(),
1342  streamstr("Can't store complex matrix in type " << typeid(T).name()));
1343  }
1344  if (var.numel() != 1) {
1345  throw VarTypeError(var.varName(),
1346  streamstr("Expected scalar but got matrix"));
1347  }
1348  }
1349 
1351  static inline RetType decodeValue(const Var & var)
1352  {
1353  const matvar_t * matvar_ptr = var.getMatvarPtr();
1354 
1355  MAT_SWITCH_TYPE(matvar_ptr,
1356  return get_value<Type>(matvar_ptr, var.varName());
1357  );
1358  // should never reach here
1359  tomographer_assert(false);
1360  }
1361 
1362 private:
1363  template<typename MATType,
1364  TOMOGRAPHER_ENABLED_IF_TMPL(!Tools::isComplex<RetType>::value &&
1366  static inline RetType get_value(const matvar_t * matvar_ptr, const std::string & )
1367  {
1368  return RetType( ((const MATType *) matvar_ptr->data)[0] );
1369  }
1370 
1371  template<typename MATType,
1372  TOMOGRAPHER_ENABLED_IF_TMPL(Tools::isComplex<RetType>::value &&
1374  static inline RetType get_value(const matvar_t * matvar_ptr, const std::string & )
1375  {
1376  return RetType( typename Tools::ComplexRealScalar<RetType>::type(((const MATType *) matvar_ptr->data)[0]),
1377  0 );
1378  }
1379 
1380  template<typename MATType,
1381  TOMOGRAPHER_ENABLED_IF_TMPL(!Tools::isComplex<RetType>::value &&
1383  static inline RetType get_value(const matvar_t * /*matvar_ptr*/, const std::string & varname)
1384  {
1385  throw VarTypeError(varname, "Expected real scalar, got complex type");
1386  }
1387 
1388  template<typename MATType,
1389  TOMOGRAPHER_ENABLED_IF_TMPL(Tools::isComplex<RetType>::value &&
1391  static inline RetType get_value(const matvar_t * matvar_ptr, const std::string & )
1392  {
1393  typedef typename Tools::ComplexRealScalar<MATType>::type MATRealType;
1394  const mat_complex_split_t * cdata = (mat_complex_split_t*) matvar_ptr->data;
1395 
1396  return RetType( typename Tools::ComplexRealScalar<RetType>::type( ((const MATRealType *) cdata->Re)[0] ),
1397  typename Tools::ComplexRealScalar<RetType>::type( ((const MATRealType *) cdata->Im)[0] ) );
1398  }
1399 
1400 };
1401 
1402 
1403 
1404 // -----------------------------------------------
1405 
1406 
1407 namespace tomo_internal {
1408 
1410 template<typename OutType, typename MatInnerT>
1411 class VarMatDataAccessor
1412 {
1413  const Var & p_var;
1414 
1415  typedef typename Tools::ComplexRealScalar<MatInnerT>::type MatRealInnerT;
1416 
1417  const MatInnerT * p_r_ptr;
1418  const MatRealInnerT * p_cre_ptr;
1419  const MatRealInnerT * p_cim_ptr;
1420 
1421 public:
1422  VarMatDataAccessor(const Var & var)
1423  : p_var(var)
1424  {
1425  const matvar_t * matvar_ptr = var.getMatvarPtr();
1426  tomographer_assert(matvar_ptr->data != NULL);
1427  if (!matvar_ptr->isComplex) {
1428  // real type
1429  p_r_ptr = (const MatInnerT*) matvar_ptr->data;
1430  p_cre_ptr = NULL;
1431  p_cim_ptr = NULL;
1432  } else {
1433  const mat_complex_split_t * cdata = (mat_complex_split_t*) matvar_ptr->data;
1434  p_r_ptr = NULL;
1435  p_cre_ptr = (const MatRealInnerT*) cdata->Re;
1436  p_cim_ptr = (const MatRealInnerT*) cdata->Im;
1437  tomographer_assert(p_cre_ptr != NULL);
1438  tomographer_assert(p_cim_ptr != NULL);
1439  }
1440  }
1441 
1442  virtual ~VarMatDataAccessor() { }
1443 
1444  template<typename IndexListType,
1445  typename OutType__ = OutType, typename MatInnerT__ = MatInnerT,
1446  TOMOGRAPHER_ENABLED_IF_TMPL(!Tools::isComplex<OutType__>::value &&
1448  inline OutType value(IndexListType&& index) const
1449  {
1450  tomographer_assert(p_r_ptr != NULL);
1451 
1452  // real value.
1453  std::size_t lin = linear_index(std::forward<IndexListType>(index));
1454  return (OutType)p_r_ptr[lin];
1455  }
1456 
1457  template<typename IndexListType,
1458  typename OutType__ = OutType, typename MatInnerT__ = MatInnerT,
1459  TOMOGRAPHER_ENABLED_IF_TMPL(!Tools::isComplex<OutType__>::value &&
1461  inline OutType value(IndexListType&& ) const
1462  {
1463  throw VarTypeError(p_var.varName(), "Expected real type, got complex");
1464  }
1465 
1466  template<typename IndexListType,
1467  typename OutType__ = OutType, typename MatInnerT__ = MatInnerT,
1468  TOMOGRAPHER_ENABLED_IF_TMPL(Tools::isComplex<OutType__>::value &&
1470  inline OutType value(IndexListType&& index) const
1471  {
1472  tomographer_assert(p_r_ptr != NULL);
1473 
1474  // real value.
1475  std::size_t lin = linear_index(std::forward<IndexListType>(index));
1476  return OutType( typename Eigen::NumTraits<OutType>::Real(p_r_ptr[lin]) , 0 );
1477  }
1478 
1479  template<typename IndexListType,
1480  typename OutType__ = OutType, typename MatInnerT__ = MatInnerT,
1481  TOMOGRAPHER_ENABLED_IF_TMPL(Tools::isComplex<OutType__>::value &&
1483  inline OutType value(IndexListType&& index) const
1484  {
1485  tomographer_assert(p_cre_ptr != NULL);
1486  tomographer_assert(p_cim_ptr != NULL);
1487 
1488  // complex value
1489  std::size_t lin = linear_index(std::forward<IndexListType>(index));
1490  return OutType( typename Eigen::NumTraits<OutType>::Real(p_cre_ptr[lin]),
1491  typename Eigen::NumTraits<OutType>::Real(p_cim_ptr[lin]) );
1492  }
1493 
1494 private:
1495  template<typename IndexListType>
1496  std::size_t linear_index(IndexListType && index) const
1497  {
1498  IndexList<false> ind_cmaj{
1499  p_var.dims(),
1501  };
1502  // std::cout << "linear_index: ind_cmaj=" << ind_cmaj << ", -> linear index = " << ind_cmaj.linearIndex() << "\n";
1503  return ind_cmaj.linearIndex();
1504  }
1505 };
1506 
1507 } // namespace tomo_internal
1508 
1509 
1510 // -----------------------------------------------
1511 
1552 struct VarShape
1553 {
1561  const bool is_complex;
1562 
1577  const DimList dims;
1578 
1593  const bool is_square;
1594 
1599  template<typename DimListType>
1600  VarShape(bool is_complex_, DimListType&& dims_, bool is_square_)
1601  : is_complex(is_complex_), dims(std::forward<DimListType>(dims_)), is_square(is_square_)
1602  {
1603  _check_consistency();
1604  }
1605 
1611  VarShape(const Var & var)
1612  : is_complex(var.isComplex()), dims(var.dims()), is_square(var.isSquareMatrix())
1613  {
1614  }
1615 
1616 
1617 private:
1618  void _check_consistency()
1619  {
1620  if (is_square) {
1621  tomographer_assert(dims.size() == 0 || (dims.size() == 2 && (dims[0] == -1 || dims[1] == -1 || dims[0] == dims[1])));
1622  }
1623  }
1624 
1625 public:
1626 
1634  inline void checkShape(const VarShape & shape);
1635 
1643  inline void checkShape(const Var & var)
1644  {
1645  try {
1646  checkShape(VarShape(var));
1647  } catch (VarTypeError & err) {
1648  err.setVarName(var.varName());
1649  throw;
1650  }
1651  }
1652 };
1653 
1655 inline std::ostream& operator<<(std::ostream& str, const VarShape & varshape)
1656 {
1657  str << ((varshape.is_complex) ? std::string("complex ") : std::string("real "));
1658  if (varshape.dims.size() == 1) {
1659  str << "vector";
1660  } else if (varshape.dims.size() == 2) {
1661  if (varshape.is_square) {
1662  str << "square ";
1663  }
1664  str << "matrix";
1665  } else if (varshape.dims.size() > 0) {
1666  str << varshape.dims.size() << "-D array";
1667  if (varshape.is_square) {
1668  str << " with first two dimensions square";
1669  }
1670  } else {
1671  // empty dims means no requirement
1672  str << "array";
1673  }
1674  if (varshape.dims.size()) {
1675  str << " of shape " << varshape.dims;
1676  }
1677  return str;
1678 }
1679 
1680 inline void VarShape::checkShape(const VarShape& other)
1681 {
1682  const DimList mvardims = other.dims;
1683 
1684  if ((other.is_complex && !is_complex) ||
1685  (mvardims.size() != dims.size() && dims.size() > 0) ||
1686  (is_square && (mvardims.size() != 2 || mvardims[0] != mvardims[1])) ||
1687  (dims.size() > 0 && !mvardims.matchesWanted(dims))) {
1688 
1689  std::stringstream errstr;
1690 
1691  errstr << "Expected "
1692  << *this
1693  << ", got "
1694  << other;
1695 
1696  //fprintf(stderr, "Bad var type for variable %s\n", var.varName().c_str());
1697  throw VarTypeError(std::string(), errstr.str());
1698 
1699  }
1700 }
1701 
1702 
1703 
1704 // -----------------------------------------------------------------------------
1705 
1706 // get an std::vector<T> for a variable.
1707 
1717 template<typename T_, bool IsRowMajor_ = false>
1719  typedef T_ type;
1720  static constexpr bool IsRowMajor = IsRowMajor_;
1721 };
1722 
1724 template<typename T, bool IsRowMajor>
1725 class VarValueDecoder<GetStdVector<T, IsRowMajor> >
1726 {
1727 public:
1728  typedef std::vector<T> RetType;
1729 
1730  static inline void checkShape(const Var & var)
1731  {
1732  if (var.isComplex() && !Tools::isComplex<T>::value) {
1733  throw VarTypeError(var.varName(),
1734  std::string("can't store complex matrix in type ")
1735  + typeid(T).name());
1736  }
1737  }
1738 
1739  static inline std::vector<T> decodeValue(const Var & var)
1740  {
1741  const matvar_t * matvar_ptr = var.getMatvarPtr();
1742  std::size_t numel = var.numel();
1743  std::vector<T> val(numel);
1744 
1745  MAT_SWITCH_TYPE(matvar_ptr,
1746  tomo_internal::VarMatDataAccessor<T, Type> acc(var);
1747 
1748  for(IndexListIterator<IsRowMajor> il(var.dims()); il.valid(); ++il) {
1749  // std::cout << "index: " << il << "\n";
1750  val[il.linearIndex()] = acc.value(il);
1751  }
1752 
1753  return val;
1754  );
1755  // should never reach here
1756  tomographer_assert(false);
1757  }
1758 
1759 };
1760 
1761 
1762 
1763 
1764 
1765 
1766 
1767 // =============================================================================
1768 
1769 // get Eigen types.
1770 
1771 namespace tomo_internal {
1772 
1773 
1774 inline DimList dims_stackedcols(DimList vdims)
1775 {
1776  tomographer_assert(vdims.size() >= 1);
1777  DimList vdimsreshaped;
1778  if (vdims.size() == 1) {
1779  vdimsreshaped = vdims;
1780  vdimsreshaped << 1;
1781  } else if (vdims.size() == 2) {
1782  vdimsreshaped = vdims;
1783  } else if (vdims.size() > 2) {
1784  vdimsreshaped << getNumEl(vdims.data(), vdims.data()+vdims.size()-1) << vdims[vdims.size()-1];
1785  }
1786  tomographer_assert(vdimsreshaped[0] != -1 && vdimsreshaped[1] != -1);
1787  return vdimsreshaped;
1788 }
1789 
1790 template<typename MatrixType, typename MatType,
1791  TOMOGRAPHER_ENABLED_IF_TMPL(Eigen::NumTraits<typename MatrixType::Scalar>::IsComplex &&
1793 void init_eigen_matrix(MatrixType & matrix, const DimList & vdims,
1794  const Var & var, const std::ptrdiff_t data_offset = 0)
1795 {
1796  typedef typename MatrixType::Scalar Scalar;
1797  typedef typename Eigen::NumTraits<Scalar>::Real RealScalar;
1798 
1799  typedef typename Eigen::NumTraits<MatType>::Real MatRealType;
1800 
1801  const matvar_t * matvar_ptr = var.getMatvarPtr();
1802 
1803  const mat_complex_split_t * cdata = (mat_complex_split_t*) matvar_ptr->data;
1804 
1805  DimList vdimsreshaped = dims_stackedcols(vdims);
1806 
1807  matrix = (
1809  (const MatRealType *) cdata->Re + data_offset, vdimsreshaped[0], vdimsreshaped[1]
1810  ).template cast<std::complex<RealScalar> >()
1811  + std::complex<RealScalar>(0,1) *
1813  (const MatRealType *) cdata->Im + data_offset, vdimsreshaped[0], vdimsreshaped[1]
1814  ).template cast<std::complex<RealScalar> >()
1815  );
1816 }
1817 
1818 template<typename MatrixType, typename MatRealType,
1819  TOMOGRAPHER_ENABLED_IF_TMPL(!Eigen::NumTraits<typename MatrixType::Scalar>::IsComplex &&
1821 void init_eigen_matrix(MatrixType & /*matrix*/, const DimList & /*vdims*/,
1822  const Var & var, const std::ptrdiff_t /*data_offset*/ = 0)
1823 {
1824  throw VarTypeError(var.varName(), "Expected real type, but got complex.");
1825 }
1826 
1827 template<typename MatrixType, typename MatRealType,
1828  TOMOGRAPHER_ENABLED_IF_TMPL(!Eigen::NumTraits<MatRealType>::IsComplex)>
1829 void init_eigen_matrix(MatrixType & matrix, const DimList & vdims,
1830  const Var & var, const std::ptrdiff_t data_offset = 0)
1831 {
1832  typedef typename MatrixType::Scalar Scalar;
1833 
1834  const matvar_t * matvar_ptr = var.getMatvarPtr();
1835 
1836  DimList vdimsreshaped = dims_stackedcols(vdims);
1837 
1838  matrix = (
1840  (const MatRealType *) matvar_ptr->data + data_offset, vdimsreshaped[0], vdimsreshaped[1]
1841  )
1842  ).template cast<Scalar>();
1843 }
1844 
1845 } // namespace tomo_internal
1846 
1847 
1848 
1857 template<typename Scalar, int Rows, int Cols, int Options, int MaxRows, int MaxCols>
1858 class VarValueDecoder<Eigen::Matrix<Scalar,Rows,Cols,Options,MaxRows,MaxCols> >
1859 {
1860 public:
1861 
1863  typedef typename Eigen::NumTraits<Scalar>::Real RealScalar;
1864  typedef MatrixType RetType;
1865 
1866  /* not needed in fact.
1867  struct Params {
1868  Params() : dims{Rows, Cols}
1869  {
1870  }
1871  Params(int rows) : dims{rows, 1}
1872  {
1873  tomographer_assert(Cols == 1);
1874  tomographer_assert(Rows == Eigen::Dynamic || Rows == rows);
1875  }
1876  Params(int rows, int cols) : dims{rows, cols}
1877  {
1878  tomographer_assert(Rows == Eigen::Dynamic || Rows == rows);
1879  tomographer_assert(Cols == Eigen::Dynamic || Cols == cols);
1880  }
1881  Params(const DimList& dims_) : dims{dims_}
1882  {
1883  tomographer_assert(dims.size() == 2);
1884  tomographer_assert(Rows == Eigen::Dynamic || Rows == dims[0]);
1885  tomographer_assert(Cols == Eigen::Dynamic || Cols == dims[1]);
1886  }
1887 
1888  const DimList dims;
1889  };
1890  */
1891 
1892  static inline void checkShape(const Var & var) //, const Params & p = Params())
1893  {
1894  DimList matdims;
1895  matdims << (Rows!=Eigen::Dynamic ? Rows : -1)
1896  << (Cols!=Eigen::Dynamic ? Cols : -1);
1897 
1899  matdims,
1900  matdims[0] != -1 && matdims[0] == matdims[1]);
1901 
1902  DimList vdims = var.dims();
1903  if (vdims.size() > 2) {
1904  vdims = (DimList() << getNumEl(vdims.data(), vdims.data()+vdims.size()-1) << vdims[vdims.size()-1]);
1905  }
1906  try {
1907  shape.checkShape(VarShape(var.isComplex(), vdims, (vdims[0] != -1 && vdims[0] == vdims[1])));
1908  } catch (VarTypeError & err) {
1909  err.setVarName(var.varName());
1910  throw; // re-throw
1911  }
1912  }
1913 
1914  static inline RetType decodeValue(const Var & var) //, const Params & p = Params())
1915  {
1916  const matvar_t * matvar_ptr = var.getMatvarPtr();
1917  DimList vdims{var.dims()};
1918 
1919  if (vdims.size() < 2) {
1920  throw VarTypeError(var.varName(), streamstr("Expected matrix, but variable shape is " << vdims));
1921  }
1922  // if we are stacking several dimensions in the column, force column-major ordering.
1923  if (vdims.size() > 2 &&
1924  ((MatrixType::Options & Eigen::RowMajorBit) == Eigen::RowMajor)) {
1925  throw VarTypeError(var.varName(),
1926  "When collapsing several dimensions into Eigen columns, you must use "
1927  "column-major ordering (sorry).");
1928  }
1929 
1930  const int cols = vdims[vdims.size()-1];
1931  // rest of dimensions.
1932  const int rows = getNumEl(vdims.data(), vdims.data()+vdims.size()-1);
1933 
1934  MatrixType matrix(rows, cols);
1935 
1937  matvar_ptr,
1938  tomo_internal::init_eigen_matrix<MatrixType, Type>(
1939  matrix, vdims, var
1940  );
1941  );
1942 
1943  return matrix;
1944  }
1945 
1946 };
1947 
1948 
1949 
1950 
1951 
1961 template<typename Scalar, int Rows, int Cols, int Options, int MaxRows, int MaxCols, typename Alloc>
1962 class VarValueDecoder<std::vector<Eigen::Matrix<Scalar,Rows,Cols,Options,MaxRows,MaxCols>, Alloc> >
1963 {
1964 public:
1965 
1967  typedef typename Eigen::NumTraits<Scalar>::Real RealScalar;
1968 
1970 
1971  static inline void checkShape(const Var & var)
1972  {
1973  DimList matdims;
1974  matdims << (Rows!=Eigen::Dynamic ? Rows : -1)
1975  << (Cols!=Eigen::Dynamic ? Cols : -1)
1976  << -1;
1977 
1979  matdims,
1980  false);
1981 
1982  DimList vdims = var.dims();
1983  if (vdims.size() < 1) {
1984  throw VarTypeError(var.varName(), "Invalid (empty) variable dimensions");
1985  }
1986  if (vdims.size() == 1) {
1987  vdims << 1 << 1;
1988  } else if (vdims.size() == 2) {
1989  vdims << 1;
1990  } else { //if (vdims.size() > 2) {
1991  vdims = (DimList() << vdims[0] << vdims[1] << getNumEl(vdims.data()+2, vdims.data()+vdims.size()));
1992  }
1993 
1994  // check shape now:
1995  try {
1996  shape.checkShape(VarShape(var.isComplex(), vdims, false));
1997  } catch (VarTypeError & err) {
1998 
1999  err.setVarName(var.varName());
2000  throw; // re-throw
2001  }
2002 
2003  }
2004 
2005  static inline RetType decodeValue(const Var & var)
2006  {
2007  DimList vardims{var.dims()};
2008 
2009  tomographer_assert(vardims.size() >= 1);
2010 
2011  DimList innerdims;
2012  std::size_t outerdim = 1;
2013  if (vardims.size() == 1) {
2014  innerdims << vardims[0] << 1;
2015  } else if (vardims.size() == 2) {
2016  innerdims = vardims;
2017  } else {
2018  // more dimensions
2019  innerdims << vardims[0] << vardims[1];
2020  outerdim = getNumEl(vardims.data()+2, vardims.data()+vardims.size());
2021  }
2022 
2023  RetType value(outerdim);
2024 
2025  std::ptrdiff_t innernumel = innerdims[0]*innerdims[1];
2026 
2027  std::size_t j;
2028  const matvar_t * matvar_ptr = var.getMatvarPtr();
2029 
2031  matvar_ptr,
2032  for (j = 0; j < outerdim; ++j) {
2033  tomo_internal::init_eigen_matrix<MatrixType,Type>(
2034  value[j], // matrix reference
2035  innerdims, // dimensions of matrix reference
2036  var, // data
2037  j*innernumel // offset
2038  );
2039  }
2040  );
2041 
2042  return value;
2043  }
2044 
2045 };
2046 
2047 
2048 // get a (guaranteed) positive semidefinite matrix from the variable, along with its
2049 // matrix square root
2050 
2051 template<typename EigenType> class EigenPosSemidefMatrixWithSqrt;
2052 template<typename EigenType> class VarValueDecoder<EigenPosSemidefMatrixWithSqrt<EigenType> >;
2053 
2054 
2070 template<typename EigenType_>
2072 {
2073 public:
2074  typedef EigenType_ EigenType;
2075  typedef typename Eigen::NumTraits<typename EigenType::Scalar>::Real RealScalarType;
2076 
2089  struct Params {
2092  : tolerance(tolerance_) { }
2094  const RealScalarType tolerance;
2095  };
2096 
2099 
2101  EigenType mat;
2103  EigenType sqrt;
2104 
2105 private:
2106  friend class VarValueDecoder<EigenPosSemidefMatrixWithSqrt<EigenType> >;
2107 
2108  EigenPosSemidefMatrixWithSqrt(EigenType && m, const Params & p)
2109  : eig( m )
2110  {
2111  typedef typename Eigen::SelfAdjointEigenSolver<EigenType>::RealVectorType RealVectorType;
2112 
2113  auto U = eig.eigenvectors();
2114  auto d = eig.eigenvalues();
2115 
2116  Tomographer::MathTools::forcePosVecKeepSum<RealVectorType>(d, p.tolerance);
2117 
2118  mat = U * d.asDiagonal() * U.adjoint();
2119  sqrt = U * d.cwiseSqrt().asDiagonal() * U.adjoint();
2120  }
2121 };
2123 template<typename EigenType_>
2124 class VarValueDecoder<EigenPosSemidefMatrixWithSqrt<EigenType_> >
2125 {
2126 public:
2127  typedef EigenType_ EigenType;
2129 
2131 
2133 
2134  static inline void checkShape(const Var & var, const Params & = Params())
2135  {
2136  // make sure we can decode the given variable
2137  EigenVarDecoder::checkShape(var);
2138  // make sure that var is a square matrix
2139  const DimList d = var.dims();
2140  if (d.size() != 2 || d[0] != d[1]) {
2141  throw VarTypeError(var.varName(), std::string("variable to decode is not a square matrix"));
2142  }
2143  }
2144 
2145  static inline RetType decodeValue(const Var & var, const Params & p = Params())
2146  {
2147  return EigenPosSemidefMatrixWithSqrt<EigenType>(EigenVarDecoder::decodeValue(var), p);
2148  }
2149 
2150 };
2151 
2152 
2153 
2154 
2155 
2156 } // namespace MAT
2157 } // namespace Tomographer
2158 
2159 
2160 
2161 
2162 #endif
Utilities for formatting strings.
Utility to iterate over a multidim array by increasing linear index.
Definition: ezmatio.h:627
File(File &&other)
Move constructor.
Definition: ezmatio.h:215
DimList()
Initializes an empty dimension list.
Definition: ezmatio.h:310
DimList dims() const
Specific dimensions of this numeric array or tensor.
Definition: ezmatio.h:1020
const std::string & varName() const
The variable name.
Definition: ezmatio.h:1001
T operator=(T... args)
Base namespace for the Tomographer project.
Definition: densellh.h:45
IndexList(const std::vector< int > &dims=std::vector< int >(), int linearindex=-1)
Constructor with linear index.
Definition: ezmatio.h:453
Var var(const std::string varname, bool load_data=true)
Find a variable by name.
Definition: ezmatio.h:1163
Invalid index or index list provided to a routine.
Definition: ezmatio.h:168
const RealVectorType & eigenvalues() const
Unknown type of a variable present in the data file.
Definition: ezmatio.h:135
void checkShape(const Var &var)
Shorthand for checkShape(const VarShape& other) for a shape given by a variable.
Definition: ezmatio.h:1643
Error while reading a variable from the MATLAB data file.
Definition: ezmatio.h:113
const std::vector< int > & index() const
Return a reference to *this.
Definition: ezmatio.h:547
DimList(VectorType &&dims)
Initialize a dimension list with another list of dimensions.
Definition: ezmatio.h:318
int numel() const
Get the total number of elements in an array of these dimensions.
Definition: ezmatio.h:352
A MATLAB file open for reading data.
Definition: ezmatio.h:192
EigenType mat
The matrix itself.
Definition: ezmatio.h:2101
int ndims() const
Get the number of dimensions in this array.
Definition: ezmatio.h:359
STL namespace.
STL class.
Var & operator=(Var &&other)
Move assignment operator as this object implements C++11 move semantics.
Definition: ezmatio.h:1143
statically determine whether a type is complex
Definition: cxxutil.h:344
T end(T... args)
File(const std::string fname)
Open a data file for reading.
Definition: ezmatio.h:200
VarValueDecoder< T >::RetType value() const
Read this variable data as native C++ object.
Definition: ezmatio.h:1109
A list of indices with an API for linear or subindices access.
Definition: ezmatio.h:440
Base Exception class for errors within our MAT routines.
Definition: ezmatio.h:70
Specializable template which takes care of decoding values.
Definition: ezmatio.h:802
IndexList & operator<<(int ind)
Append index to list.
Definition: ezmatio.h:568
IndexList(const std::vector< int > &dims, VectorIntInitializer &&index)
Constructor with multidimensional index specification.
Definition: ezmatio.h:473
std::vector< Var > getVarInfoList()
Get a list of all variables in this data file.
Definition: ezmatio.h:1168
STL class.
Map matio&#39;s constants to C/C++ types.
Definition: ezmatio.h:1211
Tools for dealing with positive semidefinite matrices.
Error while opening a MATLAB file.
Definition: ezmatio.h:149
T push_back(T... args)
static Var takeOver(matvar_t *varinfo)
Take in charge the given C matvar_t pointer.
Definition: ezmatio.h:992
T data(T... args)
Var(Var &&other)
Var implements C++11 move semantics.
Definition: ezmatio.h:969
Basic utilities for dealing with Eigen matrices and other types.
void checkShape(const VarShape &shape)
Verify that our requirements match the given other shape.
Definition: ezmatio.h:1680
const bool is_complex
Whether the variable is or should be complex.
Definition: ezmatio.h:1561
A MATLAB variable in the MAT file.
Definition: ezmatio.h:911
std::vector< int > VectorType
Base vector type (superclass)
Definition: ezmatio.h:446
EigenType sqrt
The matrix square root of the read matrix.
Definition: ezmatio.h:2103
Params(RealScalarType tolerance_=Eigen::NumTraits< RealScalarType >::dummy_precision())
Constructor, specify the tolerance.
Definition: ezmatio.h:2091
const RealScalarType tolerance
The tolerance.
Definition: ezmatio.h:2094
VarValueDecoder< T >::RetType value(const Var &var, const typename VarValueDecoder< T >::Params &params)
Access the value of the given variable, as a C++ type.
Definition: ezmatio.h:886
T str(T... args)
Ask for this type in Var::value<typename T>() to get an std::vector of the data.
Definition: ezmatio.h:1718
Parameters to read the positive semidefinite matrix.
Definition: ezmatio.h:2089
int ndims() const
Number of dimensions of this object.
Definition: ezmatio.h:1011
Some C++ utilities, with a tad of C++11 tricks.
STL class.
T move(T... args)
Read a positive semidefinite matrix along with its matrix square root.
Definition: ezmatio.h:2051
internal::plain_col_type< MatrixType, RealScalar >::type RealVectorType
static RetType decodeValue(const Var &var)
Decode the variable var into the C++ type T.
Definition: ezmatio.h:1184
T size(T... args)
static void checkShape(const Var &var)
Check that the type and shape of the var are compatible with T.
Definition: ezmatio.h:818
std::ostream & operator<<(std::ostream &out, const DimList &dlist)
C++ output stream operators for a DimList.
Definition: ezmatio.h:398
#define MAT_SWITCH_TYPE(matvar_ptr,...)
Useful hack to get C++ type from dynamical MAT type ID.
Definition: ezmatio.h:1282
STL class.
An array of ints which specifies a list of dimensions.
Definition: ezmatio.h:306
Var & operator=(const Var &copy)
Var objects are copyable. Beware though that the data is shared.
Definition: ezmatio.h:1151
const std::vector< int > & dims() const
Get the underlying dimensions given to the constructor.
Definition: ezmatio.h:556
VarShape(bool is_complex_, DimListType &&dims_, bool is_square_)
Construct a VarShape object from given characteristics.
Definition: ezmatio.h:1600
bool isComplex() const
Whether this variable is complex or real.
Definition: ezmatio.h:1043
File & operator=(File &&other)
Move assignment operator.
Definition: ezmatio.h:263
T begin(T... args)
VarShape(const Var &var)
Construct a VarShape object reflecting the actual shape of a variable in the data file...
Definition: ezmatio.h:1611
bool isSquareMatrix() const
Whether this is a square matrix.
Definition: ezmatio.h:1052
const MatrixType & eigenvectors() const
::value DimList(std::initializer_list< T > init)
Initialize the dimension list with an explicit initializer.
Definition: ezmatio.h:334
VarValueDecoder< T >::RetType value(const Var &var)
Access the value of the given variable, as a C++ type.
Definition: ezmatio.h:871
T c_str(T... args)
const matvar_t * getMatvarPtr() const
Access the underlying C pointer to the MatIO structure. Use with care.
Definition: ezmatio.h:1134
static void checkShape(const Var &var)
See VarValueDecoder::checkShape()
Definition: ezmatio.h:1338
Type mismatch (wrong type requested) in a variable read from the MATLAB data file.
Definition: ezmatio.h:124
Exception relating to a MATLAB variable in the data file.
Definition: ezmatio.h:99
Describe shape of variable and whether it is complex.
Definition: ezmatio.h:1552
mat_t * getMatPtr()
Direct access to the underlying C pointer used for the MatIO library.
Definition: ezmatio.h:253
DimList & operator<<(int dim)
Add (append) a dimension to the dimension list.
Definition: ezmatio.h:382
static RetType decodeValue(const Var &var)
See VarValueDecoder::decodeValue()
Definition: ezmatio.h:1351
const unsigned int RowMajorBit
T RetType
Type returned by decodeValue()
Definition: ezmatio.h:810
#define streamstr(tokens)
Utility macro to format stream tokens to a std::string.
Definition: fmt.h:146
Var(File &matf, const std::string &varname, bool load_data=true)
Read variable from MATLAB data file.
Definition: ezmatio.h:944
bool matchesWanted(const DimList &wanted) const
Test whether our dimensions match the given required list of dimensions.
Definition: ezmatio.h:364
Var(const Var &copy)
Var objects are copyable. Beware though that the data is shared.
Definition: ezmatio.h:962
DimList(It b, It e)
Initialize the dimension list with an iterator range.
Definition: ezmatio.h:344
STL class.
const DimList dims
The dimensions of the variable, or requested dimensions.
Definition: ezmatio.h:1577
RowMajor
ValueType getNumEl(It begin, It end)
Calculate the product of all dimensions.
Definition: ezmatio.h:283
const bool is_square
Whether the variable&#39;s two first dimensions are (or should be) the same.
Definition: ezmatio.h:1593
VarValueDecoder< T >::RetType value(const typename VarValueDecoder< T >::Params &params)
Read this variable data as native C++ object.
Definition: ezmatio.h:1124
Eigen::SelfAdjointEigenSolver< EigenType > eig
The readily-initialized eigenvalue decomposition of the matrix read from the MAT file.
Definition: ezmatio.h:2098
bool hasData() const
Whether data for this Var object has been loaded.
Definition: ezmatio.h:1063
int numel() const
The total number of elements in this array or tensor.
Definition: ezmatio.h:1030