Drake
standardMexConversions.h
Go to the documentation of this file.
1 #pragma once
2 
3 //
4 // Created by Twan Koolen on 10/10/15.
5 //
6 
7 #include <string>
8 #include "drake/util/mexify.h"
9 
14 bool isConvertibleFromMex(const mxArray* source, int*,
15  std::ostream* log) NOEXCEPT {
16  if (mxGetM(source) != 1 || mxGetN(source) != 1) {
17  if (log) *log << "Expected scalar.";
18  return false;
19  }
20  return true;
21 }
22 
23 int fromMexUnsafe(const mxArray* source, int*) {
24  return static_cast<int>(mxGetScalar(source));
25 }
26 
27 bool isConvertibleFromMex(const mxArray* source, bool*,
28  std::ostream* log) NOEXCEPT {
29  if (!mxIsLogicalScalar(source)) {
30  if (log) *log << "Expected logical scalar.";
31  return false;
32  }
33  return true;
34 }
35 
36 bool fromMexUnsafe(const mxArray* source, bool*) {
37  return mxGetLogicals(source)[0];
38 }
39 
40 /*
41  * note: leaving Options, MaxRows, and MaxCols out as template parameters
42  * (leaving them to their defaults)
43  * results in an internal compiler error on MSVC. See
44  * https://connect.microsoft.com/VisualStudio/feedback/details/1847159
45  */
46 template <int Rows, int Cols, int Options, int MaxRows, int MaxCols>
48  const mxArray* mex,
49  Eigen::MatrixBase<Eigen::Map<
50  const Eigen::Matrix<double, Rows, Cols, Options, MaxRows, MaxCols>>>*,
51  std::ostream* log) NOEXCEPT {
52  // TODO(tkoolen): size checks?
53  if (!mxIsNumeric(mex)) {
54  if (log) *log << "Expected a numeric array";
55  return false;
56  }
57  return true;
58 }
59 
60 template <int Rows, int Cols, int Options, int MaxRows, int MaxCols>
61 Eigen::Map<const Eigen::Matrix<double, Rows, Cols, Options, MaxRows, MaxCols>>
63  const mxArray* mex,
64  Eigen::MatrixBase<Eigen::Map<
65  const Eigen::Matrix<double, Rows, Cols, Options, MaxRows, MaxCols>>>*) {
66  return matlabToEigenMap<Rows, Cols>(mex);
67 }
68 
69 // quick version for VectorXi.
70 // TODO(tkoolen): generalize to arbitrary matrices of integers
71 bool isConvertibleFromMex(const mxArray* source,
72  Eigen::MatrixBase<Eigen::Map<const Eigen::VectorXi>>*,
73  std::ostream* log) NOEXCEPT {
74  if (!mxIsInt32(source)) {
75  if (log) *log << "Expected an int32 array";
76  return false;
77  }
78  if (mxGetM(source) != 1 && mxGetN(source) != 1) {
79  if (log) *log << "Expected a 1 x n or n x 1 int32 array";
80  return false;
81  }
82  return true;
83 }
84 
85 Eigen::Map<const Eigen::VectorXi> fromMexUnsafe(
86  const mxArray* source,
87  Eigen::MatrixBase<Eigen::Map<const Eigen::VectorXi>>*) {
88  auto num_elements = mxGetNumberOfElements(source);
89  return Eigen::Map<const Eigen::VectorXi>(
90  reinterpret_cast<int*>(mxGetData(source)), num_elements);
91 }
92 
93 template <typename T>
94 bool isConvertibleFromMex(const mxArray* source, std::vector<T>*,
95  std::ostream* log) NOEXCEPT {
96  if (!mxIsCell(source)) {
97  if (log) *log << "Expected a cell array";
98  return false;
99  }
100  if (mxGetM(source) != 1 && mxGetN(source) != 1) {
101  if (log) *log << "Expected a 1 x n or n x 1 cell array";
102  return false;
103  }
104  return true;
105 }
106 
107 template <typename T>
108 std::vector<T> fromMexUnsafe(const mxArray* source, std::vector<T>*) {
109  auto num_elements = mxGetNumberOfElements(source);
110  std::vector<T> ret;
111  ret.reserve(num_elements);
112  for (size_t i = 0; i < num_elements; i++) {
113  ret.push_back(
114  fromMexUnsafe(mxGetCell(source, i), static_cast<T*>(nullptr)));
115  }
116  return ret;
117 }
118 
119 template <typename DerType, int Rows, int Cols, int Options, int MaxRows,
120  int MaxCols>
122  const mxArray* mex,
123  Eigen::MatrixBase<Eigen::Matrix<Eigen::AutoDiffScalar<DerType>, Rows, Cols,
124  Options, MaxRows, MaxCols>>*,
125  std::ostream* log) NOEXCEPT {
126  using namespace Eigen;
127  using namespace std;
128 
129  if (!mxIsClass(mex, "TaylorVar")) {
130  if (log) *log << "Expected an array of TaylorVar";
131  return false;
132  }
133  if (mxIsEmpty(mex)) {
134  if (log) *log << "Can't parse empty TaylorVar arrays";
135  return false;
136  }
137  auto derivs = mxGetPropertySafe(mex, "df");
138  if (mxGetNumberOfElements(derivs) > 1) {
139  if (log)
140  *log << "TaylorVars of order higher than 1 currently not supported";
141  return false;
142  }
143  auto df = mxGetCell(derivs, 0);
144  auto dim = mxGetPrSafe(mxGetPropertySafe(mex, "dim"));
145  auto rows = static_cast<int>(
146  dim[0]); // note: apparently not always the same as mxGetM(f)
147  auto cols = static_cast<int>(
148  dim[1]); // note: apparently not always the same as mxGetN(f)
149 
150  if ((MaxRows != Dynamic && rows > MaxRows) ||
151  (Rows != Dynamic && rows != Rows)) {
152  if (log)
153  *log << "Row size mismatch. rows: " << to_string(rows)
154  << ", rows at compile time: " << to_string(Rows)
155  << ", max rows at compile time: " << to_string(MaxRows);
156  return false;
157  }
158 
159  if ((MaxCols != Dynamic && cols > MaxCols) ||
160  (Cols != Dynamic && cols != Cols)) {
161  if (log)
162  *log << "Col size mismatch. cols: " << to_string(cols)
163  << ", cols at compile time: " << to_string(Cols)
164  << ", max cols at compile time: " << to_string(MaxCols);
165  return false;
166  }
167 
168  auto num_derivs = mxGetN(df);
169  if ((DerType::MaxRowsAtCompileTime != Dynamic &&
170  num_derivs > DerType::MaxRowsAtCompileTime) ||
171  (DerType::RowsAtCompileTime != Dynamic &&
172  num_derivs != DerType::RowsAtCompileTime)) {
173  if (log)
174  *log << "Derivative size mismatch. num_derivs: " << to_string(num_derivs)
175  << ", num_derivs at compile time: "
176  << to_string(DerType::RowsAtCompileTime)
177  << ", max num_derivs at compile time: "
178  << to_string(DerType::MaxRowsAtCompileTime);
179  return false;
180  }
181 
182  return true;
183 }
184 
185 template <typename DerType, int Rows, int Cols, int Options, int MaxRows,
186  int MaxCols>
187 Eigen::Matrix<Eigen::AutoDiffScalar<DerType>, Rows, Cols, Options, MaxRows,
188  MaxCols>
190  const mxArray* mex,
191  Eigen::MatrixBase<Eigen::Matrix<Eigen::AutoDiffScalar<DerType>, Rows, Cols,
192  Options, MaxRows, MaxCols>>*) {
193  using namespace Eigen;
194 
195  typedef AutoDiffScalar<DerType> ADScalar;
196  auto f = mxGetPropertySafe(mex, "f");
197  auto derivs = mxGetPropertySafe(mex, "df");
198  auto df = mxGetCell(derivs, 0);
199 
200  auto dim = mxGetPrSafe(mxGetPropertySafe(mex, "dim"));
201  auto rows = static_cast<int>(
202  dim[0]); // note: apparently not always the same as mxGetM(f)
203  auto cols = static_cast<int>(
204  dim[1]); // note: apparently not always the same as mxGetN(f)
205 
206  Matrix<ADScalar, Rows, Cols, Options, MaxRows, MaxCols> ret(rows, cols);
207  if (!mxIsEmpty(mex)) {
208  typedef typename ADScalar::Scalar NormalScalar;
209  typedef Matrix<NormalScalar, Rows, Cols, Options, MaxRows, MaxCols>
210  ValueMatrixType;
211  ret = Map<ValueMatrixType>(mxGetPrSafe(f), rows, cols)
212  .template cast<ADScalar>();
213 
215  GradientType;
216  typedef Matrix<NormalScalar, GradientType::RowsAtCompileTime,
217  GradientType::ColsAtCompileTime, 0,
218  GradientType::RowsAtCompileTime,
219  DerType::MaxRowsAtCompileTime> GradientTypeFixedMaxSize;
220 
221  if (mxIsSparse(df)) {
222  auto gradient_matrix = GradientTypeFixedMaxSize(
223  matlabToEigenSparse(df)); // TODO(tkoolen): inefficient
224  gradientMatrixToAutoDiff(gradient_matrix, ret);
225  } else {
226  auto num_derivs = mxGetN(df);
227  auto gradient_matrix = Map<GradientTypeFixedMaxSize>(
228  mxGetPrSafe(df), mxGetM(df), num_derivs);
229  gradientMatrixToAutoDiff(gradient_matrix, ret);
230  }
231  }
232  return ret;
233 }
234 
239 int toMex(const bool& source, mxArray* dest[], int nlhs) {
240  dest[0] = mxCreateLogicalScalar(source);
241  return 1;
242 }
243 
244 /*
245  * note: leaving Options, MaxRows, and MaxCols out as template parameters
246  * (leaving them to their defaults)
247  * results in an internal compiler error on MSVC. See
248  * https://connect.microsoft.com/VisualStudio/feedback/details/1847159
249  */
250 template <typename Scalar, int Rows, int Cols, int Options, int MaxRows,
251  int MaxCols>
252 int toMex(
253  const Eigen::Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols>& source,
254  mxArray* dest[], int nlhs) {
255  if (nlhs > 0) dest[0] = eigenToMatlabGeneral<Rows, Cols>(source);
256  return 1;
257 }
258 
259 template <typename A, typename B>
260 int toMex(const std::pair<A, B>& source, mxArray* dest[], int nlhs) {
261  int num_outputs = 0;
262  num_outputs += toMex(source.first, dest, nlhs - num_outputs);
263  num_outputs += toMex(source.second, &dest[num_outputs], nlhs - num_outputs);
264  return num_outputs;
265 }
266 
267 template <typename T>
268 int toMex(const std::vector<T>& source, mxArray* dest[], int nlhs) {
269  mwSize dims[] = {source.size()};
270  dest[0] = mxCreateCellArray(1, dims);
271  for (size_t i = 0; i < source.size(); i++) {
272  mxArray* cell[1];
273  toMex(source.at(i), cell, 1);
274  mxSetCell(dest[0], i, cell[0]);
275  }
276 
277  return 1;
278 }
279 
280 namespace Drake {
281 namespace internal {
282 template <size_t Index>
284  template <typename... Ts>
285  static int run(const std::tuple<Ts...>& source, mxArray* dest[], int nlhs,
286  int num_outputs = 0) {
287  constexpr size_t tuple_index = sizeof...(Ts)-Index;
288  num_outputs += toMex(std::get<tuple_index>(source), &dest[num_outputs],
289  nlhs - num_outputs);
290  return TupleToMexHelper<Index - 1>::run(source, dest, nlhs, num_outputs);
291  }
292 };
293 
294 template <>
295 struct TupleToMexHelper<0> {
296  template <typename... Ts>
297  static int run(const std::tuple<Ts...>& source, mxArray* dest[], int nlhs,
298  int num_outputs = 0) {
299  return num_outputs;
300  }
301 };
302 }
303 }
304 
305 template <typename... Ts>
306 int toMex(const std::tuple<Ts...>& source, mxArray* dest[], int nlhs) {
307  return Drake::internal::TupleToMexHelper<sizeof...(Ts)>::run(source, dest,
308  nlhs);
309 }
Eigen::SparseMatrix< double > matlabToEigenSparse(const mxArray *mex)
Definition: drakeMexUtil.cpp:166
int fromMexUnsafe(const mxArray *source, int *)
Definition: standardMexConversions.h:23
FunctionalForm log(FunctionalForm const &x)
Definition: functional_form.cc:198
NOTE: The contents of this class are for the most part direct ports of drake/systems/plants//inverseK...
Definition: Function.h:14
STL namespace.
double * mxGetPrSafe(const mxArray *pobj)
Definition: drakeMexUtil.cpp:236
Definition: standardMexConversions.h:283
bool isConvertibleFromMex(const mxArray *source, int *, std::ostream *log) NOEXCEPT
fromMex specializations
Definition: standardMexConversions.h:14
static int run(const std::tuple< Ts... > &source, mxArray *dest[], int nlhs, int num_outputs=0)
Definition: standardMexConversions.h:297
int toMex(const bool &source, mxArray *dest[], int nlhs)
toMex specializations
Definition: standardMexConversions.h:239
std::string to_string(const Eigen::MatrixBase< Derived > &a)
Definition: testUtil.h:29
mxArray * mxGetPropertySafe(const mxArray *array, std::string const &field_name)
Definition: drakeMexUtil.cpp:244
static int run(const std::tuple< Ts... > &source, mxArray *dest[], int nlhs, int num_outputs=0)
Definition: standardMexConversions.h:285
Definition: gradient.h:13
void gradientMatrixToAutoDiff(const Eigen::MatrixBase< DerivedGradient > &gradient, Eigen::MatrixBase< DerivedAutoDiff > &auto_diff_matrix)
Definition: drakeGradientUtil.h:296
#define NOEXCEPT
Definition: mexify.h:15