| @@ -1,3 +1,6 @@ | |||||
| .pypirc | |||||
| # Byte-compiled / optimized / DLL files | # Byte-compiled / optimized / DLL files | ||||
| __pycache__/ | __pycache__/ | ||||
| *.py[cod] | *.py[cod] | ||||
| @@ -1,6 +1,6 @@ | |||||
| The MIT License (MIT) | The MIT License (MIT) | ||||
| Copyright (c) 2014 J. Pete Shadbolt | |||||
| Copyright (c) 2014 Pete Shadbolt | |||||
| Permission is hereby granted, free of charge, to any person obtaining a copy | Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| of this software and associated documentation files (the "Software"), to deal | of this software and associated documentation files (the "Software"), to deal | ||||
| @@ -0,0 +1,8 @@ | |||||
| # file GENERATED by distutils, do NOT edit | |||||
| README | |||||
| setup.py | |||||
| ./src/permanent.c | |||||
| permanent/__init__.py | |||||
| src/bithacks.h | |||||
| src/npy_util.h | |||||
| src/permanent.c | |||||
| @@ -0,0 +1 @@ | |||||
| include src/* | |||||
| @@ -0,0 +1,4 @@ | |||||
| # Fast functions for LOQC | |||||
| - Permanent (hardcoded up to 4x4 and Ryser) | |||||
| - Parallel permanent | |||||
| - No Cython dependency | |||||
| @@ -1,21 +0,0 @@ | |||||
| srcdir = src | |||||
| objdir = ./ | |||||
| target = permanent.so | |||||
| setup = setup.py | |||||
| default : $(target) test | |||||
| # Compile | |||||
| $(target): $(srcdir)/* | |||||
| python $(setup) build_ext --inplace | |||||
| test : | |||||
| python ./run-tests.py | |||||
| clean : | |||||
| @ rm permanent.so | |||||
| @ rm -rf build | |||||
| tar : | |||||
| @ tar czf permanent.tar.gz $(srcdir) $(utils) | |||||
| @@ -2,9 +2,9 @@ import os, sys | |||||
| import time | import time | ||||
| import multiprocessing as mp | import multiprocessing as mp | ||||
| import numpy as np | import numpy as np | ||||
| import lib | |||||
| import time | import time | ||||
| from matplotlib import pyplot as plt | from matplotlib import pyplot as plt | ||||
| from permanent import permanent | |||||
| def perm_ryser(a): | def perm_ryser(a): | ||||
| ''' the permanent calculated using the ryser formula. much faster than the naive approach ''' | ''' the permanent calculated using the ryser formula. much faster than the naive approach ''' | ||||
| @@ -20,7 +20,7 @@ def perm_ryser(a): | |||||
| maxtime=1 | maxtime=1 | ||||
| dimensions=range(1,11) | dimensions=range(1,11) | ||||
| for (function, label) in zip((lib.permanent, perm_ryser), ("C", "Python")): | |||||
| for (function, label) in zip((permanent, perm_ryser), ("C", "Python")): | |||||
| counts=[] | counts=[] | ||||
| for dimension in dimensions: | for dimension in dimensions: | ||||
| print dimension | print dimension | ||||
| @@ -0,0 +1,5 @@ | |||||
| #!/bin/bash | |||||
| rm permanent/*.so | |||||
| python ./setup.py build_ext --inplace && | |||||
| python ./run-tests.py | |||||
| @@ -2,16 +2,17 @@ | |||||
| from distutils.core import setup, Extension | from distutils.core import setup, Extension | ||||
| setup(name = "loqcmath", | |||||
| version = "1.0", | |||||
| description = "Fast maths for LOQC", | |||||
| setup(name = "permanent", | |||||
| version = "0.1.2", | |||||
| description = "Calculates the permanent of a Numpy matrix", | |||||
| author = "Pete Shadbolt", | author = "Pete Shadbolt", | ||||
| author_email = "pete.shadbolt@gmail.com", | author_email = "pete.shadbolt@gmail.com", | ||||
| maintainer = "pete.shadbolt@gmail.com", | maintainer = "pete.shadbolt@gmail.com", | ||||
| url = "https://www.peteshadbolt.co.uk", | |||||
| url = "https://github.com/peteshadbolt/permanent", | |||||
| packages = ["permanent"], | |||||
| ext_modules = [ | ext_modules = [ | ||||
| Extension( | Extension( | ||||
| 'permanent', ['src/permanent.c'], | |||||
| 'permanent.permanent', ['./src/permanent.c'], | |||||
| extra_compile_args=["-Ofast", "-march=native"]), | extra_compile_args=["-Ofast", "-march=native"]), | ||||
| ], | ], | ||||
| @@ -1,17 +1,16 @@ | |||||
| /* Computes the permanent, given a numpy array */ | |||||
| /* Functions to compute 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 "npy_util.h" | #include "npy_util.h" | ||||
| #include "bithacks.h" | #include "bithacks.h" | ||||
| #include "ryser.h" | |||||
| // Forward function declaration | // Forward function declaration | ||||
| static PyObject *permanent(PyObject *self, PyObject *args); | static PyObject *permanent(PyObject *self, PyObject *args); | ||||
| // Method list | // Method list | ||||
| static PyMethodDef methods[] = { | static PyMethodDef methods[] = { | ||||
| { "permanent", permanent, METH_VARARGS, "Compute the permanent"}, | |||||
| { "permanent", permanent, METH_VARARGS, "Computes the permanent of a numpy using the most appropriate method available"}, | |||||
| { NULL, NULL, 0, NULL } // Sentinel | { NULL, NULL, 0, NULL } // Sentinel | ||||
| }; | }; | ||||
| @@ -21,6 +20,29 @@ PyMODINIT_FUNC initpermanent(void) { | |||||
| import_array(); | import_array(); | ||||
| } | } | ||||
| // Ryser's algorithm | |||||
| static npy_complex128 ryser(PyArrayObject *submatrix) { | |||||
| int n = (int) PyArray_DIM(submatrix, 0); | |||||
| npy_complex128 rowsum, rowsumprod; | |||||
| npy_complex128 perm = complex_zero; | |||||
| int exp = 1 << n; | |||||
| int i, y, z; | |||||
| for (i=0; i<exp; ++i) { | |||||
| rowsumprod = complex_one; | |||||
| for (y=0; y<n; ++y) { | |||||
| rowsum = complex_zero; | |||||
| for (z=0; z<n; ++z) { | |||||
| if ((i & (1 << z)) != 0) { complex_inc(&rowsum, SM(z, y)); } | |||||
| } | |||||
| complex_multiply(&rowsumprod, rowsum); | |||||
| } | |||||
| complex_inc(&perm, complex_float_prod(rowsumprod, bitparity(i))); | |||||
| } | |||||
| if (n%2 == 1) { perm=complex_float_prod(perm, -1); } | |||||
| return perm; | |||||
| } | |||||
| // This is 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 the input | // Parse the input | ||||