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::MatrixBase<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 MATFile * mat_file = matOpen(path.c_str(), "w");
195 if(mat_file == NULL)
196 {
197 fprintf(stderr,"Error opening file %s\n",path.c_str());
198 return false;
199 }
200 assert(names.size() == data.size());
201 // loop over names and data
202 for(int i = 0;i < (int)names.size(); i++)
203 {
204 // Put variable as LOCAL variable
205 int status = matPutVariable(mat_file,names[i].c_str(), data[i]);
206 if(status != 0)
207 {
208 std::cerr<<"^MatlabWorkspace::save Error: matPutVariable ("<<names[i]<<
209 ") failed"<<std::endl;
210 return false;
211 }
212 }
213 if(matClose(mat_file) != 0)
214 {
215 fprintf(stderr,"Error closing file %s\n",path.c_str());
216 return false;
217 }
218 return true;
219}
220
221inline bool igl::matlab::MatlabWorkspace::read(const std::string & path)
222{
223
224 MATFile * mat_file;
225
226 mat_file = matOpen(path.c_str(), "r");
227 if (mat_file == NULL)
228 {
229 std::cerr<<"Error: failed to open "<<path<<std::endl;
230 return false;
231 }
232
233 int ndir;
234 const char ** dir = (const char **)matGetDir(mat_file, &ndir);
235 if (dir == NULL) {
236 std::cerr<<"Error reading directory of file "<< path<<std::endl;
237 return false;
238 }
239 mxFree(dir);
240
241 // Must close and reopen
242 if(matClose(mat_file) != 0)
243 {
244 std::cerr<<"Error: failed to close file "<<path<<std::endl;
245 return false;
246 }
247 mat_file = matOpen(path.c_str(), "r");
248 if (mat_file == NULL)
249 {
250 std::cerr<<"Error: failed to open "<<path<<std::endl;
251 return false;
252 }
253
254
255 /* Read in each array. */
256 for (int i=0; i<ndir; i++)
257 {
258 const char * name;
259 mxArray * mx_data = matGetNextVariable(mat_file, &name);
260 if (mx_data == NULL)
261 {
262 std::cerr<<"Error: matGetNextVariable failed in "<<path<<std::endl;
263 return false;
264 }
265 const int dims = mxGetNumberOfDimensions(mx_data);
266 assert(dims == 2);
267 if(dims != 2)
268 {
269 fprintf(stderr,"Variable '%s' has %d ≠ 2 dimensions. Skipping\n",
270 name,dims);
271 mxDestroyArray(mx_data);
272 continue;
273 }
274 // don't destroy
275 names.push_back(name);
276 data.push_back(mx_data);
277 }
278
279 if(matClose(mat_file) != 0)
280 {
281 std::cerr<<"Error: failed to close file "<<path<<std::endl;
282 return false;
283 }
284
285 return true;
286}
287
288// Treat everything as a double
289template <typename DerivedM>
291 const Eigen::MatrixBase<DerivedM>& M,
292 const std::string & name)
293{
294 const int m = M.rows();
295 const int n = M.cols();
296 mxArray * mx_data = mxCreateDoubleMatrix(m,n,mxREAL);
297 data.push_back(mx_data);
298 names.push_back(name);
299 // Copy data immediately
300 // Use Eigen's map and cast to copy
301 Eigen::Map< Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic> >
302 map(mxGetPr(mx_data),m,n);
303 map = M.template cast<double>();
304 return *this;
305}
306
307// Treat everything as a double
308template <typename MT>
310 const Eigen::SparseMatrix<MT>& M,
311 const std::string & name)
312{
313 const int m = M.rows();
314 const int n = M.cols();
315 // THIS WILL NOT WORK FOR ROW-MAJOR
316 assert(n==M.outerSize());
317 const int nzmax = M.nonZeros();
318 mxArray * mx_data = mxCreateSparse(m, n, nzmax, mxREAL);
319 data.push_back(mx_data);
320 names.push_back(name);
321 // Copy data immediately
322 double * pr = mxGetPr(mx_data);
323 mwIndex * ir = mxGetIr(mx_data);
324 mwIndex * jc = mxGetJc(mx_data);
325
326 // Iterate over outside
327 int k = 0;
328 for(int j=0; j<M.outerSize();j++)
329 {
330 jc[j] = k;
331 // Iterate over inside
332 for(typename Eigen::SparseMatrix<MT>::InnerIterator it (M,j); it; ++it)
333 {
334 pr[k] = it.value();
335 ir[k] = it.row();
336 k++;
337 }
338 }
339 jc[M.outerSize()] = k;
340
341 return *this;
342}
343
344template <typename ScalarM>
346 const std::vector<std::vector<ScalarM> > & vM,
347 const std::string & name)
348{
349 Eigen::MatrixXd M;
350 list_to_matrix(vM,M);
351 return this->save(M,name);
352}
353
354template <typename ScalarV>
356 const std::vector<ScalarV> & vV,
357 const std::string & name)
358{
359 Eigen::MatrixXd V;
360 list_to_matrix(vV,V);
361 return this->save(V,name);
362}
363
364template <typename Q>
366 const Eigen::Quaternion<Q> & q,
367 const std::string & name)
368{
369 Eigen::Matrix<Q,1,4> qm;
370 qm(0,0) = q.w();
371 qm(0,1) = q.x();
372 qm(0,2) = q.y();
373 qm(0,3) = q.z();
374 return save(qm,name);
375}
376
378 const double d,
379 const std::string & name)
380{
381 Eigen::VectorXd v(1);
382 v(0) = d;
383 return save(v,name);
384}
385
386template <typename DerivedM>
389 const Eigen::DenseBase<DerivedM>& M,
390 const std::string & name)
391{
392 DerivedM Mp1 = M;
393 Mp1.array() += 1;
394 return this->save(Mp1,name);
395}
396
397template <typename ScalarM>
399 const std::vector<std::vector<ScalarM> > & vM,
400 const std::string & name)
401{
402 Eigen::MatrixXd M;
403 list_to_matrix(vM,M);
404 return this->save_index(M,name);
405}
406
407template <typename ScalarV>
409 const std::vector<ScalarV> & vV,
410 const std::string & name)
411{
412 Eigen::MatrixXd V;
413 list_to_matrix(vV,V);
414 return this->save_index(V,name);
415}
416
417template <typename DerivedM>
419 const std::string & name,
420 Eigen::PlainObjectBase<DerivedM>& M)
421{
422 const int i = std::find(names.begin(), names.end(), name)-names.begin();
423 if(i>=(int)names.size())
424 {
425 return false;
426 }
427 assert(i<=(int)data.size());
428 mxArray * mx_data = data[i];
429 assert(!mxIsSparse(mx_data));
430 assert(mxGetNumberOfDimensions(mx_data) == 2);
431 //cout<<name<<": "<<mxGetM(mx_data)<<" "<<mxGetN(mx_data)<<endl;
432 const int m = mxGetM(mx_data);
433 const int n = mxGetN(mx_data);
434 // Handle vectors: in the sense that anything found becomes a column vector,
435 // whether it was column vector, row vector or matrix
436 if(DerivedM::IsVectorAtCompileTime)
437 {
438 assert(m==1 || n==1 || (m==0 && n==0));
439 M.resize(m*n,1);
440 }else
441 {
442 M.resize(m,n);
443 }
444 assert(mxGetNumberOfElements(mx_data) == M.size());
445 // Use Eigen's map and cast to copy
446 M = Eigen::Map< Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic> >
447 (mxGetPr(mx_data),M.rows(),M.cols()).cast<typename DerivedM::Scalar>();
448 return true;
449}
450
451template <typename MT>
453 const std::string & name,
454 Eigen::SparseMatrix<MT>& M)
455{
456 const int i = std::find(names.begin(), names.end(), name)-names.begin();
457 if(i>=(int)names.size())
458 {
459 return false;
460 }
461 assert(i<=(int)data.size());
462 mxArray * mx_data = data[i];
463 // Handle boring case where matrix is actually an empty dense matrix
464 if(mxGetNumberOfElements(mx_data) == 0)
465 {
466 M.resize(0,0);
467 return true;
468 }
469 assert(mxIsSparse(mx_data));
470 assert(mxGetNumberOfDimensions(mx_data) == 2);
471 //cout<<name<<": "<<mxGetM(mx_data)<<" "<<mxGetN(mx_data)<<endl;
472 const int m = mxGetM(mx_data);
473 const int n = mxGetN(mx_data);
474 // TODO: It should be possible to directly load the data into the sparse
475 // matrix without going through the triplets
476 // Copy data immediately
477 double * pr = mxGetPr(mx_data);
478 mwIndex * ir = mxGetIr(mx_data);
479 mwIndex * jc = mxGetJc(mx_data);
480 vector<Eigen::Triplet<MT> > MIJV;
481 const int nnz = mxGetNzmax(mx_data);
482 MIJV.reserve(nnz);
483 // Iterate over outside
484 int k = 0;
485 for(int j=0; j<n;j++)
486 {
487 // Iterate over inside
488 while(k<(int)jc[j+1])
489 {
490 //cout<<ir[k]<<" "<<j<<" "<<pr[k]<<endl;
491 assert((int)ir[k]<m);
492 assert((int)j<n);
493 MIJV.push_back(Eigen::Triplet<MT >(ir[k],j,pr[k]));
494 k++;
495 }
496 }
497 M.resize(m,n);
498 M.setFromTriplets(MIJV.begin(),MIJV.end());
499
500 return true;
501}
502
504 const std::string & name,
505 int & v)
506{
507 const int i = std::find(names.begin(), names.end(), name)-names.begin();
508 if(i>=(int)names.size())
509 {
510 return false;
511 }
512 assert(i<=(int)data.size());
513 mxArray * mx_data = data[i];
514 assert(!mxIsSparse(mx_data));
515 assert(mxGetNumberOfDimensions(mx_data) == 2);
516 //cout<<name<<": "<<mxGetM(mx_data)<<" "<<mxGetN(mx_data)<<endl;
517 assert(mxGetNumberOfElements(mx_data) == 1);
518 copy(
519 mxGetPr(mx_data),
520 mxGetPr(mx_data)+mxGetNumberOfElements(mx_data),
521 &v);
522 return true;
523}
524
526 const std::string & name,
527 double & d)
528{
529 const int i = std::find(names.begin(), names.end(), name)-names.begin();
530 if(i>=(int)names.size())
531 {
532 return false;
533 }
534 assert(i<=(int)data.size());
535 mxArray * mx_data = data[i];
536 assert(!mxIsSparse(mx_data));
537 assert(mxGetNumberOfDimensions(mx_data) == 2);
538 //cout<<name<<": "<<mxGetM(mx_data)<<" "<<mxGetN(mx_data)<<endl;
539 assert(mxGetNumberOfElements(mx_data) == 1);
540 copy(
541 mxGetPr(mx_data),
542 mxGetPr(mx_data)+mxGetNumberOfElements(mx_data),
543 &d);
544 return true;
545}
546
547template <typename DerivedM>
549 const std::string & name,
550 Eigen::PlainObjectBase<DerivedM>& M)
551{
552 if(!find(name,M))
553 {
554 return false;
555 }
556 M.array() -= 1;
557 return true;
558}
559
560
561//template <typename Data>
562//bool igl::matlab::MatlabWorkspace::save(const Data & M, const std::string & name)
563//{
564// using namespace std;
565// // If I don't know the type then I can't save it
566// std::cerr<<"^MatlabWorkspace::save Error: Unknown data type. "<<
567// name<<" not saved."<<std::endl;
568// return false;
569//}
570
571#endif
572
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 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:418
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:221
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:548
MatlabWorkspace & save(const Eigen::MatrixBase< DerivedM > &M, const std::string &name)
Assign data to a variable name in the workspace.
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 matlabinterface.h:38
Definition AABB.h:18
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.