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.

69 lines
2.1KB

  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. // Globals
  8. // Boilerplate: Forward function declaration.
  9. static PyObject *permanent(PyObject *self, PyObject *args);
  10. // Boilerplate: method list.
  11. static PyMethodDef methods[] = {
  12. { "permanent", permanent, METH_VARARGS, "Compute the permanent"},
  13. { NULL, NULL, 0, NULL } /* Sentinel */
  14. };
  15. // Boilerplate: Module initialization.
  16. PyMODINIT_FUNC initpermanent(void) {
  17. (void) Py_InitModule("permanent", methods);
  18. import_array();
  19. }
  20. // Array access macros.
  21. #define SM(x0, x1) (*(npy_complex64*)((PyArray_DATA(submatrix) + \
  22. (x0) * PyArray_STRIDES(submatrix)[0] + \
  23. (x1) * PyArray_STRIDES(submatrix)[1])))
  24. #define SM_shape(x0) (int) PyArray_DIM(submatrix, x0)
  25. // Ryser's algorithm takes exponential time
  26. // The advantage over naive perm() only kicks in at around 6x6 matrices
  27. // TODO: should take matrix as arg really, get rid of consts
  28. static npy_complex64 perm_ryser(PyArrayObject *submatrix) {
  29. int size = (int) PyArray_DIM(submatrix, 0);
  30. npy_complex64 p;
  31. p.real=0; p.imag=0;
  32. int i, j;
  33. for (i = 0; i < size; ++i) {
  34. for (j = 0; j < size; ++j) {
  35. npy_complex64 q = SM(i,j);
  36. printf("real: %f\n", q.real);
  37. printf("imag: %f\n", q.imag);
  38. p.real += q.real;
  39. p.imag += q.imag;
  40. }
  41. }
  42. return p;
  43. }
  44. // This is basically a wrapper which chooses the optimal permanent function
  45. static PyObject *permanent(PyObject *self, PyObject *args) {
  46. // Parse input
  47. PyArrayObject *submatrix;
  48. if (!PyArg_ParseTuple(args, "O!", &PyArray_Type, &submatrix)) {
  49. return NULL;
  50. }
  51. // Check for stupid mistakes
  52. if ((int) PyArray_NDIM(submatrix) != 2) {return NULL;}
  53. int size = (int) PyArray_DIM(submatrix, 0);
  54. if ((int) PyArray_DIM(submatrix, 1) != size) {return NULL;}
  55. // Get the permanent, convert to a python object, and return
  56. npy_complex64 p = perm_ryser(submatrix);
  57. return PyComplex_FromDoubles(p.real, p.imag);
  58. }