| @@ -13,36 +13,32 @@ | |||
| static const npy_complex128 complex_zero = {.real=0, .imag=0}; | |||
| static const npy_complex128 complex_one = {.real=1, .imag=0}; | |||
| static void complex_inc(npy_complex128 a, npy_complex128 b) { a.real+=b.real; a.imag+=b.imag;} | |||
| static npy_complex128 complex_mult(npy_complex128 a, npy_complex128 b) { | |||
| static npy_complex128 complex_prod(npy_complex128 a, npy_complex128 b) { | |||
| npy_complex128 x; | |||
| x.real = a.real*b.real+a.imag*b.imag; | |||
| x.imag = a.real*b.imag+a.imag*b.real; | |||
| return x; | |||
| } | |||
| // Boilerplate: Forward function declaration, method list, module initialization | |||
| static PyObject *permanent(PyObject *self, PyObject *args); | |||
| static PyMethodDef methods[] = { | |||
| // Boilerplate | |||
| static PyObject *permanent(PyObject *self, PyObject *args); // Forward function declaration | |||
| static PyMethodDef methods[] = { // Method list | |||
| { "permanent", permanent, METH_VARARGS, "Compute the permanent"}, | |||
| { NULL, NULL, 0, NULL } /* Sentinel */ | |||
| }; | |||
| PyMODINIT_FUNC initpermanent(void) { | |||
| PyMODINIT_FUNC initpermanent(void) { // Module initialization | |||
| (void) Py_InitModule("permanent", methods); | |||
| import_array(); | |||
| } | |||
| // The parity | |||
| /*static int parity(int x) { return 0; }*/ | |||
| // Ryser's algorithm takes exponential time | |||
| // This just calculates the sum | |||
| // Ryser's algorithm | |||
| static npy_complex128 perm_ryser(PyArrayObject *submatrix) { | |||
| int n = (int) PyArray_DIM(submatrix, 0); | |||
| int i = 0; int z = 0; int y = 0; | |||
| npy_complex128 prod; | |||
| npy_complex128 perm = complex_zero; | |||
| npy_complex128 sum = complex_zero; | |||
| int exp=1 << n; //TODO: use a shift operator | |||
| int exp = 1 << n; | |||
| // Iterate over exponentially many index strings | |||
| for (i=0; i<exp; ++i) { | |||
| @@ -52,21 +48,22 @@ static npy_complex128 perm_ryser(PyArrayObject *submatrix) { | |||
| for (z=0; z<n; ++z) { // Columns | |||
| if ((i & (1 << z)) > 0) { complex_inc(sum, SM(z,y)); } | |||
| } | |||
| prod = complex_mult(prod, sum); | |||
| prod = complex_prod(prod, sum); | |||
| } | |||
| /*complex_add(perm, parity(i) * prod);*/ | |||
| if (i%2 == 0) {prod.real*=-1; prod.imag*=-1;} | |||
| complex_inc(perm, prod); | |||
| } | |||
| /*return c_prod((pow(-1,n)), perm); #TODO power is fucked*/ | |||
| if (i%2 == 0) {perm.real*=-1; perm.imag*=-1;} | |||
| return perm; | |||
| } | |||
| // This is basically a wrapper which chooses the optimal permanent function | |||
| // This is a wrapper which chooses the optimal permanent function | |||
| static PyObject *permanent(PyObject *self, PyObject *args) { | |||
| // Parse input | |||
| // Parse the input | |||
| PyArrayObject *submatrix; | |||
| if (!PyArg_ParseTuple(args, "O!", &PyArray_Type, &submatrix)) {return NULL;} | |||
| // Compute the permanent | |||
| npy_complex128 p = perm_ryser(submatrix); | |||
| return PyComplex_FromDoubles(p.real, p.imag); | |||
| } | |||