Skip to content

Commit ed4e766

Browse files
committed
Modified NIST code to serve as library, added Python C extension
1 parent 62411c1 commit ed4e766

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+69991
-479
lines changed

.gitignore

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,128 @@
1+
# CLion
12
.idea
23
cmake-build-debug/
34

5+
# Byte-compiled / optimized / DLL files
6+
__pycache__/
7+
*.py[cod]
8+
*$py.class
9+
10+
# C extensions
11+
*.so
12+
13+
# Distribution / packaging
14+
.Python
15+
build/
16+
develop-eggs/
17+
dist/
18+
downloads/
19+
eggs/
20+
.eggs/
21+
lib/
22+
lib64/
23+
parts/
24+
sdist/
25+
var/
26+
wheels/
27+
pip-wheel-metadata/
28+
share/python-wheels/
29+
*.egg-info/
30+
.installed.cfg
31+
*.egg
32+
MANIFEST
33+
34+
# PyInstaller
35+
# Usually these files are written by a python script from a template
36+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
37+
*.manifest
38+
*.spec
39+
40+
# Installer logs
41+
pip-log.txt
42+
pip-delete-this-directory.txt
43+
44+
# Unit test / coverage reports
45+
htmlcov/
46+
.tox/
47+
.nox/
48+
.coverage
49+
.coverage.*
50+
.cache
51+
nosetests.xml
52+
coverage.xml
53+
*.cover
54+
.hypothesis/
55+
.pytest_cache/
56+
57+
# Translations
58+
*.mo
59+
*.pot
60+
61+
# Django stuff:
62+
*.log
63+
local_settings.py
64+
db.sqlite3
65+
db.sqlite3-journal
66+
67+
# Flask stuff:
68+
instance/
69+
.webassets-cache
70+
71+
# Scrapy stuff:
72+
.scrapy
73+
74+
# Sphinx documentation
75+
docs/_build/
76+
77+
# PyBuilder
78+
target/
79+
80+
# Jupyter Notebook
81+
.ipynb_checkpoints
82+
83+
# IPython
84+
profile_default/
85+
ipython_config.py
86+
87+
# pyenv
88+
.python-version
89+
90+
# pipenv
91+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
93+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
94+
# install all needed dependencies.
95+
#Pipfile.lock
96+
97+
# celery beat schedule file
98+
celerybeat-schedule
99+
100+
# SageMath parsed files
101+
*.sage.py
102+
103+
# Environments
104+
.env
105+
.venv
106+
env/
107+
venv/
108+
ENV/
109+
env.bak/
110+
venv.bak/
111+
112+
# Spyder project settings
113+
.spyderproject
114+
.spyproject
115+
116+
# Rope project settings
117+
.ropeproject
118+
119+
# mkdocs documentation
120+
/site
121+
122+
# mypy
123+
.mypy_cache/
124+
.dmypy.json
125+
dmypy.json
126+
127+
# Pyre type checker
128+
.pyre/

CMakeLists.txt

Lines changed: 0 additions & 42 deletions
This file was deleted.

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# SP 800-22 Statistical Tests for Python
2+
3+
This is a Python C extension based on the NIST implementation of the statistical tests outlined in SP 800-22 Rev1a.

include/matrix.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ int swap_rows(int i, int index, int Q, BitSequence **A);
99
int determine_rank(int m, int M, int Q, BitSequence **A);
1010
BitSequence** create_matrix(int M, int Q);
1111
void display_matrix(int M, int Q, BitSequence **m);
12-
void def_matrix(int M, int Q, BitSequence **m,int k);
12+
void def_matrix(int M, int Q, BitSequence **m,int k, BitSequence const *epsilon);
1313
void delete_matrix(int M, BitSequence **matrix);

include/stat_fncs.h

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,20 @@
33
S T A T I S T I C A L T E S T F U N C T I O N P R O T O T Y P E S
44
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
55

