0

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;
}
  • 1
    Possible duplicate of [convert numpy array to cython pointer](https://stackoverflow.com/questions/10718699/convert-numpy-array-to-cython-pointer) – DavidW Feb 22 '19 at 17:28
  • The question is, what your source and destination are. Are they numpy array? Something different with buffer protocol implemented? – ead Feb 22 '19 at 20:00

0 Answers0