Commit Graph

25 Commits (f558ccbb2de2d25c93705b96d482b07e0c7a19d2)

Author SHA1 Message Date
dellaert 74a33ff222 Re-structured argument overloading to call a common function 2017-08-06 11:07:13 -07:00
Duy-Nguyen Ta 6bf7ea23cf 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-15 13:47:11 -04:00
Duy-Nguyen Ta f154be176f Major update to generate proper Cython pxd header files which could be included in other projects/modules
All cdef (class, functions, variables) declarations are moved to pxd. Implementations of those cdefs and normal Python def are in pyx.
See: http://cython.readthedocs.io/en/latest/src/userguide/sharing_declarations.html#sharing-extension-types
2016-12-16 00:23:45 -05:00
Duy-Nguyen Ta 4439968f05 tabs to spaces 2016-11-30 05:56:07 -05:00
Duy-Nguyen Ta 5958b2397c resolve overloads via type checking, simplify Values's insert and update, more friendly Matrix and Vector utils
Keyword arguments are not needed anymore
2016-11-29 11:58:22 -05:00
Duy-Nguyen Ta c13b964777 standardize names for classes with inner namespace 2016-11-24 19:22:44 -05:00
Duy-Nguyen Ta 6ef6457e51 support global function overloads 2016-11-22 17:32:48 -05:00
Duy-Nguyen Ta 338c73669e support global functions (no overload) 2016-11-22 17:09:35 -05:00
Yao Chen d1ea1015a9 Replaced BOOSE_FOREACH with for in wrap folder. Tested the changed code locally: successful. 2016-05-20 21:41:18 -04:00
dellaert ba51b02cf0 Moving to optionals fixed template dreturn argument!
Merge branch 'qualified' into grammar_wrongtest

Conflicts:
	wrap/Class.cpp
	wrap/Function.h
	wrap/Qualified.h
	wrap/ReturnType.h
	wrap/tests/testWrap.cpp
2014-12-01 09:48:56 +01:00
dellaert 6d916c6b75 Semi-private name/namespaces 2014-11-30 20:20:13 +01:00
dellaert 0261c59063 static property is known by function! Makes so much more sense... 2014-11-29 20:59:38 +01:00
dellaert 0eaabd700b Refactored emit call 2014-11-29 20:53:38 +01:00
dellaert 6c24fc2aca Python prototype 2014-11-14 17:47:25 +01:00
dellaert 7a4748d3dc Simplified method/function hierarchy drastically, and renamed bottom addOverload to initializeOrCheck to reflect what it does. Also, gratuitous re-ordering of addOverload arguments. 2014-11-14 16:44:08 +01:00
dellaert b451e97f6f New TemplateSubstitution object simplifies a lot 2014-11-13 17:28:05 +01:00
dellaert a5e0adb7e6 Made methods and global functions derive from Function 2014-11-13 12:52:41 +01:00
dellaert 77935bd631 Massive edit: new Qualified type groups namespaces with name, eliminates a lot of clutter. 2014-11-12 02:49:23 +01:00
dellaert 5e9632e781 Now using emit_conditional_call (changed indenting) 2014-05-25 16:28:39 -04:00
dellaert 05a38ca263 Standard BORG formatting 2014-05-25 16:01:30 -04:00
dellaert 52cd200718 ReturnValue now emits, eliminated some copy/paste. Also removed unused verbose field/argument in ReturnValue 2014-05-25 14:53:32 -04:00
Chris Beall 4297d24c96 changed tabs to spaces for consistent indentation in all of GTSAM 2012-10-02 14:40:07 +00:00
Alex Cunningham 79c9bc99ff Some additional cleanup in wrap 2012-07-23 18:24:39 +00:00
Alex Cunningham b7c2177f0b Generating code for global functions now works 2012-07-23 18:24:35 +00:00
Alex Cunningham 26fce2d400 Adding support for global functions - parsing works 2012-07-23 14:09:40 +00:00