libigl v2.5.0
Loading...
Searching...
No Matches
MatlabWorkspace.h
Go to the documentation of this file.
1// This file is part of libigl, a simple c++ geometry processing library.
2//
3// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
4//
5// This Source Code Form is subject to the terms of the Mozilla Public License
6// v. 2.0. If a copy of the MPL was not distributed with this file, You can
7// obtain one at http://mozilla.org/MPL/2.0/.
8#ifndef IGL_MATLAB_MATLAB_WORKSPACE_H
9#define IGL_MATLAB_MATLAB_WORKSPACE_H
10
11#include <Eigen/Dense>
12#include <Eigen/Sparse>
13
14#include <mat.h>
15
16#include <string>
17#include <vector>
18
19namespace igl
20{
21 namespace matlab
22 {
35 {
36 private:
39 std::vector<std::string> names;
41 std::vector<mxArray*> data;
42 public:
46 inline void clear();
51 inline bool write(const std::string & path) const;
56 inline bool read(const std::string & path);
65 template <typename DerivedM>
67 const Eigen::PlainObjectBase<DerivedM>& M,
68 const std::string & name);
71 template <typename MT>
73 const Eigen::SparseMatrix<MT>& M,
74 const std::string & name);
77 template <typename ScalarM>
79 const std::vector<std::vector<ScalarM> > & vM,
80 const std::string & name);
83 template <typename ScalarV>
85 const std::vector<ScalarV> & vV,
86 const std::string & name);
92 template <typename Q>
94 const Eigen::Quaternion<Q> & q,
95 const std::string & name);
97 inline MatlabWorkspace& save(
98 const double d,
99 const std::string & name);
103 template <typename DerivedM>
105 const Eigen::DenseBase<DerivedM>& M,
106 const std::string & name);
109 template <typename ScalarM>
111 const std::vector<std::vector<ScalarM> > & vM,
112 const std::string & name);
115 template <typename ScalarV>
117 const std::vector<ScalarV> & vV,
118 const std::string & name);
127 template <typename DerivedM>
128 inline bool find(
129 const std::string & name,
130 Eigen::PlainObjectBase<DerivedM>& M);
133 template <typename MT>
134 inline bool find(
135 const std::string & name,
136 Eigen::SparseMatrix<MT>& M);
138 inline bool find(
139 const std::string & name,
140 double & d);
142 inline bool find(
143 const std::string & name,
144 int & v);
149 template <typename DerivedM>
150 inline bool find_index(
151 const std::string & name,
152 Eigen::PlainObjectBase<DerivedM>& M);
153 };
154 }
155}
156
157// Implementation
158
159// Be sure that this is not compiled into libigl.a
160// http://stackoverflow.com/a/3318993/148668
161
162// IGL
163#include "igl/list_to_matrix.h"
164
165// MATLAB
166#include "mat.h"
167
168// STL
169#include <iostream>
170#include <algorithm>
171#include <vector>
172
174 names(),
175 data()
176{
177}
178
180{
181 // clean up data
182 clear();
183}
184
186{
187 for_each(data.begin(),data.end(),&mxDestroyArray);
188 data.clear();
189 names.clear();
190}
191
192inline bool igl::matlab::MatlabWorkspace::write(const std::string & path) const
193{
194 using namespace std;
195 MATFile * mat_file = matOpen(path.c_str(), "w");
196 if(mat_file == NULL)
197 {
198 fprintf(stderr,"Error opening file %s\n",path.c_str());
199 return false;
200 }
201 assert(names.size() == data.size());
202 // loop over names and data
203 for(int i = 0;i < (int)names.size(); i++)
204 {
205 // Put variable as LOCAL variable
206 int status = matPutVariable(mat_file,names[i].c_str(), data[i]);
207 if(status != 0)
208 {
209 cerr<<"^MatlabWorkspace::save Error: matPutVariable ("<<names[i]<<
210 ") failed"<<endl;
211 return false;
212 }
213 }
214 if(matClose(mat_file) != 0)
215 {
216 fprintf(stderr,"Error closing file %s\n",path.c_str());
217 return false;
218 }
219 return true;
220}
221
222inline bool igl::matlab::MatlabWorkspace::read(const std::string & path)
223{
224 using namespace std;
225
226 MATFile * mat_file;
227
228 mat_file = matOpen(path.c_str(), "r");
229 if (mat_file == NULL)
230 {
231 cerr<<"Error: failed to open "<<path<<endl;
232 return false;
233 }
234
235 int ndir;
236 const char ** dir = (const char **)matGetDir(mat_file, &ndir);
237 if (dir == NULL) {
238 cerr<<"Error reading directory of file "<< path<<endl;
239 return false;
240 }
241 mxFree(dir);
242
243 // Must close and reopen
244 if(matClose(mat_file) != 0)
245 {
246 cerr<<"Error: failed to close file "<<path<<endl;
247 return false;
248 }
249 mat_file = matOpen(path.c_str(), "r");
250 if (mat_file == NULL)
251 {
252 cerr<<"Error: failed to open "<<path<<endl;
253 return false;
254 }
255
256
257 /* Read in each array. */
258 for (int i=0; i<ndir; i++)
259 {
260 const char * name;
261 mxArray * mx_data = matGetNextVariable(mat_file, &name);
262 if (mx_data == NULL)
263 {
264 cerr<<"Error: matGetNextVariable failed in "<<path<<endl;
265 return false;
266 }
267 const int dims = mxGetNumberOfDimensions(mx_data);
268 assert(dims == 2);
269 if(dims != 2)
270 {
271 fprintf(stderr,"Variable '%s' has %d ≠ 2 dimensions. Skipping\n",
272 name,dims);
273 mxDestroyArray(mx_data);
274 continue;
275 }
276 // don't destroy
277 names.push_back(name);
278 data.push_back(mx_data);
279 }
280
281 if(matClose(mat_file) != 0)
282 {
283 cerr<<"Error: failed to close file "<<path<<endl;
284 return false;
285 }
286
287 return true;
288}
289
290// Treat everything as a double
291template <typename DerivedM>
293 const Eigen::PlainObjectBase<DerivedM>& M,
294 const std::string & name)
295{
296 using namespace std;
297 const int m = M.rows();
298 const int n = M.cols();
299 mxArray * mx_data = mxCreateDoubleMatrix(m,n,mxREAL);
300 data.push_back(mx_data);
301 names.push_back(name);
302 // Copy data immediately
303 // Use Eigen's map and cast to copy
304 Eigen::Map< Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic> >
305 map(mxGetPr(mx_data),m,n);
306 map = M.template cast<double>();
307 return *this;
308}
309
310// Treat everything as a double
311template <typename MT>
313 const Eigen::SparseMatrix<MT>& M,
314 const std::string & name)
315{
316 using namespace std;
317 const int m = M.rows();
318 const int n = M.cols();
319 // THIS WILL NOT WORK FOR ROW-MAJOR
320 assert(n==M.outerSize());
321 const int nzmax = M.nonZeros();
322 mxArray * mx_data = mxCreateSparse(m, n, nzmax, mxREAL);
323 data.push_back(mx_data);
324 names.push_back(name);
325 // Copy data immediately
326 double * pr = mxGetPr(mx_data);
327 mwIndex * ir = mxGetIr(mx_data);
328 mwIndex * jc = mxGetJc(mx_data);
329
330 // Iterate over outside
331 int k = 0;
332 for(int j=0; j<M.outerSize();j++)
333 {
334 jc[j] = k;
335 // Iterate over inside
336 for(typename Eigen::SparseMatrix<MT>::InnerIterator it (M,j); it; ++it)
337 {
338 pr[k] = it.value();
339 ir[k] = it.row();
340 k++;
341 }
342 }
343 jc[M.outerSize()] = k;
344
345 return *this;
346}
347
348template <typename ScalarM>
350 const std::vector<std::vector<ScalarM> > & vM,
351 const std::string & name)
352{
353 Eigen::MatrixXd M;
354 list_to_matrix(vM,M);
355 return this->save(M,name);
356}
357
358template <typename ScalarV>
360 const std::vector<ScalarV> & vV,
361 const std::string & name)
362{
363 Eigen::MatrixXd V;
364 list_to_matrix(vV,V);
365 return this->save(V,name);
366}
367
368template <typename Q>
370 const Eigen::Quaternion<Q> & q,
371 const std::string & name)
372{
373 Eigen::Matrix<Q,1,4> qm;
374 qm(0,0) = q.w();
375 qm(0,1) = q.x();
376 qm(0,2) = q.y();
377 qm(0,3) = q.z();
378 return save(qm,name);
379}
380
382 const double d,
383 const std::string & name)
384{
385 Eigen::VectorXd v(1);
386 v(0) = d;
387 return save(v,name);
388}
389
390template <typename DerivedM>
393 const Eigen::DenseBase<DerivedM>& M,
394 const std::string & name)
395{
396 DerivedM Mp1 = M;
397 Mp1.array() += 1;
398 return this->save(Mp1,name);
399}
400
401template <typename ScalarM>
403 const std::vector<std::vector<ScalarM> > & vM,
404 const std::string & name)
405{
406 Eigen::MatrixXd M;
407 list_to_matrix(vM,M);
408 return this->save_index(M,name);
409}
410
411template <typename ScalarV>
413 const std::vector<ScalarV> & vV,
414 const std::string & name)
415{
416 Eigen::MatrixXd V;
417 list_to_matrix(vV,V);
418 return this->save_index(V,name);
419}
420
421template <typename DerivedM>
423 const std::string & name,
424 Eigen::PlainObjectBase<DerivedM>& M)
425{
426 using namespace std;
427 const int i = std::find(names.begin(), names.end(), name)-names.begin();
428 if(i>=(int)names.size())
429 {
430 return false;
431 }
432 assert(i<=(int)data.size());
433 mxArray * mx_data = data[i];
434 assert(!mxIsSparse(mx_data));
435 assert(mxGetNumberOfDimensions(mx_data) == 2);
436 //cout<<name<<": "<<mxGetM(mx_data)<<" "<<mxGetN(mx_data)<<endl;
437 const int m = mxGetM(mx_data);
438 const int n = mxGetN(mx_data);
439 // Handle vectors: in the sense that anything found becomes a column vector,
440 // whether it was column vector, row vector or matrix
441 if(DerivedM::IsVectorAtCompileTime)
442 {
443 assert(m==1 || n==1 || (m==0 && n==0));
444 M.resize(m*n,1);
445 }else
446 {
447 M.resize(m,n);
448 }
449 assert(mxGetNumberOfElements(mx_data) == M.size());
450 // Use Eigen's map and cast to copy
451 M = Eigen::Map< Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic> >
452 (mxGetPr(mx_data),M.rows(),M.cols()).cast<typename DerivedM::Scalar>();
453 return true;
454}
455
456template <typename MT>
458 const std::string & name,
459 Eigen::SparseMatrix<MT>& M)
460{
461 using namespace std;
462 using namespace Eigen;
463 const int i = std::find(names.begin(), names.end(), name)-names.begin();
464 if(i>=(int)names.size())
465 {
466 return false;
467 }
468 assert(i<=(int)data.size());
469 mxArray * mx_data = data[i];
470 // Handle boring case where matrix is actually an empty dense matrix
471 if(mxGetNumberOfElements(mx_data) == 0)
472 {
473 M.resize(0,0);
474 return true;
475 }
476 assert(mxIsSparse(mx_data));
477 assert(mxGetNumberOfDimensions(mx_data) == 2);
478 //cout<<name<<": "<<mxGetM(mx_data)<<" "<<mxGetN(mx_data)<<endl;
479 const int m = mxGetM(mx_data);
480 const int n = mxGetN(mx_data);
481 // TODO: It should be possible to directly load the data into the sparse
482 // matrix without going through the triplets
483 // Copy data immediately
484 double * pr = mxGetPr(mx_data);
485 mwIndex * ir = mxGetIr(mx_data);
486 mwIndex * jc = mxGetJc(mx_data);
487 vector<Triplet<MT> > MIJV;
488 const int nnz = mxGetNzmax(mx_data);
489 MIJV.reserve(nnz);
490 // Iterate over outside
491 int k = 0;
492 for(int j=0; j<n;j++)
493 {
494 // Iterate over inside
495 while(k<(int)jc[j+1])
496 {
497 //cout<<ir[k]<<" "<<j<<" "<<pr[k]<<endl;
498 assert((int)ir[k]<m);
499 assert((int)j<n);
500 MIJV.push_back(Triplet<MT >(ir[k],j,pr[k]));
501 k++;
502 }
503 }
504 M.resize(m,n);
505 M.setFromTriplets(MIJV.begin(),MIJV.end());
506
507 return true;
508}
509
511 const std::string & name,
512 int & v)
513{
514 using namespace std;
515 const int i = std::find(names.begin(), names.end(), name)-names.begin();
516 if(i>=(int)names.size())
517 {
518 return false;
519 }
520 assert(i<=(int)data.size());
521 mxArray * mx_data = data[i];
522 assert(!mxIsSparse(mx_data));
523 assert(mxGetNumberOfDimensions(mx_data) == 2);
524 //cout<<name<<": "<<mxGetM(mx_data)<<" "<<mxGetN(mx_data)<<endl;
525 assert(mxGetNumberOfElements(mx_data) == 1);
526 copy(
527 mxGetPr(mx_data),
528 mxGetPr(mx_data)+mxGetNumberOfElements(mx_data),
529 &v);
530 return true;
531}
532
534 const std::string & name,
535 double & d)
536{
537 using namespace std;
538 const int i = std::find(names.begin(), names.end(), name)-names.begin();
539 if(i>=(int)names.size())
540 {
541 return false;
542 }
543 assert(i<=(int)data.size());
544 mxArray * mx_data = data[i];
545 assert(!mxIsSparse(mx_data));
546 assert(mxGetNumberOfDimensions(mx_data) == 2);
547 //cout<<name<<": "<<mxGetM(mx_data)<<" "<<mxGetN(mx_data)<<endl;
548 assert(mxGetNumberOfElements(mx_data) == 1);
549 copy(
550 mxGetPr(mx_data),
551 mxGetPr(mx_data)+mxGetNumberOfElements(mx_data),
552 &d);
553 return true;
554}
555
556template <typename DerivedM>
558 const std::string & name,
559 Eigen::PlainObjectBase<DerivedM>& M)
560{
561 if(!find(name,M))
562 {
563 return false;
564 }
565 M.array() -= 1;
566 return true;
567}
568
569
570//template <typename Data>
571//bool igl::matlab::MatlabWorkspace::save(const Data & M, const std::string & name)
572//{
573// using namespace std;
574// // If I don't know the type then I can't save it
575// cerr<<"^MatlabWorkspace::save Error: Unknown data type. "<<
576// name<<" not saved."<<endl;
577// return false;
578//}
579
580#endif
581
Class which contains data of a matlab workspace which can be written to a .mat file and loaded from m...
Definition MatlabWorkspace.h:35
MatlabWorkspace & save_index(const Eigen::DenseBase< DerivedM > &M, const std::string &name)
Same as save() but adds 1 to each element, useful for saving "index" matrices like lists of faces or ...
MatlabWorkspace & save(const Eigen::PlainObjectBase< DerivedM > &M, const std::string &name)
Assign data to a variable name in the workspace.
MatlabWorkspace & save(const std::vector< std::vector< ScalarM > > &vM, const std::string &name)
This is an overloaded member function, provided for convenience. It differs from the above function o...
MatlabWorkspace & save_index(const std::vector< ScalarV > &vV, const std::string &name)
This is an overloaded member function, provided for convenience. It differs from the above function o...
bool write(const std::string &path) const
Save current list of variables.
Definition MatlabWorkspace.h:192
bool find(const std::string &name, Eigen::PlainObjectBase< DerivedM > &M)
Find a certain matrix by name.
Definition MatlabWorkspace.h:422
MatlabWorkspace & save(const std::vector< ScalarV > &vV, const std::string &name)
This is an overloaded member function, provided for convenience. It differs from the above function o...
bool read(const std::string &path)
Load list of variables from .mat file.
Definition MatlabWorkspace.h:222
MatlabWorkspace()
Definition MatlabWorkspace.h:173
MatlabWorkspace & save(const Eigen::SparseMatrix< MT > &M, const std::string &name)
This is an overloaded member function, provided for convenience. It differs from the above function o...
~MatlabWorkspace()
Definition MatlabWorkspace.h:179
bool find_index(const std::string &name, Eigen::PlainObjectBase< DerivedM > &M)
Subtracts 1 from all entries.
Definition MatlabWorkspace.h:557
MatlabWorkspace & save_index(const std::vector< std::vector< ScalarM > > &vM, const std::string &name)
This is an overloaded member function, provided for convenience. It differs from the above function o...
MatlabWorkspace & save(const Eigen::Quaternion< Q > &q, const std::string &name)
void clear()
Clear names and data of variables in workspace.
Definition MatlabWorkspace.h:185
Definition AABB.h:17
void for_each(const Eigen::SparseMatrix< AType > &A, const Func &func)
FOR_EACH Call a given function for each non-zero (i.e., explicit value might actually be ==0) in a Sp...
Definition for_each.h:31
bool list_to_matrix(const std::vector< std::vector< T > > &V, Eigen::PlainObjectBase< Derived > &M)
Convert a list (std::vector) of row vectors of the same length to a matrix.
void find(const Eigen::SparseMatrix< T > &X, Eigen::DenseBase< DerivedI > &I, Eigen::DenseBase< DerivedJ > &J, Eigen::DenseBase< DerivedV > &V)
Find the non-zero entries and there respective indices in a sparse matrix.