Memory Leak in Matlab when calling a C++ mexfile - c++

Dear stackoverflow community,
I am currently working on a MEX function that itself calls external C++ code.
I am calling my MEX in a loop.
Here is my mexfile:
#include "mex.h"
#include "OOMP.h"
#include <iostream>
using namespace std;
/*
function [h, Di, beta, c, Q, NorQ] = OOMP_v4(f, D, tol,ind,No)
%OOMP Optimized Orthogonal Matching Pursuit
%
% It creates an atomic decomposition of a siganl
% using OOMP criterion. You can choose a tolerance,
% the number of atoms to take in or an initial subspace to influence the OOMP algorithm.
%
%
% Usage: [h, Di, c, beta, Q, NorQ ] = OOMP_v2(f, D, tol,ind, No);
% [h, Di, c] = OOMP_v2(f, D, tol,ind, No);
*/
void mexFunction(int nlhs, mxArray *plhs[] , int nrhs, const mxArray *prhs[])
{
/* Begin input validation */
if(nrhs != 5)
{
mexErrMsgTxt("Wrong number of input arguments");
}
// Check we are being passed real full and non string variables
for ( int i = 0; i < nrhs; i++ )
{
if ( mxIsComplex(prhs[i]) || mxIsClass(prhs[i],"sparse") || mxIsChar(prhs[i]) || !mxIsDouble(prhs[i]) )
{
mexErrMsgTxt("Input must be double, real, full,and nonstring");
}
}
// First check f is a vector
if ((mxGetM(prhs[0]) !=1) || (mxGetN(prhs[0]) == 1))
{
mexErrMsgTxt("f should be a line vector");
}
// Validate D
if ( (mxGetM(prhs[1])) != (mxGetN(prhs[0])) )
{
mexPrintf("The atoms in the dictionary D are of length %i and should be of length %i\n",mxGetM(prhs[1]),mxGetN(prhs[0]));
mexErrMsgTxt("Error!!\n");
}
if ((mxGetM(prhs[1])) == 1)
{
mexErrMsgTxt("The dictionary D should contain more than 1 atom!!\n");
}
long L = mxGetM(prhs[1]);
long N = mxGetN(prhs[1]);
long numInd = mxGetN(prhs[3]);
Matrix *f = new Matrix(mxGetPr(prhs[0]),1,L, 'T');
Matrix *D = new Matrix(mxGetPr(prhs[1]),L,N,'T');
double tol = mxGetScalar(prhs[2]);
Matrix *mind = new Matrix(mxGetPr(prhs[3]),1,numInd);
long No = mxGetScalar(prhs[4]);
/* Begin Output validation */
if ( nlhs <3 || nlhs >6)
{
mexErrMsgTxt("Wrong number of output arguments");
}
Matrix *h = new Matrix(1,L,0);
Matrix *Di= new Matrix(1,0,0);
Matrix *beta= new Matrix(L,0,0);
Matrix *c= new Matrix(1,0,0);
Matrix *Q= new Matrix(L,0,0);
Matrix *NorQ= new Matrix((long)0,1,0);
int fail =OOMP_v4(f,D,tol,mind,No ,L, N,h,Di,beta,c,Q,NorQ);
if(!fail)
{
// Creation des variables de Sorties
long K = (*Di).getNbre_C();
plhs[0] = mxCreateDoubleMatrix(1,L,mxREAL);
plhs[1] = mxCreateDoubleMatrix(1,K,mxREAL);
plhs[2] = mxCreateDoubleMatrix(1,K,mxREAL);
if(nlhs>=4)
plhs[3] = mxCreateDoubleMatrix(L,K,mxREAL);
if(nlhs>=5)
plhs[4] = mxCreateDoubleMatrix(L,K,mxREAL);
if(nlhs==6)
plhs[5] = mxCreateDoubleMatrix(K,1,mxREAL);
// Transformation
double *m_h= mxGetPr(plhs[0]);
double *m_Di = mxGetPr(plhs[1]);
double *m_c = mxGetPr(plhs[2]);
ToArray(h,m_h,1,L);
ToArray(Di,m_Di,1,K);
ToArray(c,m_c,1,K);
if(nlhs>=4){
double *m_beta = mxGetPr(plhs[3]);
ToArray(beta,m_beta,L,K);
}
if(nlhs>=5){
double *m_Q = mxGetPr(plhs[4]);
ToArray(Q,m_Q,L,K);
}
if(nlhs==6){
double *m_NorQ = mxGetPr(plhs[5]);
ToArray(NorQ,m_NorQ,K,1);
}
}
else
{
mexErrMsgTxt("Error OOMP exited early see message above!!\n");
}
}
I am using the previous mexfile in a matlab program that runs successfully
Here is the loop using the mexfile:
for i=1:Nframes
f=F(:,i)'; %the signals are the colums of F
tol=PRD0*norm(f)/100;
[h, Di0, ~] = OOMP_for_new_Mex(f, D, tol,ind,No);
error_norm(i)= norm(f-h);
K(i)=numel(Di0);
clear Di0 h f tol ;
end
I got good results but the program is using too much memory 10Gb! which awkward because the variable stocked in the Matlab use only a few Mb.
The problem here that in each loop new memory is allocated but it is not released in the end of the loop: The pointers created in the mex file are not deleted after every iteration.
So my questions are:
1)Do you see something else that could cause a memory leak in the code?
2)how can I fix it?

