diff --git a/MANIFEST b/MANIFEST index e49d535..dd17fe8 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1,5 +1,4 @@ # file GENERATED by distutils, do NOT edit -README setup.py ./src/permanent.c permanent/__init__.py diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..24ce15a --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +numpy diff --git a/setup.py b/setup.py index 60c5546..77f0586 100644 --- a/setup.py +++ b/setup.py @@ -3,19 +3,20 @@ from distutils.core import setup, Extension import numpy -setup(name = "permanent", - version = "0.1.3", - description = "Calculates the permanent of a Numpy matrix", - author = "Pete Shadbolt", - author_email = "pete.shadbolt@gmail.com", - maintainer = "pete.shadbolt@gmail.com", - url = "https://github.com/peteshadbolt/permanent", - packages = ["permanent"], - ext_modules = [ - Extension( - 'permanent.permanent', ['./src/permanent.c'], - extra_compile_args=["-Ofast", "-march=native"], - include_dirs=[numpy.get_include()]), - ], - +setup( + name="permanent", + version="0.1.3", + description="Calculates the permanent of a Numpy matrix", + author="Pete Shadbolt", + author_email="hello@peteshadbolt.co.uk", + maintainer="hello@peteshadbolt.co.uk", + url="https://github.com/peteshadbolt/permanent", + packages=["permanent"], + setup_requires=["numpy"], + ext_modules=[ + Extension( + 'permanent.permanent', ['./src/permanent.c'], + extra_compile_args=["-Ofast", "-march=native"], + include_dirs=[numpy.get_include()]), + ], ) diff --git a/src/permanent.c b/src/permanent.c index 8479459..781d90b 100644 --- a/src/permanent.c +++ b/src/permanent.c @@ -14,12 +14,32 @@ static PyMethodDef methods[] = { { NULL, NULL, 0, NULL } // Sentinel }; -// Module initialization + +#if PY_MAJOR_VERSION >= 3 +static struct PyModuleDef cModPyDem = +{ + PyModuleDef_HEAD_INIT, + "permanent", "Computes the permanent of a numpy using the most appropriate method available", + -1, + methods +}; + +PyMODINIT_FUNC +PyInit_permanent(void) +{ + import_array(); + return PyModule_Create(&cModPyDem); +} + +#else + PyMODINIT_FUNC initpermanent(void) { (void) Py_InitModule("permanent", methods); import_array(); } +#endif + // Ryser's algorithm static npy_complex128 ryser(PyArrayObject *submatrix) { int n = (int) PyArray_DIM(submatrix, 0); diff --git a/tests/test_permanent.py b/tests/test_permanent.py new file mode 100644 index 0000000..5d2787b --- /dev/null +++ b/tests/test_permanent.py @@ -0,0 +1,27 @@ +import numpy as np +from permanent.permanent import permanent +import pytest + + +def test_permanent(): + """ Test that basic functions work right """ + m = np.eye(10, dtype=complex) + assert permanent(m) == 1 + m = np.zeros((10, 10), dtype=complex) + assert permanent(m) == 0 + + +def test_floaty(): + """ More tests using a precomputed permanent """ + np.random.seed(1234) + m = np.random.uniform(0, 1, 16) + 1j * np.random.uniform(0, 1, 16) + m = m.reshape(4, 4) + p = permanent(m) + assert np.allclose(p, -8.766131870776363 + 1.072095650303524j) + + +def test_error(): + """ Should raise a TypeError as we are using the wrong dtype """ + with pytest.raises(TypeError): + m = np.eye(10, dtype=float) + permanent(m) diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..227b948 --- /dev/null +++ b/tox.ini @@ -0,0 +1,9 @@ +[tox] +envlist = py27, py36 + +[testenv] +deps= + -r requirements.txt + pytest + pytest-mock +commands=pytest {posargs}