Browse Source

Had another go at complex math

master
Pete Shadbolt 9 years ago
parent
commit
126d19c426
4 changed files with 174 additions and 34 deletions
  1. +2
    -1
      run-tests.py
  2. +90
    -0
      src/old.c
  3. +68
    -0
      src/oldold.c
  4. +14
    -33
      src/permanent.c

+ 2
- 1
run-tests.py View File

@@ -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

+ 90
- 0
src/old.c View File

@@ -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);
}

+ 68
- 0
src/oldold.c View File

@@ -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);
}

+ 14
- 33
src/permanent.c View File

@@ -1,68 +1,49 @@
/* 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
// 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);
}

Loading…
Cancel
Save