6-
void Frequency(int n);
7-
void BlockFrequency(int M, int n);
8-
void CumulativeSums(int n);
9-
void Runs(int n);
10-
void LongestRunOfOnes(int n);
11-
void Rank(int n);
12-
void DiscreteFourierTransform(int n);
13-
void NonOverlappingTemplateMatchings(int m, int n);
14-
void OverlappingTemplateMatchings(int m, int n);
15-
void Universal(int n);
16-
void ApproximateEntropy(int m, int n);
17-
void RandomExcursions(int n);
18-
void RandomExcursionsVariant(int n);
19-
void LinearComplexity(int M, int n);
20-
void Serial(int m, int n);
6+
#include "defs.h"
7+
8+
double Frequency(int n, BitSequence const *);
9+
double BlockFrequency(int M, int n, BitSequence const *);
10+
double CumulativeSums(int n, BitSequence const *);
11+
double Runs(int n, BitSequence const *);
12+
double LongestRunOfOnes(int n, BitSequence const *);
13+
double Rank(int n, BitSequence const *);
14+
double DiscreteFourierTransform(int n, BitSequence const *);
15+
double NonOverlappingTemplateMatchings(int m, int n, BitSequence const *);
16+
double OverlappingTemplateMatchings(int m, int n, BitSequence const *);
17+
double Universal(int n, BitSequence const *);
18+
double ApproximateEntropy(int m, int n, BitSequence const *);
19+
double RandomExcursions(int n, BitSequence const *);
20+
double RandomExcursionsVariant(int n, BitSequence const *);
21+
double LinearComplexity(int M, int n, BitSequence const *);
22+
double Serial(int m, int n, BitSequence const *);

setup.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import setuptools
2+
3+
with open("README.md", "r") as fh:
4+
long_description = fh.read()
5+
6+
setuptools.setup(
7+
name='sp80022suite',
8+
version='0.0.1',
9+
author="Nils Wisiol",
10+
author_email="[email protected]",
11+
description="NIST SP 800-22 Statistical Tests",
12+
long_description=long_description,
13+
long_description_content_type="text/markdown",
14+
url="https://github.com/nils-wisiol/sp80022suite",
15+
packages=setuptools.find_packages(),
16+
classifiers=[
17+
"Programming Language :: Python :: 3",
18+
"License :: OSI Approved :: MIT License",
19+
],
20+
ext_modules=[setuptools.Extension('sp80022suite', [
21+
# root
22+
'src/pythonInterface.c',
23+
24+
# helpers
25+
'src/cephes.c', # for longest run of ones test
26+
'src/matrix.c', # for rank test
27+
'src/dfft.c', # for discrete fourier transform test
28+
29+
# tests
30+
'src/frequency.c',
31+
'src/blockFrequency.c',
32+
'src/runs.c',
33+
'src/longestRunOfOnes.c',
34+
'src/rank.c',
35+
'src/discreteFourierTransform.c',
36+
'src/nonOverlappingTemplateMatchings.c',
37+
'src/overlappingTemplateMatchings.c',
38+
'src/universal.c',
39+
'src/linearComplexity.c',
40+
'src/approximateEntropy.c',
41+
'src/serial.c',
42+
'src/cusum.c',
43+
'src/randomExcursions.c',
44+
'src/randomExcursionsVariant.c',
45+
])]
46+
)

src/approximateEntropy.c

Lines changed: 6 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,21 @@
22
#include <math.h>
33
#include <string.h>
44
#include <stdlib.h>
5-
#include "../include/externs.h"
5+
#include "../include/defs.h"
66
#include "../include/utilities.h"
77
#include "../include/cephes.h"
88

99
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1010
A P P R O X I M A T E E N T R O P Y T E S T
1111
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1212

