diff --git a/run-tests.py b/run-tests.py index d907ec8..b0ab93f 100644 --- a/run-tests.py +++ b/run-tests.py @@ -9,6 +9,7 @@ dimension=2 real=np.ones((dimension, dimension)) imag=np.ones((dimension, dimension)) submatrix=real+1j*imag -print submatrix +print submatrix.dtype p=lib.permanent(submatrix) +print p diff --git a/src/old.c b/src/old.c new file mode 100644 index 0000000..da69ce7 --- /dev/null +++ b/src/old.c @@ -0,0 +1,90 @@ +/* Computes the permanent, given a numpy array */ + +#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION +#include +#include +#include +#include + +// Globals +PyArrayObject *submatrix; +int size; + +// Boilerplate: Forward function declaration. +static PyObject *permanent(PyObject *self, PyObject *args); + +// Boilerplate: method list. +static PyMethodDef methods[] = { + { "permanent", permanent, METH_VARARGS, "Compute the permanent"}, + { NULL, NULL, 0, NULL } /* Sentinel */ +}; + +// Boilerplate: Module initialization. +PyMODINIT_FUNC initpermanent(void) { + (void) Py_InitModule("permanent", methods); + import_array(); +} + +// Array access macros. +#define SM(x0, x1) (*(npy_complex64*)((PyArray_DATA(submatrix) + \ + (x0) * PyArray_STRIDES(submatrix)[0] + \ + (x1) * PyArray_STRIDES(submatrix)[1]))) +#define SM_shape(x0) (int) PyArray_DIM(submatrix, x0) + +// Ryser's algorithm takes exponential time +// The advantage over naive perm() only kicks in at around 6x6 matrices +// TODO: should take matrix as arg really, get rid of consts +static npy_complex64 perm_ryser(void) { + npy_complex64 p; + p.real=0; p.imag=0; + int i, j; + for (i = 0; i < size; ++i) { + for (j = 0; j < size; ++j) { + npy_complex64 q = SM(0,0); + p.real += q.real; + p.imag += q.imag; + } + } + return p; +} + +void TODO(void) { + int n = size; + int i = 0; int z = 0; int y = 0; + npy_complex64 perm; perm.real=0; perm.imag=0; + npy_complex64 prod; + npy_complex64 sum; sum.real=0; sum.imag=0; + npy_complex64 element; + int exp=pow(2.0, n); + + // Iterate over exponentially many index strings + for (i=0; i 0) { sum.real += SM(z,y).real; sum.imag += SM(z,y).imag; } + } + prod = c_prod(prod, sum); + } + perm += parity(i) * prod; + } + return c_prod((pow(-1,n)), perm); +} + +// This is basically a wrapper which chooses the optimal permanent function +static PyObject *permanent(PyObject *self, PyObject *args) { + // Parse input + if (!PyArg_ParseTuple(args, "O!", &PyArray_Type, &submatrix)) { + return NULL; + } + + // Check for stupid mistakes + if ((int) PyArray_NDIM(submatrix) != 2) {return NULL;} + size = (int) PyArray_DIM(submatrix, 0); + if ((int) PyArray_DIM(submatrix, 1) != size) {return NULL;} + + // Get the permanent, convert to a python object, and return + npy_complex64 p = perm_ryser(); + return PyComplex_FromDoubles(p.real,p.imag); +} diff --git a/src/oldold.c b/src/oldold.c new file mode 100644 index 0000000..ae162ab --- /dev/null +++ b/src/oldold.c @@ -0,0 +1,68 @@ +/* Computes the permanent, given a numpy array */ + +#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION +#include +#include +#include +#include + +// Globals + +// Boilerplate: Forward function declaration. +static PyObject *permanent(PyObject *self, PyObject *args); + +// Boilerplate: method list. +static PyMethodDef methods[] = { + { "permanent", permanent, METH_VARARGS, "Compute the permanent"}, + { NULL, NULL, 0, NULL } /* Sentinel */ +}; + +// Boilerplate: Module initialization. +PyMODINIT_FUNC initpermanent(void) { + (void) Py_InitModule("permanent", methods); + import_array(); +} + +// Array access macros. +#define SM(x0, x1) (*(npy_complex64*)((PyArray_DATA(submatrix) + \ + (x0) * PyArray_STRIDES(submatrix)[0] + \ + (x1) * PyArray_STRIDES(submatrix)[1]))) +#define SM_shape(x0) (int) PyArray_DIM(submatrix, x0) + +// Ryser's algorithm takes exponential time +// The advantage over naive perm() only kicks in at around 6x6 matrices +// TODO: should take matrix as arg really, get rid of consts +static npy_complex64 perm_ryser(PyArrayObject *submatrix) { + int size = (int) PyArray_DIM(submatrix, 0); + npy_complex64 p; + p.real=0; p.imag=0; + int i, j; + for (i = 0; i < size; ++i) { + for (j = 0; j < size; ++j) { + npy_complex64 q = SM(i,j); + printf("real: %f\n", q.real); + printf("imag: %f\n", q.imag); + p.real += q.real; + p.imag += q.imag; + } + } + return p; +} + +// This is basically a wrapper which chooses the optimal permanent function +static PyObject *permanent(PyObject *self, PyObject *args) { + // Parse input + PyArrayObject *submatrix; + if (!PyArg_ParseTuple(args, "O!", &PyArray_Type, &submatrix)) { + return NULL; + } + + // Check for stupid mistakes + if ((int) PyArray_NDIM(submatrix) != 2) {return NULL;} + int size = (int) PyArray_DIM(submatrix, 0); + if ((int) PyArray_DIM(submatrix, 1) != size) {return NULL;} + + // Get the permanent, convert to a python object, and return + npy_complex64 p = perm_ryser(submatrix); + return PyComplex_FromDoubles(p.real, p.imag); +} diff --git a/src/permanent.c b/src/permanent.c index ae162ab..76236d3 100644 --- a/src/permanent.c +++ b/src/permanent.c @@ -1,68 +1,49 @@ /* Computes the permanent, given a numpy array */ - #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION #include #include #include #include -// Globals +// Array access macros. +#define SM(x0, x1) (*(npy_complex128*)((PyArray_DATA(submatrix) + \ + (x0) * PyArray_STRIDES(submatrix)[0] + \ + (x1) * PyArray_STRIDES(submatrix)[1]))) +#define SM_shape(x0) (int) PyArray_DIM(submatrix, x0) +#define complex_inc(x0, x1) x0.real+=x1.real; x0.imag+=x1.imag; -// Boilerplate: Forward function declaration. +// Boilerplate: Forward function declaration, method list, module initialization static PyObject *permanent(PyObject *self, PyObject *args); - -// Boilerplate: method list. static PyMethodDef methods[] = { { "permanent", permanent, METH_VARARGS, "Compute the permanent"}, { NULL, NULL, 0, NULL } /* Sentinel */ }; - -// Boilerplate: Module initialization. PyMODINIT_FUNC initpermanent(void) { (void) Py_InitModule("permanent", methods); import_array(); } -// Array access macros. -#define SM(x0, x1) (*(npy_complex64*)((PyArray_DATA(submatrix) + \ - (x0) * PyArray_STRIDES(submatrix)[0] + \ - (x1) * PyArray_STRIDES(submatrix)[1]))) -#define SM_shape(x0) (int) PyArray_DIM(submatrix, x0) - // Ryser's algorithm takes exponential time -// The advantage over naive perm() only kicks in at around 6x6 matrices -// TODO: should take matrix as arg really, get rid of consts -static npy_complex64 perm_ryser(PyArrayObject *submatrix) { +// This just calculates the sum +static npy_complex128 perm_ryser(PyArrayObject *submatrix) { + npy_complex128 p = {.real=0, .imag=0}; int size = (int) PyArray_DIM(submatrix, 0); - npy_complex64 p; - p.real=0; p.imag=0; int i, j; for (i = 0; i < size; ++i) { for (j = 0; j < size; ++j) { - npy_complex64 q = SM(i,j); - printf("real: %f\n", q.real); - printf("imag: %f\n", q.imag); - p.real += q.real; - p.imag += q.imag; + complex_inc(p, SM(0,0)); } } return p; } + // This is basically a wrapper which chooses the optimal permanent function static PyObject *permanent(PyObject *self, PyObject *args) { // Parse input PyArrayObject *submatrix; - if (!PyArg_ParseTuple(args, "O!", &PyArray_Type, &submatrix)) { - return NULL; - } - - // Check for stupid mistakes - if ((int) PyArray_NDIM(submatrix) != 2) {return NULL;} - int size = (int) PyArray_DIM(submatrix, 0); - if ((int) PyArray_DIM(submatrix, 1) != size) {return NULL;} + if (!PyArg_ParseTuple(args, "O!", &PyArray_Type, &submatrix)) {return NULL;} - // Get the permanent, convert to a python object, and return - npy_complex64 p = perm_ryser(submatrix); + npy_complex128 p = perm_ryser(submatrix); return PyComplex_FromDoubles(p.real, p.imag); }