Related

CUDD sum of products Boolean expression

I would like to create BDD for the following Boolean function:
F = (A'B'C'D') OR (A'B C) OR (C' D') OR (A)
I managed to create only F = (A'B'C'D') with the following code but how to add other product terms to the existing BDD?
int main (int argc, char *argv[])
{
char filename[30];
DdManager *gbm; /* Global BDD manager. */
gbm = Cudd_Init(0,0,CUDD_UNIQUE_SLOTS,CUDD_CACHE_SLOTS,0); /* Initialize a new BDD manager. */
DdNode *bdd, *var, *tmp_neg, *tmp;
int i;
bdd = Cudd_ReadOne(gbm); /*Returns the logic one constant of the manager*/
Cudd_Ref(bdd); /*Increases the reference count of a node*/
for (i = 3; i >= 0; i--) {
var = Cudd_bddIthVar(gbm,i); /*Create a new BDD variable*/
tmp_neg = Cudd_Not(var); /*Perform NOT boolean operation*/
tmp = Cudd_bddAnd(gbm, tmp_neg, bdd); /*Perform AND boolean operation*/
Cudd_Ref(tmp);
Cudd_RecursiveDeref(gbm,bdd);
bdd = tmp;
}
bdd = Cudd_BddToAdd(gbm, bdd);
print_dd (gbm, bdd, 2,4);
sprintf(filename, "./bdd/graph.dot");
write_dd(gbm, bdd, filename);
Cudd_Quit(gbm);
return 0;
}
Build every conjunction independently so that you get conj0 to conj3 make sure to only negate the correct literals. I'm not particularly versed in C and don't have a development environment setup right now so you will need to make some corrections.
I will use the following mapping
A <=> BDD(0)
B <=> BDD(1)
C <=> BDD(2)
D <=> BDD(3)
Build conj0 the way you do it now in your for loop. Make sure conj0 = bdd afterwards.
For conj1 which will encode (A' B C) use
bdd = Cudd_IthVar(gbm, 0);
bdd = Cudd_Not(bdd);
tmp = Cudd_And(gbm, bdd, Cudd_IthVar(gbm, 1));
Cudd_Ref(tmp);
Cudd_Deref(gbm, bdd);
bdd = tmp;
tmp = Cudd_And(gbm, bdd, Cudd_IthVar(gbm, 2));
Cudd_Ref(tmp);
Cudd_Deref(gbm, bdd);
bdd = tmp;
conj1 = bdd;
Do the same for conj2 and conj3.
After you've got all the conjunctions build build the top level disjunction by using Cudd_bddOr().
Also make sure that you get the Cudd_Ref() and Cudd_Deref() right otherwise you'll leak memory.
If you are only interested in that particular function, here's a way to build it and inspect it:
#include <stdio.h>
#include <stdlib.h>
#include "cudd.h"
int main(void) {
/* Get set. */
DdManager * mgr = Cudd_Init(4,0,CUDD_UNIQUE_SLOTS,CUDD_CACHE_SLOTS,0);
DdNode *a = Cudd_bddIthVar(mgr, 0);
DdNode *c = Cudd_bddIthVar(mgr, 1);
DdNode *b = Cudd_bddIthVar(mgr, 2);
DdNode *d = Cudd_bddIthVar(mgr, 3);
char const * const inames[] = {"a", "c", "b", "d"};
/* Build BDD. */
DdNode * tmp = Cudd_bddIte(mgr, c, b, Cudd_Not(d));
Cudd_Ref(tmp);
DdNode * f = Cudd_bddOr(mgr, a, tmp);
Cudd_Ref(f);
Cudd_RecursiveDeref(mgr, tmp);
/* Inspect it. */
printf("f");
Cudd_PrintSummary(mgr, f, 4, 0);
Cudd_bddPrintCover(mgr, f, f);
char * fform = Cudd_FactoredFormString(mgr, f, inames);
printf("%s\n", fform);
/* Break up camp and go home. */
free(fform);
Cudd_RecursiveDeref(mgr, f);
int err = Cudd_CheckZeroRef(mgr);
Cudd_Quit(mgr);
return err;
}
Note the choice of (optimal) variable order. You should see this output:
f: 5 nodes 1 leaves 12 minterms
1--- 1
-11- 1
-0-0 1
a | (c & b | !c & !d)

Mismatch of data type when passing argument

I am currently facing following problem. I have searched for any solution but could not find anything useful related to my problem.
I want to use VBA to provide some parameters to a self-written DLL which is going to calculate a result for me.
My problem: As soon as I try to process the values passed to the function setCEPCI I get an "Microsoft Excel has stopped working"- error(no further details). If I put those three lines (see my copied code) in comments, however, everything is working fine. I tried a lot of workarounds but it all came down to those lines.
Surprisingly, I can use the passed arguments in the first function getPEC, where e.g. x is my outflow.
For the record I am using a def file for exporting the function, though, IMHO the error seems to be some mismatch of data types.
EDIT: For clarification: If my DLL is not found e.g. I get the same Microsoft-Excel-error due to the RV assignment. If I try to assign any value to RV in the first function, I also get that error. On the other hand I can assign any value to PEC without problems.
My DLL looks like:
extern "C" {
typedef void(CALLBACK * FncPtrClssGetCEPCI)(CEPCIvalues &, int, int, int &);
double PEC_backUp;
const int numbMaxCEPCIlistMembers = 3;
CEPCIvalues cepcilist_backUp[numbMaxCEPCIlistMembers];
void __stdcall getPEC(int typeOfPump, double outflow, double &PEC, int &RV)
{
//y = a x^6 + b x^5 + c x^4 + d x^3 + e x^2 + f x^1 + g x^0
if ((typeOfPump < 1) || (10 < typeOfPump)) {
RV = -1;
return;
}
double a, b, c, d, e, f, g;
//...
PEC_backUp = a * pow(outflow, 6.0) +
b * pow(outflow, 5.0) +
c * pow(outflow, 4.0) +
d * pow(outflow, 3.0) +
e * pow(outflow, 2.0) +
f * pow(outflow, 1.0) +
g * pow(outflow, 0.0);
double EUR_USD_07_2000 = 0.939082609;
PEC_backUp = PEC_backUp / EUR_USD_07_2000;
PEC = PEC_backUp;
}
void __stdcall setCEPCI(int monthIN, int yearIN, int &RV)
{
//HINSTANCE hinstCEPCI = LoadLibraryEx("CEPCI.dll", NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR);
HINSTANCE hinstCEPCI = LoadLibrary("C:\\Users\\...somePath...\\CEPCI.dll");
if (!hinstCEPCI)
{
RV = -11;
return;
}
FncPtrClssGetCEPCI ptrGetCEPCI = (FncPtrClssGetCEPCI)GetProcAddress(hinstCEPCI, "getCEPCI");
if (!ptrGetCEPCI)
{
RV = -22;
return;
}
//CEPCI values of 13/1970 and 07/2000 are automatically extracted
//due to less interaction and, thus, risk of errors in user input
int monthIN_auto = 13;
int yearIN_auto = 1970;
ptrGetCEPCI(cepcilist_backUp[0], monthIN_auto, yearIN_auto, RV);
monthIN_auto = 7;
yearIN_auto = 2000;
ptrGetCEPCI(cepcilist_backUp[1], monthIN_auto, yearIN_auto, RV);
//now extract CEPCI value of user specific input
// monthIN_auto = monthIN;
// yearIN_auto = yearIN;
ptrGetCEPCI(cepcilist_backUp[2], monthIN_auto, yearIN_auto, RV);
CEPCIvalues cepcilist;
cepcilist = cepcilist_backUp[2];
// RV = monthIN + yearIN;
ptrGetCEPCI = 0;
FreeLibrary(hinstCEPCI);
hinstCEPCI = 0;
return;
}
My VBA code looks like:
Public Declare Sub getPEC _
Lib "C:\Users\...somePath...\OPunit0011PUMP.dll" _
(ByVal typeOfPump As Integer, ByVal outflow As Double, ByRef PEC As Double, ByRef RV As Integer)
Public Declare Sub setCEPCI _
Lib "C:\Users\...somePath...\OPunit0011PUMP.dll" _
(ByVal monthIN As Integer, ByVal yearIN As Integer, ByRef RV As Integer)
Function CallPump()
Dim typeOfPump, RV, monthIN, yearIN As Integer
typeOfPump = 9
Dim outlfow, PEC As Double
outflow = 100
monthIN = 5
yearIN = 2008
Call getPEC(typeOfPump, outflow, PEC, RV)
Call setCEPCI(monthIN, yearIN, RV)
End Function
Any help is appreciated. Thank you in advance.
I think I solved my problem.
Looking at the VBA code
Dim typeOfPump, RV, monthIN, yearIN as Integer
for any reason declared only typeOfPump as integer, the rest were (when monitoring with implemented watching function of Excel) still variant. Writing
Dim typeOfPump as Integer
Dim RV as Integer
...
seems to solve the problem. Unfortunately, I cannot explain what is wrong with the first line.

Constructor for boolean expression, not the result

I have created a template class called binding_condition so that I can abstract permutations of conditions to a single object. Currently it works with passing a lambda and any variables that need to be checked, but I find the lambda to be misleading since it needs to capture the variables I am referencing.
for example:
bool someVal = true;
int h = 10;
double p = 99.8;
char c = 'C';
binding_condition<bool> bc(
[] (bool b)
{ return b; },
someVal);
binding_condition<bool, int> bc2(
[] (bool b, int i)
{ return b && (i > 9); },
someVal, h);
binding_condition<bool, int, double> bc3(
[] (bool b, int i, double d)
{ return b && (i > 9) && (d < 100); },
someVal, h, p);
binding_condition<bool, int, double, char> bc4(
[] (bool b, int i, double d, char c)
{ return b && (i > 9) && (d < 100) && c == 'C'; },
someVal, h, p, c);
This allows me to abstract some complex condition into a single name:
if (ThisComplexCondition) ...
else if (ThisOtherComplexCondition ...
...
However I am wondering if there is way, either with expression templates or some other method, to allow syntax like this:
binding_condition<bool, int, double> ComplexCondition = myClass.isTrue() && someThing.id < 100 && someDouble > 30.2;
I realize the above expression is not particularly creative, but consider this next one:
// analyzing chords in music to roman numeral notation, detect modulations, etc
// isChordRelatedToKey (the chord can be made from the current key
// isNeopolitan (the chord is a bii6 of the current key
// is major
// letter() is II/ii (ie C# major in C major is not a neapolitan, but Db major is)
// isSecondaryDominant
// chord is major
// chord is dominant of next chord (requires a new temporary key of next chord
// isSecondaryDiminished
// chord is diminished, and is the viio of the next chord
// all other forms of secondary, which means a ii/V in C major is A minor, which is also the vi of the key, and the iii/IV is also A minor
// nested secondary chords ie I - V - V/V - vii/V/V (C major, G major, D major, C# diminished)
// isModulation
// the current string of chords is not related to the current Key anymore
I want to implement some sort of statemachine, package these restrictions into objects, and simply check like:
if (isModulation) ...
if (isSecondary) ... // recursive
if (isChordNoRelation) ... // some chord that makes no sense from previous string
But baby steps at a time. Right now I just want to know if I can assign and store an expression, with whatever variables/functions being referenced in that expression.
Is this possible?
What is wrong with lambda closures, capturing the variables? You don't need to have them passed as parameters. In your first example, you can do this:
bool someVal = true;
int h = 10;
double p = 99.8;
char c = 'C';
auto bc4 = [&](){return someVal && (h > 9) && (p < 100) && c == 'C';};
//later:
if(bc4())
{
/*...*/
}
and for the econd example:
auto ComplexCondition = [&]() { return myClass.isTrue() && someThing.id < 100 && someDouble > 30.2;};
The lambda expressions prodice closures that capture the mentioned variables by reference, so the values are evaluated when the closure operator() is called:
bool someVal = true;
int h = 10;
double p = 99.8;
char c = 'C';
auto bc4 = [&](){return someVal && (h > 9) && (p < 100) && c == 'C';};
if(bc4()) //gives true
{ /* ... */ }
p *= 2;
if (bc4()) {} //gives false, since p > 100

Swig Python/C Pointer in struct to another struct

I'm using Player/Stage SWIG generated code from C and now I'm trying to access a structure where a value points to another structure. I wonder how I can extract the array of structures in python.
The C code looks like this:
/** #brief Localization device data. */
typedef struct
{
/** Device info; must be at the start of all device structures. */
playerc_device_t info;
/** Map dimensions (cells). */
int map_size_x, map_size_y;
/** Map scale (m/cell). */
double map_scale;
/** Next map tile to read. */
int map_tile_x, map_tile_y;
/** Map data (empty = -1, unknown = 0, occupied = +1). */
int8_t *map_cells;
/** The number of pending (unprocessed) sensor readings. */
int pending_count;
/** The timestamp on the last reading processed. */
double pending_time;
/** List of possible poses. */
int hypoth_count;
player_localize_hypoth_t *hypoths;
double mean[3];
double variance;
int num_particles;
playerc_localize_particle_t *particles;
} playerc_localize_t;
/** #brief Hypothesis format.
Since the robot pose may be ambiguous (i.e., the robot may at any
of a number of widely spaced locations), the #p localize interface is
capable of returning more that one hypothesis. */
typedef struct player_localize_hypoth
{
/** The mean value of the pose estimate (m, m, rad). */
player_pose2d_t mean;
/** The covariance matrix pose estimate (lower half, symmetric matrix)
(cov(xx) in m$^2$, cov(yy) in $^2$, cov(aa) in rad$^2$,
cov(xy), cov(ya), cov(xa) ). */
double cov[6];
/** The weight coefficient for linear combination (alpha) */
double alpha;
} player_localize_hypoth_t;
The code for python is automatically generated. I'm trying to access the elements in hypoths variable, how can I do this in python? I can access most of the variables. Below is the generated swig code...
class playerc_localize(_object):
__swig_setmethods__ = {}
__setattr__ = lambda self, name, value: _swig_setattr(self, playerc_localize, name, value)
__swig_getmethods__ = {}
__getattr__ = lambda self, name: _swig_getattr(self, playerc_localize, name)
__repr__ = _swig_repr
__swig_setmethods__["info"] = _playerc.playerc_localize_info_set
__swig_getmethods__["info"] = _playerc.playerc_localize_info_get
if _newclass:info = _swig_property(_playerc.playerc_localize_info_get, _playerc.playerc_localize_info_set)
__swig_setmethods__["map_size_x"] = _playerc.playerc_localize_map_size_x_set
__swig_getmethods__["map_size_x"] = _playerc.playerc_localize_map_size_x_get
if _newclass:map_size_x = _swig_property(_playerc.playerc_localize_map_size_x_get, _playerc.playerc_localize_map_size_x_set)
__swig_setmethods__["map_size_y"] = _playerc.playerc_localize_map_size_y_set
__swig_getmethods__["map_size_y"] = _playerc.playerc_localize_map_size_y_get
if _newclass:map_size_y = _swig_property(_playerc.playerc_localize_map_size_y_get, _playerc.playerc_localize_map_size_y_set)
__swig_setmethods__["map_scale"] = _playerc.playerc_localize_map_scale_set
__swig_getmethods__["map_scale"] = _playerc.playerc_localize_map_scale_get
if _newclass:map_scale = _swig_property(_playerc.playerc_localize_map_scale_get, _playerc.playerc_localize_map_scale_set)
__swig_setmethods__["map_tile_x"] = _playerc.playerc_localize_map_tile_x_set
__swig_getmethods__["map_tile_x"] = _playerc.playerc_localize_map_tile_x_get
if _newclass:map_tile_x = _swig_property(_playerc.playerc_localize_map_tile_x_get, _playerc.playerc_localize_map_tile_x_set)
__swig_setmethods__["map_tile_y"] = _playerc.playerc_localize_map_tile_y_set
__swig_getmethods__["map_tile_y"] = _playerc.playerc_localize_map_tile_y_get
if _newclass:map_tile_y = _swig_property(_playerc.playerc_localize_map_tile_y_get, _playerc.playerc_localize_map_tile_y_set)
__swig_setmethods__["map_cells"] = _playerc.playerc_localize_map_cells_set
__swig_getmethods__["map_cells"] = _playerc.playerc_localize_map_cells_get
if _newclass:map_cells = _swig_property(_playerc.playerc_localize_map_cells_get, _playerc.playerc_localize_map_cells_set)
__swig_setmethods__["pending_count"] = _playerc.playerc_localize_pending_count_set
__swig_getmethods__["pending_count"] = _playerc.playerc_localize_pending_count_get
if _newclass:pending_count = _swig_property(_playerc.playerc_localize_pending_count_get, _playerc.playerc_localize_pending_count_set)
__swig_setmethods__["pending_time"] = _playerc.playerc_localize_pending_time_set
__swig_getmethods__["pending_time"] = _playerc.playerc_localize_pending_time_get
if _newclass:pending_time = _swig_property(_playerc.playerc_localize_pending_time_get, _playerc.playerc_localize_pending_time_set)
__swig_setmethods__["hypoth_count"] = _playerc.playerc_localize_hypoth_count_set
__swig_getmethods__["hypoth_count"] = _playerc.playerc_localize_hypoth_count_get
if _newclass:hypoth_count = _swig_property(_playerc.playerc_localize_hypoth_count_get, _playerc.playerc_localize_hypoth_count_set)
__swig_setmethods__["hypoths"] = _playerc.playerc_localize_hypoths_set
__swig_getmethods__["hypoths"] = _playerc.playerc_localize_hypoths_get
if _newclass:hypoths = _swig_property(_playerc.playerc_localize_hypoths_get, _playerc.playerc_localize_hypoths_set)
__swig_setmethods__["mean"] = _playerc.playerc_localize_mean_set
__swig_getmethods__["mean"] = _playerc.playerc_localize_mean_get
if _newclass:mean = _swig_property(_playerc.playerc_localize_mean_get, _playerc.playerc_localize_mean_set)
__swig_setmethods__["variance"] = _playerc.playerc_localize_variance_set
__swig_getmethods__["variance"] = _playerc.playerc_localize_variance_get
if _newclass:variance = _swig_property(_playerc.playerc_localize_variance_get, _playerc.playerc_localize_variance_set)
__swig_setmethods__["num_particles"] = _playerc.playerc_localize_num_particles_set
__swig_getmethods__["num_particles"] = _playerc.playerc_localize_num_particles_get
if _newclass:num_particles = _swig_property(_playerc.playerc_localize_num_particles_get, _playerc.playerc_localize_num_particles_set)
__swig_setmethods__["particles"] = _playerc.playerc_localize_particles_set
__swig_getmethods__["particles"] = _playerc.playerc_localize_particles_get
if _newclass:particles = _swig_property(_playerc.playerc_localize_particles_get, _playerc.playerc_localize_particles_set)
def __init__(self, *args):
this = _playerc.new_playerc_localize(*args)
try: self.this.append(this)
except: self.this = this
def destroy(self): return _playerc.playerc_localize_destroy(self)
def subscribe(self, *args): return _playerc.playerc_localize_subscribe(self, *args)
def unsubscribe(self): return _playerc.playerc_localize_unsubscribe(self)
def set_pose(self, *args): return _playerc.playerc_localize_set_pose(self, *args)
def get_particles(self): return _playerc.playerc_localize_get_particles(self)
__swig_destroy__ = _playerc.delete_playerc_localize
__del__ = lambda self : None;
playerc_localize_swigregister = _playerc.playerc_localize_swigregister
playerc_localize_swigregister(playerc_localize)
Everything compiles in SWIG, but now my python code gives errors. I know that the alpha line may be wrong, but I get the same error for both lines:
LOC = playerc_localize(CON, 0)
if LOC.subscribe(PLAYERC_OPEN_MODE) != 0:
raise playerc_error_str()
CON.read()
# This should work right? If I omit the index,
# then I get the first value from the array.
print LOC.get_hypoth(0).alpha
print LOC.get_hypoth(1)
I get the following errors in python:
print LOC.get_hypoth(1).alpha
File "/usr/local/lib/python2.7/dist-packages/playerc.py", line 7413, in get_hypoth
return _playerc._playerc_localize_get_hypoth(self, index)
TypeError: in method '_playerc_localize_get_hypoth', argument 1 of type 'playerc_localize_t *'
PART II
I've come around another problem, again I'm trying to access some values but it doesn't work and I can't figure out whats wrong. I'm trying to access waypoints in the planner device:
PLN = playerc_planner(CON, 0)
if PLN.subscribe(PLAYERC_OPEN_MODE) != 0:
raise playerc_error_str()
# saves the waypoints in PLN.waypoints
PLN.get_waypoints()
# gives: <Swig Object of type 'double (*)[3]' at 0x38105d0>
# if i try accessing members of it using (0) or [0] or something I get errors
print PLN.waypoints
Now the related files and parts: in playerc.py
class playerc_planner(_object):
...
__swig_setmethods__["waypoints"] = _playerc.playerc_planner_waypoints_set
__swig_getmethods__["waypoints"] = _playerc.playerc_planner_waypoints_get
if _newclass:waypoints = _swig_property(_playerc.playerc_planner_waypoints_get, _playerc.playerc_planner_waypoints_set)
The part in playerc_wrap.i:
%header
%{
#define new_playerc_planner playerc_planner_create
#define del_playerc_planner playerc_planner_destroy
typedef playerc_planner_t playerc_planner;
%}
typedef struct
{
playerc_device info;
int path_valid;
int path_done;
double px, py, pa;
double gx, gy, ga;
double wx, wy, wa;
int curr_waypoint;
int waypoint_count;
double (*waypoints)[3];
%extend
{
playerc_planner (playerc_client *client, int index);
void destroy(void);
int subscribe (int access);
int unsubscribe (void);
int set_cmd_pose (double gx, double gy, double ga);
int get_waypoints (void);
int enable (int state);
}
} playerc_planner;
And the related part in playerc_wrap.h:
typedef struct
{
playerc_device_t info;
int path_valid;
int path_done;
double px, py, pa;
double gx, gy, ga;
double wx, wy, wa;
int curr_waypoint;
int waypoint_count;
double (*waypoints)[3];
} playerc_planner_t;
PLAYERC_EXPORT playerc_planner_t *playerc_planner_create(playerc_client_t *client, int index);
PLAYERC_EXPORT void playerc_planner_destroy(playerc_planner_t *device);
PLAYERC_EXPORT int playerc_planner_subscribe(playerc_planner_t *device, int access);
PLAYERC_EXPORT int playerc_planner_unsubscribe(playerc_planner_t *device);
PLAYERC_EXPORT int playerc_planner_set_cmd_pose(playerc_planner_t *device,
double gx, double gy, double ga);
PLAYERC_EXPORT int playerc_planner_get_waypoints(playerc_planner_t *device);
PLAYERC_EXPORT int playerc_planner_enable(playerc_planner_t *device, int state);
So I'm again lost in how to access the waypoints in this double(*)[3] variable, I tried some stuff but it all fails to compile in SWIG. Again thanks!
It looks like those dynamically sized arrays are not properly wrapped in libcplayer's SWIG interface file. The LOC.hypoths accessor will probably just give you the first element in the array, not any of the others.
I think the easiest thing to do would be to add something like this to playerc.i and regenerate the SWIG bindings:
%inline %{
player_localize_hypoth_t *_playerc_localize_get_hypoth(playerc_localize *localize, int index)
{
return &(localize->hypoths[index]);
}
%}
%extend playerc_localize {
%pythoncode %{
def get_hypoth(self, index):
return _playerc._playerc_localize_get_hypoth(self, index)
%}
}
Then you should be able to access element number n in Python with LOC.get_hypoth(n).
References:
SWIG 2.0 manual section 34.6
libplayerc/bindings/python/playerc.i
libplayerc/playerc.h
libplayerc/dev_localize.c
libplayerc/bindings/python/playerc_swig_parse.py
Notes:
The name of the struct is playerc_localize instead of playerc_localize_t because of the regular expressions applied to the interface file by the playerc_swig_parse.py script.
Part II
A similar problem. Again, there might be a cleverer way to do this, but this simple way is nice and clean and there's no need to try and make it any more complicated than it already is:
%inline %{
double _playerc_planner_get_waypoint_coord(playerc_planner *planner, int index, int coord)
{
return planner->waypoints[index][coord];
}
%}
%extend playerc_planner {
%pythoncode %{
def get_waypoint(self, index):
x = _playerc._playerc_planner_get_waypoint_coord(self, index, 0)
y = _playerc._playerc_planner_get_waypoint_coord(self, index, 1)
z = _playerc._playerc_planner_get_waypoint_coord(self, index, 2)
return (x, y, z)
%}
}
Then you should be able to access waypoint number n in Python like this:
(x, y, z) = PLN.get_waypoint(n)

BulkLoading the R* tree with spatialindex library

After successfully building the R* tree with spatial library inserting records one-by-one 2.5 million of times, I was trying to create the R* tree with bulkloading. I implemented the DBStream class to iteratively give the data to the BulkLoader. Essentially, it invokes the following method and prepared a Data (d variable in the code) object for the Bulkloader:
void DBStream::retrieveTuple() {
if (query.next()) {
hasNextBool = true;
int gid = query.value(0).toInt();
// allocate memory for bounding box
// this streets[gid].first returns bbox[4]
double* bbox = streets[gid].first;
// filling the bounding box values
bbox[0] = query.value(1).toDouble();
bbox[1] = query.value(2).toDouble();
bbox[2] = query.value(3).toDouble();
bbox[3] = query.value(4).toDouble();
rowId++;
r = new SpatialIndex::Region();
d = new SpatialIndex::RTree::Data((size_t) 0, (byte*) 0, *r, gid);
r->m_dimension = 2;
d->m_pData = 0;
d->m_dataLength = 0;
r->m_pLow = bbox;
r->m_pHigh = bbox + 2;
d->m_id = gid;
} else {
d = 0;
hasNextBool = false;
cout << "stream is finished d:" << d << endl;
}
}
I initialize the DBStream object and invoke the bulk loading in the following way:
// creating a main memory RTree
memStorage = StorageManager::createNewMemoryStorageManager();
size_t capacity = 1000;
bool bWriteThrough = false;
fileInMem = StorageManager
::createNewRandomEvictionsBuffer(*memStorage, capacity, bWriteThrough);
double fillFactor = 0.7;
size_t indexCapacity = 100;
size_t leafCapacity = 100;
size_t dimension = 2;
RTree::RTreeVariant rv = RTree::RV_RSTAR;
DBStream dstream();
tree = RTree::createAndBulkLoadNewRTree(SpatialIndex::RTree::BLM_STR, dstream,
*fileInMem,
fillFactor, indexCapacity,
leafCapacity, dimension, rv, indexIdentifier);
cout << "BulkLoading done" << endl;
Bulk loading calls my next() and hasNext() functions, retrieved my data, sorts it and then seg faults in the building phase. Any clues way? Yeah, the error is:
RTree::BulkLoader: Building level 0
terminate called after throwing an instance of 'Tools::IllegalArgumentException'
The problem supposedly lies in the memory allocation and a few bugs in the code (somewhat related to memory allocation too). Firstly one needs to properly assign the properties of the Data variable:
memcpy(data->m_region.m_pLow, bbox, 2 * sizeof(double));
memcpy(data->m_region.m_pHigh, bbox + 2, 2 * sizeof(double));
data->m_id = gid;
Second (and most importantly) getNext must return a new object with all the values:
RTree::Data *p = new RTree::Data(returnData->m_dataLength, returnData->m_pData,
returnData->m_region, returnData->m_id);
return returnData;
de-allocation of memory is done by RTree so no care is needed to be taken here.