|
@@ -2,15 +2,23 @@ |
|
|
#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 <complex.h> |
|
|
|
|
|
|
|
|
|
|
|
// Array access macros. |
|
|
// Array access macros. |
|
|
#define SM(x0, x1) (*(npy_complex128*)((PyArray_DATA(submatrix) + \ |
|
|
#define SM(x0, x1) (*(npy_complex128*)((PyArray_DATA(submatrix) + \ |
|
|
(x0) * PyArray_STRIDES(submatrix)[0] + \ |
|
|
(x0) * PyArray_STRIDES(submatrix)[0] + \ |
|
|
(x1) * PyArray_STRIDES(submatrix)[1]))) |
|
|
(x1) * PyArray_STRIDES(submatrix)[1]))) |
|
|
#define SM_shape(x0) (int) PyArray_DIM(submatrix, x0) |
|
|
#define SM_shape(x0) (int) PyArray_DIM(submatrix, x0) |
|
|
#define complex_inc(x0, x1) x0.real+=x1.real; x0.imag+=x1.imag; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Complex numbers |
|
|
|
|
|
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) { |
|
|
|
|
|
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 |
|
|
// Boilerplate: Forward function declaration, method list, module initialization |
|
|
static PyObject *permanent(PyObject *self, PyObject *args); |
|
|
static PyObject *permanent(PyObject *self, PyObject *args); |
|
@@ -23,21 +31,36 @@ PyMODINIT_FUNC initpermanent(void) { |
|
|
import_array(); |
|
|
import_array(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// The parity |
|
|
|
|
|
/*static int parity(int x) { return 0; }*/ |
|
|
|
|
|
|
|
|
// Ryser's algorithm takes exponential time |
|
|
// Ryser's algorithm takes exponential time |
|
|
// This just calculates the sum |
|
|
// This just calculates the sum |
|
|
static npy_complex128 perm_ryser(PyArrayObject *submatrix) { |
|
|
static npy_complex128 perm_ryser(PyArrayObject *submatrix) { |
|
|
npy_complex128 p = {.real=0, .imag=0}; |
|
|
|
|
|
int size = (int) PyArray_DIM(submatrix, 0); |
|
|
|
|
|
int i, j; |
|
|
|
|
|
for (i = 0; i < size; ++i) { |
|
|
|
|
|
for (j = 0; j < size; ++j) { |
|
|
|
|
|
complex_inc(p, SM(0,0)); |
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|
|
|
|
|
// Iterate over exponentially many index strings |
|
|
|
|
|
for (i=0; i<exp; ++i) { |
|
|
|
|
|
prod = complex_one; |
|
|
|
|
|
for (y=0; y<n; ++y) { // Rows |
|
|
|
|
|
sum = complex_zero; |
|
|
|
|
|
for (z=0; z<n; ++z) { // Columns |
|
|
|
|
|
if ((i & (1 << z)) > 0) { complex_inc(sum, SM(z,y)); } |
|
|
|
|
|
} |
|
|
|
|
|
prod = complex_mult(prod, sum); |
|
|
|
|
|
} |
|
|
|
|
|
/*complex_add(perm, parity(i) * prod);*/ |
|
|
|
|
|
complex_inc(perm, prod); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
return p; |
|
|
|
|
|
|
|
|
/*return c_prod((pow(-1,n)), perm); #TODO power is fucked*/ |
|
|
|
|
|
return perm; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 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 |
|
|