Python C extension to compute the permanent.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

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