13-
void
14-
ApproximateEntropy(int m, int n)
13+
double
14+
ApproximateEntropy(int m, int n, BitSequence const *epsilon)
1515
{
1616
int i, j, k, r, blockSize, seqLength, powLen, index;
1717
double sum, numOfBlocks, ApEn[2], apen, chi_squared, p_value;
1818
unsigned int *P;
1919

20-
fprintf(stats[TEST_APEN], "\t\t\tAPPROXIMATE ENTROPY TEST\n");
21-
fprintf(stats[TEST_APEN], "\t\t--------------------------------------------\n");
22-
fprintf(stats[TEST_APEN], "\t\tCOMPUTATIONAL INFORMATION:\n");
23-
fprintf(stats[TEST_APEN], "\t\t--------------------------------------------\n");
24-
fprintf(stats[TEST_APEN], "\t\t(a) m (block length) = %d\n", m);
25-
2620
seqLength = n;
2721
r = 0;
2822

@@ -35,8 +29,7 @@ ApproximateEntropy(int m, int n)
3529
numOfBlocks = (double)seqLength;
3630
powLen = (int)pow(2, blockSize+1)-1;
3731
if ( (P = (unsigned int*)calloc(powLen,sizeof(unsigned int)))== NULL ) {
38-
fprintf(stats[TEST_APEN], "ApEn: Insufficient memory available.\n");
39-
return;
32+
return -1;
4033
}
4134
for ( i=1; i<powLen-1; i++ )
4235
P[i] = 0;
@@ -67,22 +60,6 @@ ApproximateEntropy(int m, int n)
6760

6861
chi_squared = 2.0*seqLength*(log(2) - apen);
6962
p_value = cephes_igamc(pow(2, m-1), chi_squared/2.0);
70-
71-
fprintf(stats[TEST_APEN], "\t\t(b) n (sequence length) = %d\n", seqLength);
72-
fprintf(stats[TEST_APEN], "\t\t(c) Chi^2 = %f\n", chi_squared);
73-
fprintf(stats[TEST_APEN], "\t\t(d) Phi(m) = %f\n", ApEn[0]);
74-
fprintf(stats[TEST_APEN], "\t\t(e) Phi(m+1) = %f\n", ApEn[1]);
75-
fprintf(stats[TEST_APEN], "\t\t(f) ApEn = %f\n", apen);
76-
fprintf(stats[TEST_APEN], "\t\t(g) Log(2) = %f\n", log(2.0));
77-
fprintf(stats[TEST_APEN], "\t\t--------------------------------------------\n");
7863

79-
if ( m > (int)(log(seqLength)/log(2)-5) ) {
80-
fprintf(stats[TEST_APEN], "\t\tNote: The blockSize = %d exceeds recommended value of %d\n", m,
81-
MAX(1, (int)(log(seqLength)/log(2)-5)));
82-
fprintf(stats[TEST_APEN], "\t\tResults are inaccurate!\n");
83-
fprintf(stats[TEST_APEN], "\t\t--------------------------------------------\n");
84-
}
85-
86-
fprintf(stats[TEST_APEN], "%s\t\tp_value = %f\n\n", p_value < ALPHA ? "FAILURE" : "SUCCESS", p_value); fflush(stats[TEST_APEN]);
87-
fprintf(results[TEST_APEN], "%f\n", p_value); fflush(results[TEST_APEN]);
88-
}
64+
return p_value;
65+
}

src/blockFrequency.c

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
#include <stdio.h>
22
#include <math.h>
33
#include <string.h>
4-
#include "../include/externs.h"
4+
#include "../include/defs.h"
55
#include "../include/cephes.h"
66

77
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
88
B L O C K F R E Q U E N C Y T E S T
99
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1010

11-
void
12-
BlockFrequency(int M, int n)
11+
double
12+
BlockFrequency(int M, int n, BitSequence const *epsilon)
1313
{
1414
int i, j, N, blockSum;
1515
double p_value, sum, pi, v, chi_squared;
@@ -28,16 +28,5 @@ BlockFrequency(int M, int n)
2828
chi_squared = 4.0 * M * sum;
2929
p_value = cephes_igamc(N/2.0, chi_squared/2.0);
3030

31-
fprintf(stats[TEST_BLOCK_FREQUENCY], "\t\t\tBLOCK FREQUENCY TEST\n");
32-
fprintf(stats[TEST_BLOCK_FREQUENCY], "\t\t---------------------------------------------\n");
33-
fprintf(stats[TEST_BLOCK_FREQUENCY], "\t\tCOMPUTATIONAL INFORMATION:\n");
34-
fprintf(stats[TEST_BLOCK_FREQUENCY], "\t\t---------------------------------------------\n");
35-
fprintf(stats[TEST_BLOCK_FREQUENCY], "\t\t(a) Chi^2 = %f\n", chi_squared);
36-
fprintf(stats[TEST_BLOCK_FREQUENCY], "\t\t(b) # of substrings = %d\n", N);
37-
fprintf(stats[TEST_BLOCK_FREQUENCY], "\t\t(c) block length = %d\n", M);
38-
fprintf(stats[TEST_BLOCK_FREQUENCY], "\t\t(d) Note: %d bits were discarded.\n", n % M);
39-
fprintf(stats[TEST_BLOCK_FREQUENCY], "\t\t---------------------------------------------\n");
40-
41-
fprintf(stats[TEST_BLOCK_FREQUENCY], "%s\t\tp_value = %f\n\n", p_value < ALPHA ? "FAILURE" : "SUCCESS", p_value); fflush(stats[TEST_BLOCK_FREQUENCY]);
42-
fprintf(results[TEST_BLOCK_FREQUENCY], "%f\n", p_value); fflush(results[TEST_BLOCK_FREQUENCY]);
31+
return p_value;
4332
}

0 commit comments

Comments
 (0)