Passing Python array to c++ function with SWIG - c++

I have written a good bit of code in python and it works great. But now I'm scaling up the size of the problems that I'm analyzing and python is dreadfully slow. The slow part of the python code is
for i in range(0,H,1):
x1 = i - length
x2 = i + length
for j in range(0,W,1):
#print i, ',', j # check the limits
y1 = j - length
y2 = j + length
IntRed[i,j] = np.mean(RawRed[x1:x2,y1:y2])
With H and W equal to 1024 the function takes around 5 minutes to excute. I've written a simple c++ program/function that performs the same computation and it excutes in less than a second with the same data size.
double summ = 0;
double total_num = 0;
double tmp_num = 0 ;
int avesize = 2;
for( i = 0+avesize; i <X-avesize ;i++)
for(j = 0+avesize;j<Y-avesize;j++)
{
// loop through sub region of the matrix
// if the value is not zero add it to the sum
// and increment the counter.
for( int ii = -2; ii < 2; ii ++)
{
int iii = i + ii;
for( int jj = -2; jj < 2 ; jj ++ )
{
int jjj = j + jj;
tmp_num = gsl_matrix_get(m,iii,jjj);
if(tmp_num != 0 )
{
summ = summ + tmp_num;
total_num++;
}
}
}
gsl_matrix_set(Matrix_mean,i,j,summ/total_num);
summ = 0;
total_num = 0;
}
I have some other methods to perform on the 2D array. The one listed is a simple examples.
What I want to do is pass a python 2D array to my c++ function and return a 2D array back to python.
I've read a bit about swig, and have sereached pervious questions, and it seems like it's a possible solution. But I can't seem to figure out what I actually need to do.
Can I get any help? Thanks

You can use arrays as it is described here: Doc - 5.4.5 Arrays, the carray.i or std_vector.i from the SWIG library.
I find it easier to work with std::vector from the SWIG library std_vector.i to send a python list to a C++ SWIG extension. Though in your case where optimization matters, it may not be the optimal.
In your case you can define:
test.i
%module test
%{
#include "test.h"
%}
%include "std_vector.i"
namespace std {
%template(Line) vector < int >;
%template(Array) vector < vector < int> >;
}
void print_array(std::vector< std::vector < int > > myarray);
test.h
#ifndef TEST_H__
#define TEST_H__
#include <stdio.h>
#include <vector>
void print_array(std::vector< std::vector < int > > myarray);
#endif /* TEST_H__ */
test.cpp
#include "test.h"
void print_array(std::vector< std::vector < int > > myarray)
{
for (int i=0; i<2; i++)
for (int j=0; j<2; j++)
printf("[%d][%d] = [%d]\n", i, j, myarray[i][j]);
}
If you run the following python code (I used python 2.6.5), you can see that the C++ function can access the python list:
>>> import test
>>> a = test.Array()
>>> a = [[0, 1], [2, 3]]
>>> test.print_array(a)
[0][0] = [0]
[0][1] = [1]
[1][0] = [2]
[1][1] = [3]

Related

Looping Through Large, Multidimensional Array Using Rcpp

