Python C extension to compute the permanent.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

50 lines
1.6KB

  1. /* Computes the permanent, given a numpy array */
  2. #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
  3. #include <Python.h>
  4. #include <numpy/arrayobject.h>
  5. #include <math.h>
  6. #include <complex.h>
  7. // Array access macros.
  8. #define SM(x0, x1) (*(npy_complex128*)((PyArray_DATA(submatrix) + \
  9. (x0) * PyArray_STRIDES(submatrix)[0] + \
  10. (x1) * PyArray_STRIDES(submatrix)[1])))
  11. #define SM_shape(x0) (int) PyArray_DIM(submatrix, x0)
  12. #define complex_inc(x0, x1) x0.real+=x1.real; x0.imag+=x1.imag;
  13. // Boilerplate: Forward function declaration, method list, module initialization
  14. static PyObject *permanent(PyObject *self, PyObject *args);
  15. static PyMethodDef methods[] = {
  16. { "permanent", permanent, METH_VARARGS, "Compute the permanent"},
  17. { NULL, NULL, 0, NULL } /* Sentinel */
  18. };
  19. PyMODINIT_FUNC initpermanent(void) {
  20. (void) Py_InitModule("permanent", methods);
  21. import_array();
  22. }
  23. // Ryser's algorithm takes exponential time
  24. // This just calculates the sum
  25. static npy_complex128 perm_ryser(PyArrayObject *submatrix) {
  26. npy_complex128 p = {.real=0, .imag=0};
  27. int size = (int) PyArray_DIM(submatrix, 0);
  28. int i, j;
  29. for (i = 0; i < size; ++i) {
  30. for (j = 0; j < size; ++j) {
  31. complex_inc(p, SM(0,0));
  32. }
  33. }
  34. return p;
  35. }
  36. // This is basically a wrapper which chooses the optimal permanent function
  37. static PyObject *permanent(PyObject *self, PyObject *args) {
  38. // Parse input
  39. PyArrayObject *submatrix;
  40. if (!PyArg_ParseTuple(args, "O!", &PyArray_Type, &submatrix)) {return NULL;}
  41. npy_complex128 p = perm_ryser(submatrix);
  42. return PyComplex_FromDoubles(p.real, p.imag);
  43. }