I am trying to wrap a C++ library using Cython. In .pyx the relevant definitions are
void Multinomial_doubleSource "Multinomial"(int32_t* destination, double* source, int32_t n, int colors)
void Multinomial_intSource "Multinomial"(int32_t* destination, int32_t* source, int32_t n, int colors)
In .pyx file relevant implementation is:
def Multinomial(self, destination, source, n, colors):
if isinstance(source[0], int):
self._stoc1ptr.Multinomial_intSource(<int32_t*>destination, <double*>source, n, colors)
if isinstance(source[0], float):
self._stoc1ptr.Multinomial_doubleSource(<int32_t*>destination, <int32_t*>source, n, colors)
When I try to compile, I receive the error Python objects cannot be cast to pointers of primitive types
. If I do
def Multinomial(self, destination, source, n, colors):
if isinstance(source[0], int):
self._stoc1ptr.Multinomial_intSource(&destination, &source, n, colors)
if isinstance(source[0], float):
self._stoc1ptr.Multinomial_doubleSource(&destination, &source, n, colors)
I got the error Cannot take address of Python variable 'destination'
.
What is the proper way to wrap a C++ function where it takes pointers as its argument?
Implementation for Multinomial
in the .cpp file is
void StochasticLib1::Multinomial(int32_t *destination, double *source, int32_t n, int colors)
{
/*
This function generates a vector of random variates, each with the
binomial distribution.
The multinomial distribution is the distribution you get when drawing
balls from an urn with more than two colors, with replacement.
Parameters:
destination: An output array to receive the number of balls of each
color. Must have space for at least 'colors' elements.
source: An input array containing the probability or fraction
of each color in the urn. Must have 'colors' elements.
All elements must be non-negative. The sum doesn't have
to be 1, but the sum must be positive.
n: The number of balls drawn from the urn.
colors: The number of possible colors.
*/
double s, sum;
int32_t x;
int i;
if (n < 0 || colors < 0)
FatalError("Parameter negative in multinomial function");
if (colors == 0)
return;
// compute sum of probabilities
for (i = 0, sum = 0; i < colors; i++)
{
s = source[i];
if (s < 0)
FatalError("Parameter negative in multinomial function");
sum += s;
}
if (sum == 0 && n > 0)
FatalError("Zero sum in multinomial function");
for (i = 0; i < colors - 1; i++)
{
// generate output by calling binomial (colors-1) times
s = source[i];
if (sum <= s)
{
// this fixes two problems:
// 1. prevent division by 0 when sum = 0
// 2. prevent s/sum getting bigger than 1 in case of rounding errors
x = n;
}
else
{
x = Binomial(n, s / sum);
}
n -= x;
sum -= s;
destination[i] = x;
}
// get the last one
destination[i] = n;
}
void StochasticLib1::Multinomial(int32_t *destination, int32_t *source, int32_t n, int colors)
{
// same as above, with integer source
int32_t x, p, sum;
int i;
if (n < 0 || colors < 0)
FatalError("Parameter negative in multinomial function");
if (colors == 0)
return;
// compute sum of probabilities
for (i = 0, sum = 0; i < colors; i++)
{
p = source[i];
if (p < 0)
FatalError("Parameter negative in multinomial function");
sum += p;
}
if (sum == 0 && n > 0)
FatalError("Zero sum in multinomial function");
for (i = 0; i < colors - 1; i++)
{
// generate output by calling binomial (colors-1) times
if (sum == 0)
{
destination[i] = 0;
continue;
}
p = source[i];
x = Binomial(n, (double)p / sum);
n -= x;
sum -= p;
destination[i] = x;
}
// get the last one
destination[i] = n;
}