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.

80 lignes
2.2KB

  1. /* Functions to compute 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 "npy_util.h"
  6. #include "bithacks.h"
  7. // Forward function declaration
  8. static PyObject *permanent(PyObject *self, PyObject *args);
  9. // Method list
  10. static PyMethodDef methods[] = {
  11. { "permanent", permanent, METH_VARARGS, "Computes the permanent of a numpy using the most appropriate method available"},
  12. { NULL, NULL, 0, NULL } // Sentinel
  13. };
  14. #if PY_MAJOR_VERSION >= 3
  15. static struct PyModuleDef cModPyDem =
  16. {
  17. PyModuleDef_HEAD_INIT,
  18. "permanent", "Computes the permanent of a numpy using the most appropriate method available",
  19. -1,
  20. methods
  21. };
  22. PyMODINIT_FUNC
  23. PyInit_permanent(void)
  24. {
  25. import_array();
  26. return PyModule_Create(&cModPyDem);
  27. }
  28. #else
  29. PyMODINIT_FUNC initpermanent(void) {
  30. (void) Py_InitModule("permanent", methods);
  31. import_array();
  32. }
  33. #endif
  34. // Ryser's algorithm
  35. static npy_complex128 ryser(PyArrayObject *submatrix) {
  36. int n = (int) PyArray_DIM(submatrix, 0);
  37. npy_complex128 rowsum, rowsumprod;
  38. npy_complex128 perm = complex_zero;
  39. int exp = 1 << n;
  40. int i, y, z;
  41. for (i=0; i<exp; ++i) {
  42. rowsumprod = complex_one;
  43. for (y=0; y<n; ++y) {
  44. rowsum = complex_zero;
  45. for (z=0; z<n; ++z) {
  46. if ((i & (1 << z)) != 0) { complex_inc(&rowsum, SM(z, y)); }
  47. }
  48. complex_multiply(&rowsumprod, rowsum);
  49. }
  50. complex_inc(&perm, complex_float_prod(rowsumprod, bitparity(i)));
  51. }
  52. if (n%2 == 1) { perm=complex_float_prod(perm, -1); }
  53. return perm;
  54. }
  55. // This is a wrapper which chooses the optimal permanent function
  56. static PyObject *permanent(PyObject *self, PyObject *args) {
  57. // Parse the input
  58. PyArrayObject *submatrix;
  59. if (!PyArg_ParseTuple(args, "O!", &PyArray_Type, &submatrix)) {return NULL;}
  60. if (!PyArray_ISCOMPLEX(submatrix)) {
  61. PyErr_SetString(PyExc_TypeError, "Array dtype must be `complex`.");
  62. return NULL;
  63. }
  64. // Compute the permanent
  65. npy_complex128 p = ryser(submatrix);
  66. return PyComplex_FromDoubles(p.real, p.imag);
  67. }