@@ -9,6 +9,7 @@ dimension=2 | |||||
real=np.ones((dimension, dimension)) | real=np.ones((dimension, dimension)) | ||||
imag=np.ones((dimension, dimension)) | imag=np.ones((dimension, dimension)) | ||||
submatrix=real+1j*imag | submatrix=real+1j*imag | ||||
print submatrix | |||||
print submatrix.dtype | |||||
p=lib.permanent(submatrix) | p=lib.permanent(submatrix) | ||||
print p |
@@ -0,0 +1,90 @@ | |||||
/* Computes the permanent, given a numpy array */ | |||||
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION | |||||
#include <Python.h> | |||||
#include <numpy/arrayobject.h> | |||||
#include <math.h> | |||||
#include <complex.h> | |||||
// 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<exp; ++i) { | |||||
prod.real = 1; prod.imag=0; | |||||
for (y=0; y<n; ++y) { // Rows | |||||
sum.real = 0; sum.imag = 0; | |||||
for (z=0; z<n; ++z) { // Columns | |||||
if ((i & (1 << z)) > 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); | |||||
} |
@@ -0,0 +1,68 @@ | |||||
/* Computes the permanent, given a numpy array */ | |||||
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION | |||||
#include <Python.h> | |||||
#include <numpy/arrayobject.h> | |||||
#include <math.h> | |||||
#include <complex.h> | |||||
// 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); | |||||
} |
@@ -1,68 +1,49 @@ | |||||
/* Computes the permanent, given a numpy array */ | /* Computes the permanent, given a numpy array */ | ||||
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION | #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION | ||||
#include <Python.h> | #include <Python.h> | ||||
#include <numpy/arrayobject.h> | #include <numpy/arrayobject.h> | ||||
#include <math.h> | #include <math.h> | ||||
#include <complex.h> | #include <complex.h> | ||||
// 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); | static PyObject *permanent(PyObject *self, PyObject *args); | ||||
// Boilerplate: method list. | |||||
static PyMethodDef methods[] = { | static PyMethodDef methods[] = { | ||||
{ "permanent", permanent, METH_VARARGS, "Compute the permanent"}, | { "permanent", permanent, METH_VARARGS, "Compute the permanent"}, | ||||
{ NULL, NULL, 0, NULL } /* Sentinel */ | { NULL, NULL, 0, NULL } /* Sentinel */ | ||||
}; | }; | ||||
// Boilerplate: Module initialization. | |||||
PyMODINIT_FUNC initpermanent(void) { | PyMODINIT_FUNC initpermanent(void) { | ||||
(void) Py_InitModule("permanent", methods); | (void) Py_InitModule("permanent", methods); | ||||
import_array(); | 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 | // 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); | int size = (int) PyArray_DIM(submatrix, 0); | ||||
npy_complex64 p; | |||||
p.real=0; p.imag=0; | |||||
int i, j; | int i, j; | ||||
for (i = 0; i < size; ++i) { | for (i = 0; i < size; ++i) { | ||||
for (j = 0; j < size; ++j) { | 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; | return p; | ||||
} | } | ||||
// This is basically a wrapper which chooses the optimal permanent function | // This is basically 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 input | ||||
PyArrayObject *submatrix; | 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); | return PyComplex_FromDoubles(p.real, p.imag); | ||||
} | } |