| @@ -0,0 +1,57 @@ | |||
| # Byte-compiled / optimized / DLL files | |||
| __pycache__/ | |||
| *.py[cod] | |||
| # C extensions | |||
| *.so | |||
| # Distribution / packaging | |||
| .Python | |||
| env/ | |||
| build/ | |||
| develop-eggs/ | |||
| dist/ | |||
| downloads/ | |||
| eggs/ | |||
| lib/ | |||
| lib64/ | |||
| parts/ | |||
| sdist/ | |||
| var/ | |||
| *.egg-info/ | |||
| .installed.cfg | |||
| *.egg | |||
| # PyInstaller | |||
| # Usually these files are written by a python script from a template | |||
| # before PyInstaller builds the exe, so as to inject date/other infos into it. | |||
| *.manifest | |||
| *.spec | |||
| # Installer logs | |||
| pip-log.txt | |||
| pip-delete-this-directory.txt | |||
| # Unit test / coverage reports | |||
| htmlcov/ | |||
| .tox/ | |||
| .coverage | |||
| .cache | |||
| nosetests.xml | |||
| coverage.xml | |||
| # Translations | |||
| *.mo | |||
| *.pot | |||
| # Django stuff: | |||
| *.log | |||
| # Sphinx documentation | |||
| docs/_build/ | |||
| # PyBuilder | |||
| target/ | |||
| # PYC | |||
| *.pyc | |||
| @@ -0,0 +1,22 @@ | |||
| The MIT License (MIT) | |||
| Copyright (c) 2014 J. Pete Shadbolt | |||
| Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| of this software and associated documentation files (the "Software"), to deal | |||
| in the Software without restriction, including without limitation the rights | |||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| copies of the Software, and to permit persons to whom the Software is | |||
| furnished to do so, subject to the following conditions: | |||
| The above copyright notice and this permission notice shall be included in all | |||
| copies or substantial portions of the Software. | |||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| SOFTWARE. | |||
| @@ -0,0 +1,3 @@ | |||
| # Fast functions for LOQC | |||
| - Permanent (hardcoded up to 4x4 and Ryser) | |||
| - Parallel permanent | |||
| @@ -0,0 +1,35 @@ | |||
| import os | |||
| import time | |||
| import multiprocessing as mp | |||
| import numpy as np | |||
| import lib | |||
| def test_fn(perm_fn, name, dimension=6, steps=1000, dt=1e-3, bodies=101, threads=1): | |||
| # Test the speed of the evolution function. | |||
| sreal=np.random.uniform(0,1,(dimension, dimension)) | |||
| scomp=np.random.uniform(0,1,(dimension, dimension)) | |||
| submatrix=sreal+1j*scomp | |||
| t0 = time.time() | |||
| for i in range(steps): | |||
| p=perm_fn(submatrix) | |||
| t1 = time.time() | |||
| print "{0} ({1}): {2} steps/sec".format(name, threads, int(steps / (t1 - t0))) | |||
| if __name__ == "__main__": | |||
| d=4 | |||
| steps=1000 | |||
| # Test on one core | |||
| test_fn(lib.perm_python, "1 core, C", steps=steps, threads=1) | |||
| # Test on one core | |||
| test_fn(lib.perm_c, "1 core, C", steps=steps, threads=1) | |||
| # Test on four cores | |||
| test_fn(lib.perm_c, "All cores, C", steps=steps/threads, threads=threads) | |||
| @@ -0,0 +1,5 @@ | |||
| #!/bin/bash | |||
| rm lib/*.so | |||
| python ./setup.py build_ext --inplace && | |||
| python ./run-tests.py | |||
| @@ -0,0 +1,18 @@ | |||
| #!/usr/bin/env python | |||
| from distutils.core import setup, Extension | |||
| setup(name = "loqcmath", | |||
| version = "1.0", | |||
| description = "Fast maths for LOQC", | |||
| author = "Pete Shadbolt", | |||
| author_email = "pete.shadbolt@gmail.com", | |||
| maintainer = "pete.shadbolt@gmail.com", | |||
| url = "https://www.peteshadbolt.co.uk", | |||
| ext_modules = [ | |||
| Extension( | |||
| 'perm_c', ['src/perm_c'], | |||
| extra_compile_args=["-Ofast", "-march=native"]), | |||
| ], | |||
| ) | |||
| @@ -0,0 +1,106 @@ | |||
| /* Computes the permanent, given a numpy array */ | |||
| #include <Python.h> | |||
| #include <numpy/arrayobject.h> | |||
| #include <math.h> | |||
| // 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 m(x0) (*(npy_float64*)((PyArray_DATA(py_m) + \ | |||
| (x0) * PyArray_STRIDES(py_m)[0]))) | |||
| #define m_shape(i) (py_m->dimensions[(i)]) | |||
| #define r(x0, x1) (*(npy_float64*)((PyArray_DATA(py_r) + \ | |||
| (x0) * PyArray_STRIDES(py_r)[0] + \ | |||
| (x1) * PyArray_STRIDES(py_r)[1]))) | |||
| #define r_shape(i) (py_r->dimensions[(i)]) | |||
| #define v(x0, x1) (*(npy_float64*)((PyArray_DATA(py_v) + \ | |||
| (x0) * PyArray_STRIDES(py_v)[0] + \ | |||
| (x1) * PyArray_STRIDES(py_v)[1]))) | |||
| #define v_shape(i) (py_v->dimensions[(i)]) | |||
| #define F(x0, x1) (*(npy_float64*)((PyArray_DATA(py_F) + \ | |||
| (x0) * PyArray_STRIDES(py_F)[0] + \ | |||
| (x1) * PyArray_STRIDES(py_F)[1]))) | |||
| #define F_shape(i) (py_F->dimensions[(i)]) | |||
| /***************************************************************************** | |||
| * compute_F * | |||
| *****************************************************************************/ | |||
| static inline void compute_F(npy_int64 N, | |||
| PyArrayObject *py_m, | |||
| PyArrayObject *py_r, | |||
| PyArrayObject *py_F) { | |||
| npy_int64 i, j; | |||
| npy_float64 sx, sy, Fx, Fy, s3, tmp; | |||
| // Set all forces to zero. | |||
| for(i = 0; i < N; ++i) { | |||
| F(i, 0) = F(i, 1) = 0; | |||
| } | |||
| // Compute forces between pairs of bodies. | |||
| for(i = 0; i < N; ++i) { | |||
| for(j = i + 1; j < N; ++j) { | |||
| sx = r(j, 0) - r(i, 0); | |||
| sy = r(j, 1) - r(i, 1); | |||
| s3 = sqrt(sx*sx + sy*sy); | |||
| s3 *= s3 * s3; | |||
| tmp = m(i) * m(j) / s3; | |||
| Fx = tmp * sx; | |||
| Fy = tmp * sy; | |||
| F(i, 0) += Fx; | |||
| F(i, 1) += Fy; | |||
| F(j, 0) -= Fx; | |||
| F(j, 1) -= Fy; | |||
| } | |||
| } | |||
| } | |||
| static PyObject *permanent(PyObject *self, PyObject *args) { | |||
| // Declare variables. | |||
| npy_int64 d, i, j; | |||
| npy_float64 output; | |||
| PyArrayObject *submatrix; | |||
| // Parse variables. | |||
| if (!PyArg_ParseTuple(args, "ldllO!O!O!O!", | |||
| &threads, | |||
| &dt, | |||
| &steps, | |||
| &N, | |||
| &PyArray_Type, &submatrix)) { | |||
| return NULL; | |||
| } | |||
| // Compute the permanent | |||
| for(i = 0; i < d; ++i) { | |||
| for(j = 0; j<d; ++j) { | |||
| } | |||
| } | |||
| Py_RETURN_NONE; | |||
| } | |||