MatlabWorkspace.cpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. #include "igl/matlab/MatlabWorkspace.h"
  2. // IGL
  3. #include "igl/list_to_matrix.h"
  4. // MATLAB
  5. #include "mat.h"
  6. // STL
  7. #include <iostream>
  8. #include <algorithm>
  9. IGL_INLINE igl::MatlabWorkspace::MatlabWorkspace()
  10. {
  11. }
  12. IGL_INLINE igl::MatlabWorkspace::~MatlabWorkspace()
  13. {
  14. // clean up data
  15. clear();
  16. }
  17. IGL_INLINE void igl::MatlabWorkspace::clear()
  18. {
  19. for_each(data.begin(),data.end(),&mxDestroyArray);
  20. data.clear();
  21. names.clear();
  22. }
  23. IGL_INLINE bool igl::MatlabWorkspace::write(const std::string & path) const
  24. {
  25. using namespace std;
  26. MATFile * mat_file = matOpen(path.c_str(), "w");
  27. assert(names.size() == data.size());
  28. // loop over names and data
  29. for(int i = 0;i < (int)names.size(); i++)
  30. {
  31. // Put variable as LOCAL variable
  32. int status = matPutVariable(mat_file,names[i].c_str(), data[i]);
  33. if(status != 0)
  34. {
  35. cerr<<"^MatlabWorkspace::save Error: matPutVariable ("<<names[i]<<
  36. ") failed"<<endl;
  37. return false;
  38. }
  39. }
  40. if(matClose(mat_file) != 0)
  41. {
  42. fprintf(stderr,"Error closing file %s\n",path.c_str());
  43. return false;
  44. }
  45. return true;
  46. }
  47. IGL_INLINE bool igl::MatlabWorkspace::read(const std::string & path)
  48. {
  49. using namespace std;
  50. MATFile * mat_file;
  51. mat_file = matOpen(path.c_str(), "r");
  52. if (mat_file == NULL)
  53. {
  54. cerr<<"Error: failed to open "<<path<<endl;
  55. return false;
  56. }
  57. int ndir;
  58. const char ** dir = (const char **)matGetDir(mat_file, &ndir);
  59. if (dir == NULL) {
  60. cerr<<"Error reading directory of file "<< path<<endl;
  61. return false;
  62. }
  63. mxFree(dir);
  64. // Must close and reopen
  65. if(matClose(mat_file) != 0)
  66. {
  67. cerr<<"Error: failed to close file "<<path<<endl;
  68. return false;
  69. }
  70. mat_file = matOpen(path.c_str(), "r");
  71. if (mat_file == NULL)
  72. {
  73. cerr<<"Error: failed to open "<<path<<endl;
  74. return false;
  75. }
  76. /* Read in each array. */
  77. for (int i=0; i<ndir; i++)
  78. {
  79. const char * name;
  80. mxArray * mx_data = matGetNextVariable(mat_file, &name);
  81. if (mx_data == NULL)
  82. {
  83. cerr<<"Error: matGetNextVariable failed in "<<path<<endl;
  84. return false;
  85. }
  86. const int dims = mxGetNumberOfDimensions(mx_data);
  87. assert(dims == 2);
  88. if(dims != 2)
  89. {
  90. fprintf(stderr,"Variable '%s' has %d ≠ 2 dimensions. Skipping\n",
  91. name,dims);
  92. mxDestroyArray(mx_data);
  93. continue;
  94. }
  95. // don't destroy
  96. names.push_back(name);
  97. data.push_back(mx_data);
  98. }
  99. if(matClose(mat_file) != 0)
  100. {
  101. cerr<<"Error: failed to close file "<<path<<endl;
  102. return false;
  103. }
  104. return true;
  105. }
  106. // Treat everything as a double
  107. template <typename DerivedM>
  108. IGL_INLINE igl::MatlabWorkspace& igl::MatlabWorkspace::save(
  109. const Eigen::PlainObjectBase<DerivedM>& M,
  110. const std::string & name)
  111. {
  112. using namespace std;
  113. const int m = M.rows();
  114. const int n = M.cols();
  115. mxArray * mx_data = mxCreateDoubleMatrix(m,n,mxREAL);
  116. data.push_back(mx_data);
  117. names.push_back(name);
  118. // Copy data immediately
  119. // Q: Won't this be incorrect for integers?
  120. copy(M.data(),M.data()+M.size(),mxGetPr(mx_data));
  121. return *this;
  122. }
  123. // Treat everything as a double
  124. template <typename MT>
  125. IGL_INLINE igl::MatlabWorkspace& igl::MatlabWorkspace::save(
  126. const Eigen::SparseMatrix<MT>& M,
  127. const std::string & name)
  128. {
  129. using namespace std;
  130. const int m = M.rows();
  131. const int n = M.cols();
  132. // THIS WILL NOT WORK FOR ROW-MAJOR
  133. assert(n==M.outerSize());
  134. const int nzmax = M.nonZeros();
  135. mxArray * mx_data = mxCreateSparse(m, n, nzmax, mxREAL);
  136. data.push_back(mx_data);
  137. names.push_back(name);
  138. // Copy data immediately
  139. double * pr = mxGetPr(mx_data);
  140. mwIndex * ir = mxGetIr(mx_data);
  141. mwIndex * jc = mxGetJc(mx_data);
  142. // Iterate over outside
  143. int k = 0;
  144. for(int j=0; j<M.outerSize();j++)
  145. {
  146. jc[j] = k;
  147. // Iterate over inside
  148. for(typename Eigen::SparseMatrix<MT>::InnerIterator it (M,j); it; ++it)
  149. {
  150. pr[k] = it.value();
  151. ir[k] = it.row();
  152. k++;
  153. }
  154. }
  155. jc[M.outerSize()] = k;
  156. return *this;
  157. }
  158. template <typename ScalarM>
  159. IGL_INLINE igl::MatlabWorkspace& igl::MatlabWorkspace::save(
  160. const std::vector<std::vector<ScalarM> > & vM,
  161. const std::string & name)
  162. {
  163. Eigen::MatrixXd M;
  164. list_to_matrix(vM,M);
  165. return this->save(M,name);
  166. }
  167. template <typename ScalarV>
  168. IGL_INLINE igl::MatlabWorkspace& igl::MatlabWorkspace::save(
  169. const std::vector<ScalarV> & vV,
  170. const std::string & name)
  171. {
  172. Eigen::MatrixXd V;
  173. list_to_matrix(vV,V);
  174. return this->save(V,name);
  175. }
  176. template <typename DerivedM>
  177. IGL_INLINE igl::MatlabWorkspace&
  178. igl::MatlabWorkspace::save_index(
  179. const Eigen::PlainObjectBase<DerivedM>& M,
  180. const std::string & name)
  181. {
  182. DerivedM Mp1 = M;
  183. Mp1.array() += 1;
  184. return this->save(Mp1,name);
  185. }
  186. template <typename ScalarM>
  187. IGL_INLINE igl::MatlabWorkspace& igl::MatlabWorkspace::save_index(
  188. const std::vector<std::vector<ScalarM> > & vM,
  189. const std::string & name)
  190. {
  191. Eigen::MatrixXd M;
  192. list_to_matrix(vM,M);
  193. return this->save_index(M,name);
  194. }
  195. template <typename ScalarV>
  196. IGL_INLINE igl::MatlabWorkspace& igl::MatlabWorkspace::save_index(
  197. const std::vector<ScalarV> & vV,
  198. const std::string & name)
  199. {
  200. Eigen::MatrixXd V;
  201. list_to_matrix(vV,V);
  202. return this->save_index(V,name);
  203. }
  204. template <typename DerivedM>
  205. IGL_INLINE bool igl::MatlabWorkspace::find(
  206. const std::string & name,
  207. Eigen::PlainObjectBase<DerivedM>& M)
  208. {
  209. using namespace std;
  210. const int i = std::find(names.begin(), names.end(), name)-names.begin();
  211. if(i>=(int)names.size())
  212. {
  213. return false;
  214. }
  215. assert(i<=(int)data.size());
  216. mxArray * mx_data = data[i];
  217. assert(!mxIsSparse(mx_data));
  218. assert(mxGetNumberOfDimensions(mx_data) == 2);
  219. //cout<<name<<": "<<mxGetM(mx_data)<<" "<<mxGetN(mx_data)<<endl;
  220. const int m = mxGetM(mx_data);
  221. const int n = mxGetN(mx_data);
  222. // Handle vectors
  223. if(DerivedM::IsVectorAtCompileTime)
  224. {
  225. assert(m==1 || n==1 || (m==0 && n==0));
  226. M.resize(m*n);
  227. }else
  228. {
  229. M.resize(m,n);
  230. }
  231. copy(
  232. mxGetPr(mx_data),
  233. mxGetPr(mx_data)+mxGetNumberOfElements(mx_data),
  234. M.data());
  235. return true;
  236. }
  237. template <typename MT>
  238. IGL_INLINE bool igl::MatlabWorkspace::find(
  239. const std::string & name,
  240. Eigen::SparseMatrix<MT>& M)
  241. {
  242. using namespace std;
  243. using namespace Eigen;
  244. const int i = std::find(names.begin(), names.end(), name)-names.begin();
  245. if(i>=(int)names.size())
  246. {
  247. return false;
  248. }
  249. assert(i<=(int)data.size());
  250. mxArray * mx_data = data[i];
  251. // Handle boring case where matrix is actually an empty dense matrix
  252. if(mxGetNumberOfElements(mx_data) == 0)
  253. {
  254. M.resize(0,0);
  255. return true;
  256. }
  257. assert(mxIsSparse(mx_data));
  258. assert(mxGetNumberOfDimensions(mx_data) == 2);
  259. //cout<<name<<": "<<mxGetM(mx_data)<<" "<<mxGetN(mx_data)<<endl;
  260. const int m = mxGetM(mx_data);
  261. const int n = mxGetN(mx_data);
  262. // Copy data immediately
  263. double * pr = mxGetPr(mx_data);
  264. mwIndex * ir = mxGetIr(mx_data);
  265. mwIndex * jc = mxGetJc(mx_data);
  266. vector<Triplet<MT> > MIJV;
  267. MIJV.reserve(mxGetNumberOfElements(mx_data));
  268. // Iterate over outside
  269. int k = 0;
  270. for(int j=0; j<n;j++)
  271. {
  272. // Iterate over inside
  273. while(k<(int)jc[j+1])
  274. {
  275. //cout<<ir[k]<<" "<<j<<" "<<pr[k]<<endl;
  276. assert((int)ir[k]<m);
  277. assert((int)j<n);
  278. MIJV.push_back(Triplet<MT >(ir[k],j,pr[k]));
  279. k++;
  280. }
  281. }
  282. M.resize(m,n);
  283. M.setFromTriplets(MIJV.begin(),MIJV.end());
  284. return true;
  285. }
  286. template <typename DerivedM>
  287. IGL_INLINE bool igl::MatlabWorkspace::find_index(
  288. const std::string & name,
  289. Eigen::PlainObjectBase<DerivedM>& M)
  290. {
  291. if(!find(name,M))
  292. {
  293. return false;
  294. }
  295. M.array() -= 1;
  296. return true;
  297. }
  298. //template <typename Data>
  299. //bool igl::MatlabWorkspace::save(const Data & M, const std::string & name)
  300. //{
  301. // using namespace std;
  302. // // If I don't know the type then I can't save it
  303. // cerr<<"^MatlabWorkspace::save Error: Unknown data type. "<<
  304. // name<<" not saved."<<endl;
  305. // return false;
  306. //}