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.

70 lignes
2.5KB

  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. // Array access macros.
  6. #define SM(x0, x1) (*(npy_complex128*)((PyArray_DATA(submatrix) + \
  7. (x0) * PyArray_STRIDES(submatrix)[0] + \
  8. (x1) * PyArray_STRIDES(submatrix)[1])))
  9. #define SM_shape(x0) (int) PyArray_DIM(submatrix, x0)
  10. // Complex numbers
  11. static const npy_complex128 complex_zero = {.real=0, .imag=0};
  12. static const npy_complex128 complex_one = {.real=1, .imag=0};
  13. static void complex_inc(npy_complex128 a, npy_complex128 b) { a.real+=b.real; a.imag+=b.imag;}
  14. static npy_complex128 complex_prod(npy_complex128 a, npy_complex128 b) {
  15. npy_complex128 x;
  16. x.real = a.real*b.real+a.imag*b.imag;
  17. x.imag = a.real*b.imag+a.imag*b.real;
  18. return x;
  19. }
  20. // Boilerplate
  21. static PyObject *permanent(PyObject *self, PyObject *args); // Forward function declaration
  22. static PyMethodDef methods[] = { // Method list
  23. { "permanent", permanent, METH_VARARGS, "Compute the permanent"},
  24. { NULL, NULL, 0, NULL } /* Sentinel */
  25. };
  26. PyMODINIT_FUNC initpermanent(void) { // Module initialization
  27. (void) Py_InitModule("permanent", methods);
  28. import_array();
  29. }
  30. // Ryser's algorithm
  31. static npy_complex128 perm_ryser(PyArrayObject *submatrix) {
  32. int n = (int) PyArray_DIM(submatrix, 0);
  33. int i = 0; int z = 0; int y = 0;
  34. npy_complex128 prod;
  35. npy_complex128 perm = complex_zero;
  36. npy_complex128 sum = complex_zero;
  37. int exp = 1 << n;
  38. // Iterate over exponentially many index strings
  39. for (i=0; i<exp; ++i) {
  40. prod = complex_one;
  41. for (y=0; y<n; ++y) { // Rows
  42. sum = complex_zero;
  43. for (z=0; z<n; ++z) { // Columns
  44. if ((i & (1 << z)) > 0) { complex_inc(sum, SM(z,y)); }
  45. }
  46. prod = complex_prod(prod, sum);
  47. }
  48. if (i%2 == 0) {prod.real*=-1; prod.imag*=-1;}
  49. complex_inc(perm, prod);
  50. }
  51. if (i%2 == 0) {perm.real*=-1; perm.imag*=-1;}
  52. return perm;
  53. }
  54. // This is a wrapper which chooses the optimal permanent function
  55. static PyObject *permanent(PyObject *self, PyObject *args) {
  56. // Parse the input
  57. PyArrayObject *submatrix;
  58. if (!PyArg_ParseTuple(args, "O!", &PyArray_Type, &submatrix)) {return NULL;}
  59. // Compute the permanent
  60. npy_complex128 p = perm_ryser(submatrix);
  61. return PyComplex_FromDoubles(p.real, p.imag);
  62. }