MatlabWorkspace.cpp 7.8 KB

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