I am trying to create models that involve looping through large multidimensional arrays (ex: dimensions = 20 x 1000 x 60), which run very slow the way I code them in R. I downloaded Rcpp and have been trying to implement such a model, since C++ handles loops very well. Normally, I would write such a function in R as:
fun <- function(x,y,z){
f <- array(0, dim = c(18,50,10));
for (i in 1:18){
for (j in 1:50){
for (l in 1:10){
f[i,j,l] <- (i*j/10) + l;
}
}
}
return(f[x,y,z])
}
and as expected the function yields:
> fun(10,20,5)
[1] 25
This is what I thought the equivalent code in Rcpp should look like:
cppFunction('
double fun(int x, int y, int z){
int f[18][50][10] = {0};
for (int i = 1; i > 18; i++){
for (int j = 1; j > 50; j++){
for (int l = 1; l > 10; l++){
f[i][j][l] = (i * j/10) + l;
}
}
}
return f[x][y][z];
}
')
but I am getting 0's anytime I go to use the function.
> fun(10,20,5)
[1] 0
The actual models I'll be implementing use backward iteration, so I do need the arrays as part of the function. Alternatively, returning the array itself would also work for my purposes, but I haven't had luck with that either.
Any help would be sincerely appreciated.
Thanks
Remember that C++ is 0 indexed. You need to start your indexing at 0 rather than 1 as in R. You also need to make sure that your loops only continue while the value of i, j, and l are less than the dimensions of the array (so switch > for <. And your array needs to be an array of double, not int:
Rcpp::cppFunction('
double fun(int x, int y, int z){
double f[18][50][10] = {0};
for (int i = 0; i < 18; i++){
for (int j = 0; j < 50; j++){
for (int l = 0; l < 10; l++){
f[i][j][l] = (i * j/10) + l;
}
}
}
return f[x][y][z];
}
')
Testing gives:
fun(10, 20, 5)
#> [1] 25

Transforming a 2x4 array into a 4x2, and copying all the elemets

I've been going at this piece of code for the past couple of hours, and I haven't really figured out how I can do what I need to do, basically I'm trying to copy the elements of the 2x4 array into the 4x2
input array:
{1,3,5,7}
{2,4,6,8}
output desired:
{1,5}
{2,6}
{3,7}
{4,8}
what I've tried so far
int arr1[4][2];
int arr2[2][4];
int x,y;
for (x=0; x<4; x++){
for(y=0; y<2; y++){
arr1[x][y] = arr2[y][x];
}
}
Any suggestions on how i can approach the problem would be appreciated.
I am with #fern17 that you example is probably incorrect, and that you need a transpose which you implemented correctly.
If your example is correct, then you need to figure the function that maps input indexes to output indexes. This following would do but I don't know how that generalizes to other sizes:
#include <stdio.h>
int main() {
int src[2][4] = {
{1,3,5,7},
{2,4,6,8}
};
int dst[4][2];
for(int i = 0; i < 4; i++) {
for(int j = 0; j < 2; j++) {
dst[i][j] = src[i % 2][2 * j + i / 2];
printf("%d%s", dst[i][j], j + 1 < 2 ? ", " : "\n");
}
}
}
which would give you this output:
1, 5
2, 6
3, 7
4, 8

I need 2 for loops to fill a matrix in Eigen but I can fill it with only 1 for loop in Matlab - can I get rid of the extra for loop?

I am filling an Eigen matrix with the following code:
int M = 3;
int N = 4;
MatrixXd A(M, N);
double res = sin(4);
for (int i = 0; i < M; i++) {
for (int j = 0; j < N; j++) {
A(i, j) = sin(i+j);
}
}
In Matlab I only need 1 for loop to do the same thing using vectorization:
M = 3;
N = 4;
N_Vec = 0:(N-1);
A = zeros(M,N);
for i=1:M
A(i,:) = sin((i-1)+N_Vec);
end
Is it possible to do something similar in C++/Eigen so that I can get rid of one of the for loops? If it is possible to somehow get rid of both for loops that would be even better. Is that possible?
Using a NullaryExpr you can do this with zero (manual) loops in Eigen:
Eigen::MatrixXd A = Eigen::MatrixXd::NullaryExpr(M, N,
[](Eigen::Index i, Eigen::Index j) {return std::sin(i+j);});
When compiled with optimization this is not necessarily faster than the manual two-loop version (and without optimization it could even be slower).
You can write int or long instead of Eigen::Index, if that is more readable ...

Merging 3 sets of arrays

I am consider new to c++ and I have facing some doubt on merging three set of arrays.
For example:
x = 2,3,1,4,5
y = 1,3,5,7,9
z = 3,5,4,6,1
I would like to merge them into:
w = 2,1,3,3,3,5,1,5,4,4,7,6,5,9,1
I have been searching through Google. However what I get is how to merge the arrays and put them in an ascending orders.
What I actually needed:
1st from x, 1st from y, 1st from z, 2nd from x, 2nd from y, 2nd from z ............ 5th from z
Thank you very much!
It's just a matter of making a loop with i from 0 to 4 and mapping every i to the corresponding element of the array w.
Here's the skeleton of the algorithm:
std::array<int, 5> x, y, z;
std::array<int, 15> w;
for (int i = 0; i < 5; i++) {
w[i*3] = x[i];
w[i*3+1] = y[i];
w[i*3+2] = z[i];
}
And here's the working example.
If you are using std::vector, then the algorithm gets a little bit trickier. You'll need to find the maximum size, using std::max for example, and perform a loop based on that value. Then whenever a vector is empty, you'll need to skip it. Here's the skeleton again:
std::vector<int> x, y, z;
std::vector<int> w;
std::size_t max = std::max({x.size(), y.size(), z.size()});
for (std::size_t i = 0; i < max; i++) {
if (x.size() > i) w.push_back(x[i]);
if (y.size() > i) w.push_back(y[i]);
if (z.size() > i) w.push_back(z[i]);
}
As long as you know the size of x, y, z, and w, this is a fairly straightforward solution.
In C++, unlike other higher-level programming languages, most array-based operations are not handled by special functions. Instead, the user is required to write a loop to do this task themselves.
In your case, assuming that x, y, z, and w are all declared and defined properly, the most straightforward way is probably using a for loop, as follows:
int i;
for(i=0; i<(size_of_x); i++){
w[i*3] = x[i];
w[i*3+1] = y[i];
w[i*3+2] = z[i];
}
Notice that the variable size_of_x will need to be defined for this to work.
You might also want to consider the fact that the lengths of the arrays may differ.
int *resArray;
int totalLength = sizeof(x) + sizeof(y) + sizeof(z);
int maxLength = max(sizeof(x), max(sizeof(y), sizeof(x));
resArray = new int[totalLength];
int j = 0;
for (int i = 0; i < maxLength; i++)
{
if (i < sizeof(x))
{
resArray[j] = x[i];
j++
}
if (i < sizeof(y))
{
resArray[j] = y[i];
j++
}
if (i < sizeof(z))
{
resArray[j] = z[i];
j++
}
}
It'll not be the fastest solution, but it can handle arrays of different lengths.
Edit:
Do not forget to free the memory you've allocated using new.
And you can consider the use of std::vector
How about some C++11?
#include <vector>
int main()
{
std::vector<int> x {2,3,1,4,5}, y {1,3,5,7,9}, z {3,5,4,6,1};
std::vector<int> w;
for (int i {}; i < x.size(); ++i)
{
w.insert(v.end(),{x[i], y[i], z[i]});
}
}

C++ - dynamic pointer of array

first i would like to say i am Newbie in C++.
As part of my master thesis i am writing a program in C++ which also get as parameters the variables m and d (both integers). Were d is the power of 2 (this means 2^d elements). Parameter m define the number of possible interactions between one element and the total group (2^d elements).
The number of possible interactions is computed as following:
\kappa = \sum_{i=0}^m\binom{d}{i}
(at present i generate vector of vectors for 2^d x \kappa, but my Prof. would like me to create different statistics to different m's. My first though was to to generate a dynamic array of m arrays of different sizes... Then i though of defining a 3-dim array with the biggest needed 2d array, but also program speed is important (e.g d = 20).
i would like to ask for your advice how to define such kind of dynamic array that will also be fast.
Regards
Use boost mutlidimensional arrays
http://www.boost.org/doc/libs/1_41_0/libs/multi_array/doc/index.html
for example look at this code. This is very easy
#include "boost/multi_array.hpp"
#include <cassert>
int main () {
// Create a 3D array that is 3 x 4 x 2
typedef boost::multi_array<double, 3> array_type;
typedef array_type::index index;
array_type A(boost::extents[3][4][2]);
// Assign values to the elements
int values = 0;
for(index i = 0; i != 3; ++i)
for(index j = 0; j != 4; ++j)
for(index k = 0; k != 2; ++k)
A[i][j][k] = values++;
// Verify values
int verify = 0;
for(index i = 0; i != 3; ++i)
for(index j = 0; j != 4; ++j)
for(index k = 0; k != 2; ++k)
assert(A[i][j][k] == verify++);
return 0;
}