2011-10-14 02:41:56 +08:00
|
|
|
/* ----------------------------------------------------------------------------
|
|
|
|
|
2016-11-17 06:51:03 +08:00
|
|
|
* GTSAM Copyright 2010, Georgia Tech Research Corporation,
|
2011-10-14 02:41:56 +08:00
|
|
|
* Atlanta, Georgia 30332-0415
|
|
|
|
* All Rights Reserved
|
|
|
|
* Authors: Frank Dellaert, et al. (see THANKS for the full author list)
|
|
|
|
|
|
|
|
* See LICENSE for the license information
|
|
|
|
|
|
|
|
* -------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
/**
|
2011-10-14 11:23:14 +08:00
|
|
|
* @file Constructor.ccp
|
|
|
|
* @author Frank Dellaert
|
2012-06-27 02:52:27 +08:00
|
|
|
* @author Andrew Melim
|
2012-07-13 06:28:28 +08:00
|
|
|
* @author Richard Roberts
|
2011-10-14 02:41:56 +08:00
|
|
|
**/
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
#include <fstream>
|
2012-06-27 02:52:27 +08:00
|
|
|
#include <algorithm>
|
2011-10-14 02:41:56 +08:00
|
|
|
|
2012-07-05 22:04:36 +08:00
|
|
|
#include <boost/lexical_cast.hpp>
|
2011-10-14 02:41:56 +08:00
|
|
|
|
|
|
|
#include "utilities.h"
|
|
|
|
#include "Constructor.h"
|
2016-09-10 03:52:44 +08:00
|
|
|
#include "Class.h"
|
2011-10-14 02:41:56 +08:00
|
|
|
|
|
|
|
using namespace std;
|
2011-12-03 00:43:15 +08:00
|
|
|
using namespace wrap;
|
2011-10-14 02:41:56 +08:00
|
|
|
|
|
|
|
/* ************************************************************************* */
|
2014-11-15 00:47:25 +08:00
|
|
|
string Constructor::matlab_wrapper_name(Str className) const {
|
2012-07-03 02:18:11 +08:00
|
|
|
string str = "new_" + className;
|
2011-10-14 02:41:56 +08:00
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************************************************* */
|
2014-11-15 00:47:25 +08:00
|
|
|
void Constructor::proxy_fragment(FileWriter& file,
|
2016-11-20 22:24:43 +08:00
|
|
|
const std::string& wrapperName, bool hasParent,
|
|
|
|
const int id, const ArgumentList args) const {
|
2012-10-02 22:40:07 +08:00
|
|
|
size_t nrArgs = args.size();
|
|
|
|
// check for number of arguments...
|
2012-07-05 22:04:36 +08:00
|
|
|
file.oss << " elseif nargin == " << nrArgs;
|
2016-11-20 22:24:43 +08:00
|
|
|
if (nrArgs > 0) file.oss << " && ";
|
2012-10-02 22:40:07 +08:00
|
|
|
// ...and their types
|
2011-10-14 02:41:56 +08:00
|
|
|
bool first = true;
|
2014-11-15 00:47:25 +08:00
|
|
|
for (size_t i = 0; i < nrArgs; i++) {
|
2016-11-20 22:24:43 +08:00
|
|
|
if (!first) file.oss << " && ";
|
2014-11-15 00:47:25 +08:00
|
|
|
file.oss << "isa(varargin{" << i + 1 << "},'" << args[i].matlabClass(".")
|
2016-11-20 22:24:43 +08:00
|
|
|
<< "')";
|
2014-11-15 00:47:25 +08:00
|
|
|
first = false;
|
2012-01-10 13:06:46 +08:00
|
|
|
}
|
|
|
|
// emit code for calling constructor
|
2014-11-15 00:47:25 +08:00
|
|
|
if (hasParent)
|
2012-10-02 22:40:07 +08:00
|
|
|
file.oss << "\n [ my_ptr, base_ptr ] = ";
|
|
|
|
else
|
|
|
|
file.oss << "\n my_ptr = ";
|
2012-07-09 08:02:43 +08:00
|
|
|
file.oss << wrapperName << "(" << id;
|
2012-01-10 13:06:46 +08:00
|
|
|
// emit constructor arguments
|
2014-11-15 00:47:25 +08:00
|
|
|
for (size_t i = 0; i < nrArgs; i++) {
|
2012-07-08 20:27:39 +08:00
|
|
|
file.oss << ", ";
|
2014-11-15 00:47:25 +08:00
|
|
|
file.oss << "varargin{" << i + 1 << "}";
|
2011-10-14 02:41:56 +08:00
|
|
|
}
|
2012-07-05 22:04:36 +08:00
|
|
|
file.oss << ");\n";
|
2011-10-14 02:41:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************************************************* */
|
2014-11-15 00:47:25 +08:00
|
|
|
string Constructor::wrapper_fragment(FileWriter& file, Str cppClassName,
|
2016-11-20 22:24:43 +08:00
|
|
|
Str matlabUniqueName,
|
|
|
|
boost::optional<string> cppBaseClassName,
|
|
|
|
int id, const ArgumentList& al) const {
|
|
|
|
const string wrapFunctionName =
|
|
|
|
matlabUniqueName + "_constructor_" + boost::lexical_cast<string>(id);
|
2012-07-05 22:04:36 +08:00
|
|
|
|
2014-11-15 00:47:25 +08:00
|
|
|
file.oss << "void " << wrapFunctionName
|
2016-11-20 22:24:43 +08:00
|
|
|
<< "(int nargout, mxArray *out[], int nargin, const mxArray *in[])"
|
|
|
|
<< endl;
|
2012-07-05 22:04:36 +08:00
|
|
|
file.oss << "{\n";
|
2012-10-02 22:40:07 +08:00
|
|
|
file.oss << " mexAtExit(&_deleteAllObjects);\n";
|
2016-11-20 22:24:43 +08:00
|
|
|
// Typedef boost::shared_ptr
|
2012-10-02 22:40:07 +08:00
|
|
|
file.oss << " typedef boost::shared_ptr<" << cppClassName << "> Shared;\n";
|
|
|
|
file.oss << "\n";
|
2012-06-27 02:52:27 +08:00
|
|
|
|
2016-11-20 22:24:43 +08:00
|
|
|
// Check to see if there will be any arguments and remove {} for consiseness
|
|
|
|
if (al.size() > 0) al.matlab_unwrap(file); // unwrap arguments
|
2014-11-15 00:47:25 +08:00
|
|
|
file.oss << " Shared *self = new Shared(new " << cppClassName << "("
|
2016-11-20 22:24:43 +08:00
|
|
|
<< al.names() << "));" << endl;
|
2012-10-02 22:40:07 +08:00
|
|
|
file.oss << " collector_" << matlabUniqueName << ".insert(self);\n";
|
2012-07-05 22:04:36 +08:00
|
|
|
|
2014-11-15 00:47:25 +08:00
|
|
|
if (verbose_)
|
2013-03-16 07:24:30 +08:00
|
|
|
file.oss << " std::cout << \"constructed \" << self << std::endl;" << endl;
|
2014-11-15 00:47:25 +08:00
|
|
|
file.oss
|
|
|
|
<< " out[0] = mxCreateNumericMatrix(1, 1, mxUINT32OR64_CLASS, mxREAL);"
|
|
|
|
<< endl;
|
|
|
|
file.oss << " *reinterpret_cast<Shared**> (mxGetData(out[0])) = self;"
|
2016-11-20 22:24:43 +08:00
|
|
|
<< endl;
|
2012-06-27 02:52:27 +08:00
|
|
|
|
2016-11-20 22:24:43 +08:00
|
|
|
// If we have a base class, return the base class pointer (MATLAB will call
|
|
|
|
// the base class collectorInsertAndMakeBase to add this to the collector and
|
|
|
|
// recurse the heirarchy)
|
2014-11-30 17:38:24 +08:00
|
|
|
if (cppBaseClassName) {
|
2012-10-02 22:40:07 +08:00
|
|
|
file.oss << "\n";
|
2014-11-30 17:38:24 +08:00
|
|
|
file.oss << " typedef boost::shared_ptr<" << *cppBaseClassName
|
2016-11-20 22:24:43 +08:00
|
|
|
<< "> SharedBase;\n";
|
|
|
|
file.oss << " out[1] = mxCreateNumericMatrix(1, 1, mxUINT32OR64_CLASS, "
|
|
|
|
"mxREAL);\n";
|
|
|
|
file.oss << " *reinterpret_cast<SharedBase**>(mxGetData(out[1])) = new "
|
|
|
|
"SharedBase(*self);\n";
|
2012-10-02 22:40:07 +08:00
|
|
|
}
|
2012-07-09 08:02:43 +08:00
|
|
|
|
2012-01-16 05:42:41 +08:00
|
|
|
file.oss << "}" << endl;
|
2011-10-14 02:41:56 +08:00
|
|
|
|
2012-10-02 22:40:07 +08:00
|
|
|
return wrapFunctionName;
|
2011-10-14 02:41:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************************************************* */
|
2014-11-15 00:47:25 +08:00
|
|
|
void Constructor::python_wrapper(FileWriter& wrapperFile, Str className) const {
|
2016-11-20 22:24:43 +08:00
|
|
|
wrapperFile.oss << " .def(\"" << name_ << "\", &" << className
|
|
|
|
<< "::" << name_ << ");\n";
|
2014-11-15 00:47:25 +08:00
|
|
|
}
|
|
|
|
|
2016-09-11 07:44:53 +08:00
|
|
|
/* ************************************************************************* */
|
|
|
|
bool Constructor::hasDefaultConstructor() const {
|
|
|
|
for (size_t i = 0; i < nrOverloads(); i++) {
|
|
|
|
if (argumentList(i).size() == 0) return true;
|
2016-11-17 06:51:03 +08:00
|
|
|
}
|
2016-09-11 07:44:53 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-11-15 00:47:25 +08:00
|
|
|
/* ************************************************************************* */
|
2016-12-16 13:23:45 +08:00
|
|
|
void Constructor::emit_cython_pxd(FileWriter& pxdFile, const Class& cls) const {
|
2016-09-09 01:33:32 +08:00
|
|
|
for (size_t i = 0; i < nrOverloads(); i++) {
|
|
|
|
ArgumentList args = argumentList(i);
|
2016-09-13 06:17:47 +08:00
|
|
|
|
2016-09-11 07:44:53 +08:00
|
|
|
// generate the constructor
|
2016-12-16 13:23:45 +08:00
|
|
|
pxdFile.oss << " " << cls.pxdClassName() << "(";
|
|
|
|
args.emit_cython_pxd(pxdFile, cls.pxdClassName(), cls.templateArgs);
|
2016-11-20 22:24:43 +08:00
|
|
|
pxdFile.oss << ") "
|
|
|
|
<< "except +\n";
|
2016-09-09 01:33:32 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************************************************* */
|
2016-09-10 03:52:44 +08:00
|
|
|
void Constructor::emit_cython_pyx(FileWriter& pyxFile, const Class& cls) const {
|
|
|
|
for (size_t i = 0; i < nrOverloads(); i++) {
|
|
|
|
ArgumentList args = argumentList(i);
|
2016-11-30 18:56:07 +08:00
|
|
|
pyxFile.oss << " def " + cls.pyxClassName() + "_" + to_string(i) +
|
2016-11-20 22:24:43 +08:00
|
|
|
"(self, *args, **kwargs):\n";
|
2016-11-22 06:14:30 +08:00
|
|
|
pyxFile.oss << pyx_resolveOverloadParams(args, true);
|
convert numpy input params to dtype float and order 'F' automatically
using numpy.astype(...). No copy if the params are already in the correct dtype and storage order.
For a function
f(Matrix A, Matrix B),
simply wrapping it to pyx as
f(A.astype(float, order='F', copy=False), B.astype(float, order='F', copy=False))
won't work.
It produces a strange side-effect that the content of A is overwritten by B and the two inputs are the same (data address) inside the function!
This is because Cython decreases the ref count for the temporary variable resulted from A.astype(...) before generates the wrap for B.astype(...).
Hence, the A.astype temp var is probably reused for B.astype, and they were pointing to the same data address.
For that reason, we have to go a longer route and wrap it as:
A = A.astype(float, order='F', copy=False)
B = B.astype(float, order='F', copy=False)
f(A, B)
For future ref., here is a sample of the wrongly generated code that wraps the JacobianFactor constructor:
Jacobian(Key i1, Matrix A1, Key i2, Matrix A2, Vector b, noiseModel::Diagonal model)
Wrongly wrapped pyx code:
self.shared_CJacobianFactor_ = shared_ptr[CJacobianFactor](new CJacobianFactor(i1, <MatrixXd>(Map[MatrixXd](A1.astype(float, order='F',copy=False)), i2, <MatrixXd>(Map[MatrixXd](A2.astype(float, order='F', copy=False)), <VectorXd>(Map[VectorXd](b.astype(float, order='F', copy=False))), model.shared_CnoiseModel_Diagonal_))
The problematic Cython generated CPP code with a comment on the problematic line:
/////////////////////////////////////////
// WRONG VERSION
/////////////////////////////////////////
__pyx_t_12 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_A1), __pyx_n_s_astype); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 2107, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_12);
__pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 2107, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_4);
__Pyx_INCREF(((PyObject *)(&PyFloat_Type)));
__Pyx_GIVEREF(((PyObject *)(&PyFloat_Type)));
PyTuple_SET_ITEM(__pyx_t_4, 0, ((PyObject *)(&PyFloat_Type)));
__pyx_t_5 = PyDict_New(); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 2107, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_5);
if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_order, __pyx_n_s_F) < 0) __PYX_ERR(0, 2107, __pyx_L1_error)
if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_copy, Py_False) < 0) __PYX_ERR(0, 2107, __pyx_L1_error)
__pyx_t_13 = __Pyx_PyObject_Call(__pyx_t_12, __pyx_t_4, __pyx_t_5); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 2107, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_13);
__Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0;
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
if (!(likely(((__pyx_t_13) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_13, __pyx_ptype_5numpy_ndarray))))) __PYX_ERR(0, 2107, __pyx_L1_error)
try {
__pyx_t_14 = eigency::Map<Eigen::MatrixXd> (((PyArrayObject *)__pyx_t_13));
} catch(...) {
__Pyx_CppExn2PyErr();
__PYX_ERR(0, 2107, __pyx_L1_error)
}
///////////////////////////////////////////////
__Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; //<------- Problematic line!!! Killing this will result in the correct result!
///////////////////////////////////////////////
__pyx_t_13 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_A2), __pyx_n_s_astype); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 2107, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_13);
__pyx_t_5 = PyTuple_New(1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 2107, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_5);
__Pyx_INCREF(((PyObject *)(&PyFloat_Type)));
__Pyx_GIVEREF(((PyObject *)(&PyFloat_Type)));
PyTuple_SET_ITEM(__pyx_t_5, 0, ((PyObject *)(&PyFloat_Type)));
__pyx_t_4 = PyDict_New(); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 2107, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_4);
if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_order, __pyx_n_s_F) < 0) __PYX_ERR(0, 2107, __pyx_L1_error)
if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_copy, Py_False) < 0) __PYX_ERR(0, 2107, __pyx_L1_error)
__pyx_t_12 = __Pyx_PyObject_Call(__pyx_t_13, __pyx_t_5, __pyx_t_4); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 2107, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_12);
__Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0;
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
if (!(likely(((__pyx_t_12) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_12, __pyx_ptype_5numpy_ndarray))))) __PYX_ERR(0, 2107, __pyx_L1_error)
try {
__pyx_t_15 = eigency::Map<Eigen::MatrixXd> (((PyArrayObject *)__pyx_t_12));
} catch(...) {
__Pyx_CppExn2PyErr();
__PYX_ERR(0, 2107, __pyx_L1_error)
}
__Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0;
__pyx_t_12 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_b), __pyx_n_s_astype); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 2107, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_12);
__pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 2107, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_4);
__Pyx_INCREF(((PyObject *)(&PyFloat_Type)));
__Pyx_GIVEREF(((PyObject *)(&PyFloat_Type)));
PyTuple_SET_ITEM(__pyx_t_4, 0, ((PyObject *)(&PyFloat_Type)));
__pyx_t_5 = PyDict_New(); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 2107, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_5);
if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_order, __pyx_n_s_F) < 0) __PYX_ERR(0, 2107, __pyx_L1_error)
if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_copy, Py_False) < 0) __PYX_ERR(0, 2107, __pyx_L1_error)
__pyx_t_13 = __Pyx_PyObject_Call(__pyx_t_12, __pyx_t_4, __pyx_t_5); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 2107, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_13);
__Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0;
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
if (!(likely(((__pyx_t_13) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_13, __pyx_ptype_5numpy_ndarray))))) __PYX_ERR(0, 2107, __pyx_L1_error)
try {
__pyx_t_16 = eigency::Map<Eigen::VectorXd> (((PyArrayObject *)__pyx_t_13));
} catch(...) {
__Pyx_CppExn2PyErr();
__PYX_ERR(0, 2107, __pyx_L1_error)
}
__Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0;
try {
__pyx_t_17 = new gtsam::JacobianFactor(__pyx_v_i1, ((Eigen::MatrixXd)__pyx_t_14), __pyx_v_i2, ((Eigen::MatrixXd)__pyx_t_15), ((Eigen::VectorXd)__pyx_t_16), __pyx_v_model->shared_CnoiseModel_Diagonal_);
} catch(...) {
__Pyx_CppExn2PyErr();
__PYX_ERR(0, 2107, __pyx_L1_error)
}
__pyx_v_self->shared_CJacobianFactor_ = boost::shared_ptr<gtsam::JacobianFactor> (__pyx_t_17);
2017-03-16 01:47:11 +08:00
|
|
|
pyxFile.oss << argumentList(i).pyx_convertEigenTypeAndStorageOrder(" ");
|
2016-11-17 06:51:03 +08:00
|
|
|
|
2016-11-30 18:56:07 +08:00
|
|
|
pyxFile.oss << " self." << cls.shared_pxd_obj_in_pyx() << " = "
|
2016-11-23 01:13:33 +08:00
|
|
|
<< cls.shared_pxd_class_in_pyx() << "(new " << cls.pxd_class_in_pyx()
|
2016-11-20 22:24:43 +08:00
|
|
|
<< "(" << args.pyx_asParams() << "))\n";
|
2016-11-30 18:56:07 +08:00
|
|
|
pyxFile.oss << " return True\n\n";
|
2016-09-10 03:52:44 +08:00
|
|
|
}
|
2016-09-10 00:01:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************************************************* */
|