Drake
drakeMexUtil.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <mex.h>
4 
5 #include <vector>
6 #include <Eigen/Core>
7 #include <Eigen/Sparse>
8 #include "drake/util/TrigPoly.h"
9 /*
10  * NOTE: include AutoDiff AFTER TrigPoly.h.
11  * TrigPoly.h includes LLDT.h via Eigenvalues, PolynomialSolver, and our
12  * Polynomial.h
13  * MSVC versions up to and including 2013 have trouble with the rankUpdate
14  * method in LLDT.h
15  * For some reason there is a bad interaction with AutoDiff, even though LLDT.h
16  * still gets included if TrigPoly.h is included before AutoDiff.
17  * See http://eigen.tuxfamily.org/bz/show_bug.cgi?id=1057
18  */
19 #include <unsupported/Eigen/AutoDiff>
20 #include <Eigen/src/SparseCore/SparseMatrix.h>
21 
22 #include "drake/math/autodiff.h"
24 
28 
29 #undef DLLEXPORT
30 #if defined(WIN32) || defined(WIN64)
31 #if defined(drakeMexUtil_EXPORTS)
32 #define DLLEXPORT __declspec(dllexport)
33 #else
34 #define DLLEXPORT __declspec(dllimport)
35 #endif
36 #else
37 #define DLLEXPORT
38 #endif
39 
40 DLLEXPORT bool isa(const mxArray* mxa, const char* class_str);
41 DLLEXPORT bool mexCallMATLABsafe(int nlhs, mxArray* plhs[], int nrhs,
42  mxArray* prhs[], const char* filename);
43 
44 DLLEXPORT double* mxGetPrSafe(const mxArray* pobj);
45 
46 DLLEXPORT mxArray* mxGetPropertySafe(const mxArray* array,
47  std::string const& field_name);
48 DLLEXPORT mxArray* mxGetFieldSafe(const mxArray* array,
49  std::string const& field_name);
50 DLLEXPORT mxArray* mxGetPropertySafe(const mxArray* array, size_t index,
51  std::string const& field_name);
52 DLLEXPORT mxArray* mxGetFieldSafe(const mxArray* array, size_t index,
53  std::string const& field_name);
54 DLLEXPORT void mxSetFieldSafe(mxArray* array, size_t index,
55  std::string const& fieldname, mxArray* data);
56 DLLEXPORT mxArray* mxGetFieldOrPropertySafe(const mxArray* array,
57  std::string const& field_name);
58 DLLEXPORT mxArray* mxGetFieldOrPropertySafe(const mxArray* array, size_t index,
59  std::string const& field_name);
60 
61 // Mex pointers shared through matlab
62 // Note: the same mex function which calls this method will be called with the
63 // syntax mexFunction(drake_mex_ptr) as the destructor
64 
66  void* ptr, const std::string& name = "", int type_id = -1,
67  int num_additional_inputs = 0,
68  mxArray* delete_fcn_additional_inputs[] = NULL,
69  const std::string& subclass_name = "",
70  const std::string& mex_function_name_prefix = ""); // increments lock count
71 DLLEXPORT void* getDrakeMexPointer(const mxArray* mx);
72 
73 template <typename Derived>
74 inline void destroyDrakeMexPointer(const mxArray* mx) {
75  if (!isa(mx, "DrakeMexPointer"))
76  mexErrMsgIdAndTxt("Drake:destroyDrakeMexPointer:BadInputs",
77  "This object is not a DrakeMexPointer. Delete failed.");
78 
79  Derived typed_ptr = (Derived)getDrakeMexPointer(mx);
80 
81  // mexPrintf("deleting drake mex pointer\n");
82  delete typed_ptr;
83  mexUnlock(); // decrement lock count
84 
85  // mexPrintf(mexIsLocked() ? "mex file is locked\n" : "mex file is
86  // unlocked\n");
87 }
88 
89 template <typename Derived>
90 DLLEXPORT mxArray* eigenToMatlabSparse(Eigen::MatrixBase<Derived> const& M,
91  int& num_non_zero);
92 
93 template <typename DerivedA>
94 mxArray* eigenToMatlab(const DerivedA& m) {
95  // this avoids zero initialization that would occur using mxCreateDoubleMatrix
96  // with nonzero dimensions.
97  // see https://classes.soe.ucsc.edu/ee264/Fall11/cmex.pdf, page 8
98  mxArray* pm = mxCreateDoubleMatrix(0, 0, mxREAL);
99  int rows = static_cast<int>(m.rows());
100  int cols = static_cast<int>(m.cols());
101  int numel = rows * cols;
102  mxSetM(pm, rows);
103  mxSetN(pm, cols);
104  if (numel) mxSetData(pm, mxMalloc(sizeof(double) * numel));
105  memcpy(mxGetPr(pm), m.data(), sizeof(double) * numel);
106  return pm;
107 }
108 
109 template <int RowsAtCompileTime, int ColsAtCompileTime>
110 Eigen::Matrix<double, RowsAtCompileTime, ColsAtCompileTime> matlabToEigen(
111  const mxArray* matlab_array) {
112  const mwSize* size_array = mxGetDimensions(matlab_array);
113  Eigen::Matrix<double, RowsAtCompileTime, ColsAtCompileTime> ret(
114  size_array[0], size_array[1]);
115  memcpy(ret.data(), mxGetPr(matlab_array), sizeof(double) * ret.size());
116  return ret;
117 }
118 
119 template<int Rows, int Cols>
120 Eigen::Map<const Eigen::Matrix<double, Rows, Cols>> matlabToEigenMap(
121  const mxArray *mex) {
122  using namespace Eigen;
123  using namespace std;
124 
125  Index rows, cols; // at runtime
126  if (mxIsEmpty(mex)) {
127  // be lenient when it comes to dimensions in the empty input case
128  if (Rows == Dynamic && Cols == Dynamic) {
129  // if both dimensions are dynamic, then follow the dimensions of
130  // the Matlab matrix
131  rows = mxGetM(mex);
132  cols = mxGetN(mex);
133  } else {
134  // if only one dimension is dynamic, use the known dimension at
135  // compile time and set the other dimension to zero
136  rows = Rows == Dynamic ? 0 : Rows;
137  cols = Cols == Dynamic ? 0 : Cols;
138  }
139  } else {
140  // the non-empty case
141  rows = Rows == Dynamic ? mxGetM(mex) : Rows;
142  cols = Cols == Dynamic ? mxGetN(mex) : Cols;
143  }
144 
145  if (Rows != Dynamic && Rows != rows) {
146  ostringstream stream;
147  stream << "Error converting Matlab matrix. Expected " << Rows
148  << " rows, but got " << mxGetM(mex) << ".";
149  throw runtime_error(stream.str().c_str());
150  }
151 
152  if (Cols != Dynamic && Cols != cols) {
153  ostringstream stream;
154  stream << "Error converting Matlab matrix. Expected " << Cols
155  << " cols, but got " << mxGetN(mex) << ".";
156  throw runtime_error(stream.str().c_str());
157  }
158 
159  double *data = rows * cols == 0 ? nullptr : mxGetPrSafe(mex);
160  return Map<const Matrix<double, Rows, Cols>>(data, rows, cols);
161 }
162 
163 DLLEXPORT Eigen::SparseMatrix<double> matlabToEigenSparse(const mxArray* mex);
164 
165 DLLEXPORT std::string mxGetStdString(const mxArray* array);
166 DLLEXPORT std::vector<std::string> mxGetVectorOfStdStrings(
167  const mxArray* array);
168 
169 template <typename Scalar>
170 mxArray* stdVectorToMatlab(const std::vector<Scalar>& vec) {
171  mxArray* pm = mxCreateDoubleMatrix(static_cast<int>(vec.size()), 1, mxREAL);
172  for (int i = 0; i < static_cast<int>(vec.size()); i++) {
173  mxGetPr(pm)[i] = (double)vec[i];
174  }
175  return pm;
176 }
177 DLLEXPORT mxArray* stdStringToMatlab(const std::string& str);
179  const std::vector<std::string>& strs);
180 
181 DLLEXPORT void sizecheck(const mxArray* mat, mwSize M, mwSize N);
182 
183 template <size_t Rows, size_t Cols>
184 void matlabToCArrayOfArrays(const mxArray* source,
185  double(&destination)[Rows][Cols]) {
186  // Matlab arrays come in as column-major data. The format used in e.g. LCM
187  // messages is an array of arrays.
188  // from http://stackoverflow.com/a/17569578/2228557
189  sizecheck(source, static_cast<int>(Rows), static_cast<int>(Cols));
190  double* source_data = mxGetPr(source);
191  for (size_t row = 0; row < Rows; ++row) {
192  for (size_t col = 0; col < Cols; ++col) {
193  destination[row][col] = source_data[row + col * Rows];
194  }
195  }
196 }
197 
198 DLLEXPORT mwSize sub2ind(mwSize ndims, const mwSize* dims, const mwSize* sub);
199 
200 template <typename T>
201 const std::vector<T> matlabToStdVector(const mxArray* in);
202 
203 DLLEXPORT Eigen::Matrix<Polynomiald, Eigen::Dynamic, Eigen::Dynamic>
204 msspolyToEigen(const mxArray* msspoly);
205 
206 template <int _Rows, int _Cols>
207 mxArray* eigenToMSSPoly(const Eigen::Matrix<Polynomiald, _Rows, _Cols>& poly) {
208  size_t num_monomials = 0, max_terms = 0;
209  for (int i = 0; i < poly.size(); i++) {
210  auto monomials = poly(i).getMonomials();
211  num_monomials += monomials.size();
212  for (std::vector<Polynomiald::Monomial>::const_iterator iter =
213  monomials.begin();
214  iter != monomials.end(); iter++) {
215  if (iter->terms.size() > max_terms) max_terms = iter->terms.size();
216  }
217  }
218 
219  Eigen::Matrix<double, 1, 2> dim;
220  dim << static_cast<double>(poly.rows()), static_cast<double>(poly.cols());
221  Eigen::MatrixXd sub(num_monomials, 2);
222  Eigen::MatrixXd var = Eigen::MatrixXd::Zero(num_monomials, max_terms);
223  Eigen::MatrixXd pow = Eigen::MatrixXd::Zero(num_monomials, max_terms);
224  Eigen::VectorXd coeff(num_monomials);
225 
226  int index = 0;
227  for (int i = 0; i < poly.rows(); i++) {
228  for (int j = 0; j < poly.cols(); j++) {
229  auto monomials = poly(i, j).getMonomials();
230  for (std::vector<Polynomiald::Monomial>::const_iterator iter =
231  monomials.begin();
232  iter != monomials.end(); iter++) {
233  sub(index, 0) = i + 1;
234  sub(index, 1) = j + 1;
235  for (int k = 0; k < iter->terms.size(); k++) {
236  var(index, k) = (double)iter->terms[k].var;
237  pow(index, k) = (double)iter->terms[k].power;
238  }
239  coeff(index) = iter->coefficient;
240  index++;
241  }
242  }
243  }
244 
245  mxArray* plhs[1];
246  mxArray* prhs[5];
247  prhs[0] = eigenToMatlab(dim);
248  prhs[1] = eigenToMatlab(sub);
249  prhs[2] = eigenToMatlab(var);
250  prhs[3] = eigenToMatlab(pow);
251  prhs[4] = eigenToMatlab(coeff);
252  mexCallMATLABsafe(1, plhs, 5, prhs, "msspoly");
253  return plhs[0];
254 }
255 
256 DLLEXPORT Eigen::Matrix<TrigPolyd, Eigen::Dynamic, Eigen::Dynamic>
257 trigPolyToEigen(const mxArray* trigpoly);
258 
259 template <int _Rows, int _Cols>
261  const Eigen::Matrix<TrigPolyd, _Rows, _Cols>& trigpoly_mat) {
262  Eigen::Matrix<Polynomiald, Eigen::Dynamic, Eigen::Dynamic> poly_mat(
263  trigpoly_mat.rows(), trigpoly_mat.cols());
264  TrigPolyd::SinCosMap sin_cos_map;
265  for (int i = 0; i < trigpoly_mat.size(); i++) {
266  const TrigPolyd::SinCosMap& sc = trigpoly_mat(i).getSinCosMap();
267  sin_cos_map.insert(sc.begin(), sc.end());
268  poly_mat(i) = trigpoly_mat(i).getPolynomial();
269  }
270 
271  if (sin_cos_map
272  .empty()) // then just return the msspoly. what else can i do?
273  return eigenToMSSPoly<Eigen::Dynamic, Eigen::Dynamic>(poly_mat);
274 
275  // construct the equivalent of the sin/cos map
276  // (do I need to worry about them possibly being out of order?)
277  Eigen::Matrix<Polynomiald, Eigen::Dynamic, 1> q(sin_cos_map.size()),
278  s(sin_cos_map.size()), c(sin_cos_map.size());
279  int i = 0;
280  for (TrigPolyd::SinCosMap::iterator iter = sin_cos_map.begin();
281  iter != sin_cos_map.end(); iter++) {
282  q(i) = Polynomiald(1.0, iter->first);
283  s(i) = Polynomiald(1.0, iter->second.s);
284  c(i) = Polynomiald(1.0, iter->second.c);
285  i++;
286  }
287 
288  mxArray* plhs[1];
289  mxArray* prhs[3];
290  prhs[0] = eigenToMSSPoly<Eigen::Dynamic, 1>(q);
291  prhs[1] = eigenToMSSPoly<Eigen::Dynamic, 1>(s);
292  prhs[2] = eigenToMSSPoly<Eigen::Dynamic, 1>(c);
293  mexCallMATLABsafe(1, plhs, 3, prhs, "TrigPoly");
294 
295  mxSetProperty(plhs[0], 0, "p",
296  eigenToMSSPoly<Eigen::Dynamic, Eigen::Dynamic>(poly_mat));
297 
298  return plhs[0];
299 }
300 
301 template <int Rows, int Cols>
302 Eigen::Matrix<Eigen::AutoDiffScalar<Eigen::VectorXd>, Rows, Cols>
303 taylorVarToEigen(const mxArray* taylor_var) {
304  if (mxIsEmpty(taylor_var)) {
305  return Eigen::Matrix<Eigen::AutoDiffScalar<Eigen::VectorXd>, Rows, Cols>(
306  mxGetM(taylor_var), mxGetN(taylor_var));
307  }
308  auto f = mxGetPropertySafe(taylor_var, "f");
309  auto df = mxGetPropertySafe(taylor_var, "df");
310  if (mxGetNumberOfElements(df) > 1)
311  throw std::runtime_error(
312  "TaylorVars of order higher than 1 currently not supported");
313  auto ret = matlabToEigenMap<Rows, Cols>(f)
314  .template cast<Eigen::AutoDiffScalar<Eigen::VectorXd>>()
315  .eval();
316  typedef Gradient<decltype(ret), Eigen::Dynamic> GradientType;
317  auto gradient_matrix =
318  matlabToEigenMap<GradientType::type::RowsAtCompileTime,
319  GradientType::type::ColsAtCompileTime>(mxGetCell(df, 0));
320  gradientMatrixToAutoDiff(gradient_matrix, ret);
321  return ret;
322 }
323 
324 template <typename Derived>
325 mxArray* eigenToTaylorVar(const Eigen::MatrixBase<Derived>& m,
326  int num_variables = Eigen::Dynamic) {
327  const int nrhs = 2;
328  mxArray* prhs[nrhs];
329  prhs[0] = eigenToMatlab(autoDiffToValueMatrix(m));
330  mwSize dims[] = {1};
331  prhs[1] = mxCreateCellArray(1, dims);
332  mxArray* plhs[1];
333  mxSetCell(prhs[1], 0,
334  eigenToMatlab(autoDiffToGradientMatrix(m, num_variables)));
335  mexCallMATLABsafe(1, plhs, nrhs, prhs, "TaylorVar");
336  return plhs[0];
337 }
338 
339 template <int RowsAtCompileTime, int ColsAtCompileTime, typename DerType>
340 mxArray* eigenToMatlabGeneral(const Eigen::MatrixBase<Eigen::Matrix<
341  Eigen::AutoDiffScalar<DerType>, RowsAtCompileTime, ColsAtCompileTime>>&
342  mat) {
343  return eigenToTaylorVar(mat);
344 }
345 
346 template <int RowsAtCompileTime, int ColsAtCompileTime>
347 mxArray* eigenToMatlabGeneral(const Eigen::MatrixBase<
348  Eigen::Matrix<TrigPolyd, RowsAtCompileTime, ColsAtCompileTime>>& mat) {
349  return eigenToTrigPoly<RowsAtCompileTime, ColsAtCompileTime>(mat);
350 }
351 
352 template <int RowsAtCompileTime, int ColsAtCompileTime>
353 mxArray* eigenToMatlabGeneral(const Eigen::MatrixBase<
354  Eigen::Matrix<double, RowsAtCompileTime, ColsAtCompileTime>>& mat) {
355  return eigenToMatlab(mat.const_cast_derived());
356 }
THIS FILE IS DEPRECATED.
Eigen::Matrix< double, RowsAtCompileTime, ColsAtCompileTime > matlabToEigen(const mxArray *matlab_array)
Definition: drakeMexUtil.h:110
DLLEXPORT mxArray * stdStringToMatlab(const std::string &str)
Definition: drakeMexUtil.cpp:224
DLLEXPORT void sizecheck(const mxArray *mat, mwSize M, mwSize N)
Definition: drakeMexUtil.cpp:404
AutoDiffToValueMatrix< Derived >::type autoDiffToValueMatrix(const Eigen::MatrixBase< Derived > &auto_diff_matrix)
Definition: autodiff.h:40
DLLEXPORT mxArray * mxGetFieldOrPropertySafe(const mxArray *array, std::string const &field_name)
Definition: drakeMexUtil.cpp:283
DLLEXPORT Eigen::Matrix< Polynomiald, Eigen::Dynamic, Eigen::Dynamic > msspolyToEigen(const mxArray *msspoly)
Definition: drakeMexUtil.cpp:332
Eigen::Matrix< Eigen::AutoDiffScalar< Eigen::VectorXd >, Rows, Cols > taylorVarToEigen(const mxArray *taylor_var)
Definition: drakeMexUtil.h:303
DLLEXPORT mxArray * createDrakeMexPointer(void *ptr, const std::string &name="", int type_id=-1, int num_additional_inputs=0, mxArray *delete_fcn_additional_inputs[]=NULL, const std::string &subclass_name="", const std::string &mex_function_name_prefix="")
Definition: drakeMexUtil.cpp:68
DLLEXPORT void mxSetFieldSafe(mxArray *array, size_t index, std::string const &fieldname, mxArray *data)
Definition: drakeMexUtil.cpp:273
mxArray * eigenToMatlabGeneral(const Eigen::MatrixBase< Eigen::Matrix< Eigen::AutoDiffScalar< DerType >, RowsAtCompileTime, ColsAtCompileTime >> &mat)
Definition: drakeMexUtil.h:340
DLLEXPORT std::string mxGetStdString(const mxArray *array)
Definition: drakeMexUtil.cpp:196
DLLEXPORT double * mxGetPrSafe(const mxArray *pobj)
Definition: drakeMexUtil.cpp:236
AutoDiffToGradientMatrix< Derived >::type autoDiffToGradientMatrix(const Eigen::MatrixBase< Derived > &auto_diff_matrix, int num_variables=Eigen::Dynamic)
Definition: autodiff.h:61
STL namespace.
DLLEXPORT mxArray * eigenToMatlabSparse(Eigen::MatrixBase< Derived > const &M, int &num_non_zero)
DLLEXPORT mwSize sub2ind(mwSize ndims, const mwSize *dims, const mwSize *sub)
Definition: drakeMexUtil.cpp:394
DLLEXPORT Eigen::SparseMatrix< double > matlabToEigenSparse(const mxArray *mex)
Definition: drakeMexUtil.cpp:166
mxArray * stdVectorToMatlab(const std::vector< Scalar > &vec)
Definition: drakeMexUtil.h:170
DLLEXPORT mxArray * mxGetPropertySafe(const mxArray *array, std::string const &field_name)
Definition: drakeMexUtil.cpp:244
Polynomial< double > Polynomiald
Definition: Polynomial.h:497
void destroyDrakeMexPointer(const mxArray *mx)
Definition: drakeMexUtil.h:74
Utilities for arithmetic on AutoDiffScalar.
mxArray * eigenToTrigPoly(const Eigen::Matrix< TrigPolyd, _Rows, _Cols > &trigpoly_mat)
Definition: drakeMexUtil.h:260
std::map< VarType, SinCosVars > SinCosMap
Definition: TrigPoly.h:52
#define DLLEXPORT
Definition: drakeMexUtil.h:37
void matlabToCArrayOfArrays(const mxArray *source, double(&destination)[Rows][Cols])
Definition: drakeMexUtil.h:184
DLLEXPORT std::vector< std::string > mxGetVectorOfStdStrings(const mxArray *array)
Definition: drakeMexUtil.cpp:213
mxArray * eigenToTaylorVar(const Eigen::MatrixBase< Derived > &m, int num_variables=Eigen::Dynamic)
Definition: drakeMexUtil.h:325
DLLEXPORT void * getDrakeMexPointer(const mxArray *mx)
Definition: drakeMexUtil.cpp:122
DLLEXPORT mxArray * vectorOfStdStringsToMatlab(const std::vector< std::string > &strs)
Definition: drakeMexUtil.cpp:228
DLLEXPORT Eigen::Matrix< TrigPolyd, Eigen::Dynamic, Eigen::Dynamic > trigPolyToEigen(const mxArray *trigpoly)
Definition: drakeMexUtil.cpp:369
mxArray * eigenToMatlab(const DerivedA &m)
Definition: drakeMexUtil.h:94
Definition: gradient.h:13
void gradientMatrixToAutoDiff(const Eigen::MatrixBase< DerivedGradient > &gradient, Eigen::MatrixBase< DerivedAutoDiff > &auto_diff_matrix)
Definition: drakeGradientUtil.h:296
Eigen::Map< const Eigen::Matrix< double, Rows, Cols > > matlabToEigenMap(const mxArray *mex)
Definition: drakeMexUtil.h:120
const std::vector< T > matlabToStdVector(const mxArray *in)
Definition: drakeMexUtil.cpp:298
DLLEXPORT mxArray * mxGetFieldSafe(const mxArray *array, std::string const &field_name)
Definition: drakeMexUtil.cpp:259
DLLEXPORT bool isa(const mxArray *mxa, const char *class_str)
Definition: DCSFunction.cpp:16
DLLEXPORT bool mexCallMATLABsafe(int nlhs, mxArray *plhs[], int nrhs, mxArray *prhs[], const char *filename)
Definition: drakeMexUtil.cpp:23
mxArray * eigenToMSSPoly(const Eigen::Matrix< Polynomiald, _Rows, _Cols > &poly)
Definition: drakeMexUtil.h:207