Browse Source

Compatible with PyPI, can be installed through pip

Pete Shadbolt 4 years ago
parent
commit
5ededa9998
11 changed files with 55 additions and 32 deletions
  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 View File

@@ -1,3 +1,6 @@
1
+.pypirc
2
+*.pdf
3
+
1 4
 # Byte-compiled / optimized / DLL files
2 5
 __pycache__/
3 6
 *.py[cod]

+ 1
- 1
LICENSE View File

@@ -1,6 +1,6 @@
1 1
 The MIT License (MIT)
2 2
 
3
-Copyright (c) 2014 J. Pete Shadbolt
3
+Copyright (c) 2014 Pete Shadbolt
4 4
 
5 5
 Permission is hereby granted, free of charge, to any person obtaining a copy
6 6
 of this software and associated documentation files (the "Software"), to deal

+ 8
- 0
MANIFEST View File

@@ -0,0 +1,8 @@
1
+# file GENERATED by distutils, do NOT edit
2
+README
3
+setup.py
4
+./src/permanent.c
5
+permanent/__init__.py
6
+src/bithacks.h
7
+src/npy_util.h
8
+src/permanent.c

+ 1
- 0
MANIFEST.in View File

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

+ 4
- 0
README View File

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

+ 0
- 21
makefile View File

@@ -1,21 +0,0 @@
1
-srcdir = src
2
-objdir = ./
3
-
4
-target = permanent.so
5
-setup = setup.py
6
-
7
-default : $(target) test
8
-
9
-# Compile
10
-$(target): $(srcdir)/* 
11
-	python $(setup) build_ext --inplace 
12
-
13
-test : 
14
-	python ./run-tests.py
15
-
16
-clean :
17
-	@ rm permanent.so
18
-	@ rm -rf build
19
-
20
-tar :
21
-	@ tar czf permanent.tar.gz $(srcdir) $(utils)

lib/__init__.py → permanent/__init__.py View File


+ 2
- 2
run-tests.py View File

@@ -2,9 +2,9 @@ import os, sys
2 2
 import time
3 3
 import multiprocessing as mp
4 4
 import numpy as np
5
-import lib
6 5
 import time
7 6
 from matplotlib import pyplot as plt
7
+from permanent import permanent
8 8
 
9 9
 def perm_ryser(a):
10 10
     ''' the permanent calculated using the ryser formula. much faster than the naive approach '''
@@ -20,7 +20,7 @@ def perm_ryser(a):
20 20
 maxtime=1
21 21
 dimensions=range(1,11)
22 22
 
23
-for (function, label) in zip((lib.permanent, perm_ryser), ("C", "Python")):
23
+for (function, label) in zip((permanent, perm_ryser), ("C", "Python")):
24 24
     counts=[]
25 25
     for dimension in dimensions:
26 26
         print dimension

+ 5
- 0
run-tests.sh View File

@@ -0,0 +1,5 @@
1
+#!/bin/bash
2
+
3
+rm permanent/*.so
4
+python ./setup.py build_ext --inplace &&
5
+python ./run-tests.py

+ 6
- 5
setup.py View File

@@ -2,16 +2,17 @@
2 2
 
3 3
 from distutils.core import setup, Extension
4 4
 
5
-setup(name             = "loqcmath",
6
-      version          = "1.0",
7
-      description      = "Fast maths for LOQC",
5
+setup(name             = "permanent",
6
+      version          = "0.1.2",
7
+      description      = "Calculates the permanent of a Numpy matrix",
8 8
       author           = "Pete Shadbolt",
9 9
       author_email     = "pete.shadbolt@gmail.com",
10 10
       maintainer       = "pete.shadbolt@gmail.com",
11
-      url              = "https://www.peteshadbolt.co.uk",
11
+      url              = "https://github.com/peteshadbolt/permanent",
12
+      packages         = ["permanent"],
12 13
       ext_modules      = [
13 14
           Extension(
14
-              'permanent', ['src/permanent.c'],
15
+              'permanent.permanent', ['./src/permanent.c'],
15 16
               extra_compile_args=["-Ofast", "-march=native"]),
16 17
       ], 
17 18
       

+ 25
- 3
src/permanent.c View File

@@ -1,17 +1,16 @@
1
-/* Computes the permanent, given a numpy array */
1
+/* Functions to compute the permanent, given a numpy array */
2 2
 #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
3 3
 #include <Python.h>
4 4
 #include <numpy/arrayobject.h>
5 5
 #include "npy_util.h"
6 6
 #include "bithacks.h"
7
-#include "ryser.h"
8 7
 
9 8
 // Forward function declaration 
10 9
 static PyObject *permanent(PyObject *self, PyObject *args);    
11 10
 
12 11
 // Method list
13 12
 static PyMethodDef methods[] = {                                
14
-  { "permanent", permanent, METH_VARARGS, "Compute the permanent"},
13
+  { "permanent", permanent, METH_VARARGS, "Computes the permanent of a numpy using the most appropriate method available"},
15 14
   { NULL, NULL, 0, NULL } // Sentinel
16 15
 };
17 16
 
@@ -21,6 +20,29 @@ PyMODINIT_FUNC initpermanent(void) {
21 20
   import_array();
22 21
 }
23 22
 
23
+// Ryser's algorithm 
24
+static npy_complex128 ryser(PyArrayObject *submatrix) {
25
+    int n = (int) PyArray_DIM(submatrix, 0);
26
+    npy_complex128 rowsum, rowsumprod;
27
+    npy_complex128 perm = complex_zero;
28
+    int exp = 1 << n; 
29
+    int i, y, z;
30
+    for (i=0; i<exp; ++i) {
31
+        rowsumprod = complex_one;
32
+        for (y=0; y<n; ++y) {               
33
+            rowsum = complex_zero;
34
+            for (z=0; z<n; ++z) { 
35
+                if ((i & (1 << z)) != 0) { complex_inc(&rowsum, SM(z, y)); }
36
+            }
37
+            complex_multiply(&rowsumprod, rowsum);
38
+        }
39
+        complex_inc(&perm, complex_float_prod(rowsumprod, bitparity(i)));
40
+    }
41
+    if (n%2 == 1) { perm=complex_float_prod(perm, -1); }
42
+    return perm;
43
+}
44
+
45
+
24 46
 // This is a wrapper which chooses the optimal permanent function
25 47
 static PyObject *permanent(PyObject *self, PyObject *args) {
26 48
   // Parse the input