浏览代码

Compatible with PyPI, can be installed through pip

master
Pete Shadbolt 10 年前
父节点
当前提交
5ededa9998
共有 11 个文件被更改,包括 55 次插入32 次删除
  1. +3
    -0
      .gitignore
  2. +1
    -1
      LICENSE
  3. +8
    -0
      MANIFEST
  4. +1
    -0
      MANIFEST.in
  5. +4
    -0
      README
  6. +0
    -21
      makefile
  7. +0
    -0
      permanent/__init__.py
  8. +2
    -2
      run-tests.py
  9. +5
    -0
      run-tests.sh
  10. +6
    -5
      setup.py
  11. +25
    -3
      src/permanent.c

+ 3
- 0
.gitignore 查看文件

@@ -1,3 +1,6 @@
.pypirc
*.pdf

# Byte-compiled / optimized / DLL files # Byte-compiled / optimized / DLL files
__pycache__/ __pycache__/
*.py[cod] *.py[cod]


+ 1
- 1
LICENSE 查看文件

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


+ 8
- 0
MANIFEST 查看文件

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

+ 1
- 0
MANIFEST.in 查看文件

@@ -0,0 +1 @@
include src/*

+ 4
- 0
README 查看文件

@@ -0,0 +1,4 @@
# Fast functions for LOQC
- Permanent (hardcoded up to 4x4 and Ryser)
- Parallel permanent
- No Cython dependency

+ 0
- 21
makefile 查看文件

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

lib/__init__.py → permanent/__init__.py 查看文件


+ 2
- 2
run-tests.py 查看文件

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


+ 5
- 0
run-tests.sh 查看文件

@@ -0,0 +1,5 @@
#!/bin/bash

rm permanent/*.so
python ./setup.py build_ext --inplace &&
python ./run-tests.py

+ 6
- 5
setup.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"]),
], ],


+ 25
- 3
src/permanent.c 查看文件

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


正在加载...
取消
保存