| @@ -13,36 +13,32 @@ | |||||
| static const npy_complex128 complex_zero = {.real=0, .imag=0}; | static const npy_complex128 complex_zero = {.real=0, .imag=0}; | ||||
| static const npy_complex128 complex_one = {.real=1, .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 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; | npy_complex128 x; | ||||
| x.real = a.real*b.real+a.imag*b.imag; | x.real = a.real*b.real+a.imag*b.imag; | ||||
| x.imag = a.real*b.imag+a.imag*b.real; | x.imag = a.real*b.imag+a.imag*b.real; | ||||
| return x; | 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"}, | { "permanent", permanent, METH_VARARGS, "Compute the permanent"}, | ||||
| { NULL, NULL, 0, NULL } /* Sentinel */ | { NULL, NULL, 0, NULL } /* Sentinel */ | ||||
| }; | }; | ||||
| PyMODINIT_FUNC initpermanent(void) { | |||||
| PyMODINIT_FUNC initpermanent(void) { // Module initialization | |||||
| (void) Py_InitModule("permanent", methods); | (void) Py_InitModule("permanent", methods); | ||||
| import_array(); | 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) { | static npy_complex128 perm_ryser(PyArrayObject *submatrix) { | ||||
| int n = (int) PyArray_DIM(submatrix, 0); | int n = (int) PyArray_DIM(submatrix, 0); | ||||
| int i = 0; int z = 0; int y = 0; | int i = 0; int z = 0; int y = 0; | ||||
| npy_complex128 prod; | npy_complex128 prod; | ||||
| npy_complex128 perm = complex_zero; | npy_complex128 perm = complex_zero; | ||||
| npy_complex128 sum = 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 | // Iterate over exponentially many index strings | ||||
| for (i=0; i<exp; ++i) { | for (i=0; i<exp; ++i) { | ||||
| @@ -52,21 +48,22 @@ static npy_complex128 perm_ryser(PyArrayObject *submatrix) { | |||||
| for (z=0; z<n; ++z) { // Columns | for (z=0; z<n; ++z) { // Columns | ||||
| if ((i & (1 << z)) > 0) { complex_inc(sum, SM(z,y)); } | 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); | 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; | 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) { | static PyObject *permanent(PyObject *self, PyObject *args) { | ||||
| // Parse input | |||||
| // Parse the input | |||||
| PyArrayObject *submatrix; | PyArrayObject *submatrix; | ||||
| if (!PyArg_ParseTuple(args, "O!", &PyArray_Type, &submatrix)) {return NULL;} | if (!PyArg_ParseTuple(args, "O!", &PyArray_Type, &submatrix)) {return NULL;} | ||||
| // Compute the permanent | |||||
| npy_complex128 p = perm_ryser(submatrix); | npy_complex128 p = perm_ryser(submatrix); | ||||
| return PyComplex_FromDoubles(p.real, p.imag); | return PyComplex_FromDoubles(p.real, p.imag); | ||||
| } | } | ||||