aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--Makefile9
-rw-r--r--README.md16
-rw-r--r--SyncRNG.R (renamed from Tausworthe.R)24
-rw-r--r--SyncRNG.py21
-rw-r--r--Tausworthe.py16
-rw-r--r--setup.py12
-rw-r--r--syncrng.c (renamed from taus.c)62
8 files changed, 99 insertions, 64 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ed61eb2
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+*.pyc
+*.so
+*.o
diff --git a/Makefile b/Makefile
index 4531139..da2d612 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,6 @@
PYTHON=python2
+RLIB=RSyncRNG.so
+CFILE=syncrng.c
.PHONY: all clean
@@ -8,10 +10,9 @@ python:
$(PYTHON) setup.py build_ext --inplace
R:
- R CMD SHLIB -o tausR.so taus.c
+ R CMD SHLIB -o $(RLIB) $(CFILE)
clean:
rm -rf build
- rm -f taus.so
- rm -f tausR.so
- rm -f taus.o
+ rm -f *.so *.o
+ rm *.pyc
diff --git a/README.md b/README.md
index 4c402d8..6147774 100644
--- a/README.md
+++ b/README.md
@@ -25,7 +25,7 @@ build both shared libraries using:
make
Then, in a Python script located in the same directory as `syncrng.so` and
-`pysyncrng.py`, you can do:
+`SyncRNG.py`, you can do:
from pysyncrng import SyncRNG
@@ -33,10 +33,10 @@ Then, in a Python script located in the same directory as `syncrng.so` and
for i in range(10):
print(s.randi())
-Similarly, in an R script located in the same directory as `Rsyncrng.so` and
-`Rsyncrng.R`, you can do:
+Similarly, in an R script located in the same directory as `RSyncRNG.so` and
+`SyncRNG.R`, you can do:
- source('./Rsyncrng.R')
+ source('./SyncRNG.R')
s = SyncRNG(seed=123456)
for (i in 1:10) {
@@ -55,3 +55,11 @@ random numbers are no longer uniformly distributed on `[0, 2^32 -1]`. For the
intended use of SyncRNG this is not a problem, but it is a compromise worth
considering when using SyncRNG. SyncRNG should definitely not be used for any
cryptographic purposes.
+
+
+TODO
+----
+
+Future versions may include a random number generator that does not need
+capping, and is uniform. It may also provide easier system-wide installation
+through an R package and a Python module.
diff --git a/Tausworthe.R b/SyncRNG.R
index e4fe355..23be4d2 100644
--- a/Tausworthe.R
+++ b/SyncRNG.R
@@ -1,8 +1,8 @@
library(methods)
-dyn.load('tausR.so')
+dyn.load('RSyncRNG.so')
-TauswortheRNG <- setRefClass('TauswortheRNG',
+SyncRNG <- setRefClass('SyncRNG',
fields=list(
seed='numeric',
state='numeric'
@@ -10,13 +10,13 @@ TauswortheRNG <- setRefClass('TauswortheRNG',
methods=list(
initialize=function(..., seed=0) {
seed <<- seed
- tmp <- .Call('R_tausworthe_seed',
+ tmp <- .Call('R_syncrng_seed',
as.integer(seed))
state <<- tmp[1:4]
callSuper(...)
},
randi=function() {
- tmp <- .Call('R_tausworthe_rand',
+ tmp <- .Call('R_syncrng_rand',
as.integer(state))
state <<- tmp[1:4]
return(tmp[5])
@@ -27,19 +27,3 @@ TauswortheRNG <- setRefClass('TauswortheRNG',
}
)
)
-
-taus.seed <- function(seed=0)
-{
- t <- TauswortheRNG(seed=seed)
- return(t)
-}
-
-taus.rand <- function(t)
-{
- return(t$rand())
-}
-
-taus.randi <- function(t)
-{
- return(t$randi())
-}
diff --git a/SyncRNG.py b/SyncRNG.py
new file mode 100644
index 0000000..7137439
--- /dev/null
+++ b/SyncRNG.py
@@ -0,0 +1,21 @@
+"""
+Simple interface to SyncRNG. This file defines a SyncRNG object which can be
+used to seed and pull numbers from the RNG.
+
+"""
+
+import syncrng
+
+class SyncRNG(object):
+
+ def __init__(self, seed=0):
+ self.seed = seed
+ self.state = syncrng.seed(seed)
+
+ def randi(self):
+ tmp = syncrng.rand(self.state)
+ self.state = tmp[:-1]
+ return(tmp[-1])
+
+ def rand(self):
+ return self.randi() * 2.3283064365387e-10
diff --git a/Tausworthe.py b/Tausworthe.py
deleted file mode 100644
index 303f358..0000000
--- a/Tausworthe.py
+++ /dev/null
@@ -1,16 +0,0 @@
-
-import taus
-
-class TauswortheRNG(object):
-
- def __init__(self, seed=0):
- self.seed = seed
- self.state = taus.seed(seed)
-
- def randi(self):
- tmp = taus.rand(self.state)
- self.state = tmp[:-1]
- return(tmp[-1])
-
- def rand(self):
- return self.randi() * 2.3283064365387e-10
diff --git a/setup.py b/setup.py
index f3c23b0..3c6bf16 100644
--- a/setup.py
+++ b/setup.py
@@ -2,18 +2,18 @@
from distutils.core import setup, Extension
"""
-module1 = Extension('taus',
+module1 = Extension('syncrng',
define_macros = [('TARGETPYTHON', '1')],
- sources=['taus.c'])
+ sources=['syncrng.c'])
-setup (name = 'Tausworthe RNG',
+setup (name = 'SyncRNG',
version = '0.1',
- description='The Tausworthe RNG for Python and R',
+ description='A synchronized Tausworthe RNG for Python and R',
ext_modules = [module1])
"""
setup(
- ext_modules=[Extension("taus",
+ ext_modules=[Extension("syncrng",
define_macros=[('TARGETPYTHON', '1')],
- sources=["taus.c"])],
+ sources=["syncrng.c"])],
)
diff --git a/taus.c b/syncrng.c
index 9eba229..deb9439 100644
--- a/taus.c
+++ b/syncrng.c
@@ -10,6 +10,30 @@
#include <Rinternals.h>
#endif
+/**
+ * @brief Generate a single random number using the capped Tausworthe RNG
+ *
+ * @details
+ * This generates random numbers according to the process described in [1]. As
+ * an additional step, the state variables are capped to 0x7FFFFFFF using a
+ * bitwise and. This is to overcome limitations of R. On return, the state
+ * variables are updated.
+ *
+ * [1]: @article{l1996maximally,
+ * title={Maximally equidistributed combined Tausworthe generators},
+ * author={L’ecuyer, Pierre},
+ * journal={Mathematics of Computation of the American Mathematical
+ * Society},
+ * volume={65},
+ * number={213},
+ * pages={203--213},
+ * year={1996}
+ * }
+ *
+ * @param[in,out] state pointer to current state array
+ *
+ * @return a generated random number
+ */
int lfsr113(int **state)
{
unsigned long z1, z2, z3, z4, b;
@@ -42,6 +66,18 @@ int lfsr113(int **state)
return(b);
}
+/**
+ * @brief Seed the Tausworthe RNG using a seed value
+ *
+ * @details
+ * This function seeds the state array using a supplied seed value. As noted
+ * in [1] (see lfsr113()), the values of z1, z2, z3, and z4 should be larger
+ * than 1, 7, 15, and 127 respectively. Here too the state variables are
+ * capped at 0x7FFFFFF.
+ *
+ * @param[in] seed user supplied seed value for the RNG
+ * @param[out] state state of the RNG
+ */
void lfsr113_seed(unsigned long seed, int **state)
{
unsigned long z1 = 2,
@@ -71,10 +107,7 @@ void lfsr113_seed(unsigned long seed, int **state)
*
*/
-static char module_docstring[] =
-"This module provides the Tausworthe RNG for R and Python simultaneously";
-
-static PyObject *taus_seed(PyObject *self, PyObject *args)
+static PyObject *syncrng_seed(PyObject *self, PyObject *args)
{
int seed, *state = NULL;
@@ -88,7 +121,7 @@ static PyObject *taus_seed(PyObject *self, PyObject *args)
return pystate;
}
-static PyObject *taus_rand(PyObject *self, PyObject *args)
+static PyObject *syncrng_rand(PyObject *self, PyObject *args)
{
int i, value, numints, *localstate;
@@ -117,17 +150,18 @@ static PyObject *taus_rand(PyObject *self, PyObject *args)
return pystate;
}
-static PyMethodDef TausMethods[] = {
- {"seed", taus_seed, METH_VARARGS,
- "Seed the Tausworthe RNG."},
- {"rand", taus_rand, METH_VARARGS,
- "Generate a single random integer."},
+static PyMethodDef SyncRNGMethods[] = {
+ {"seed", syncrng_seed, METH_VARARGS,
+ "Seed the RNG."},
+ {"rand", syncrng_rand, METH_VARARGS,
+ "Generate a single random integer using SyncRNG."},
{NULL, NULL, 0, NULL}
};
-PyMODINIT_FUNC inittaus(void)
+PyMODINIT_FUNC initsyncrng(void)
{
- PyObject *m = Py_InitModule3("taus", TausMethods, module_docstring);
+ PyObject *m = Py_InitModule3("syncrng", SyncRNGMethods,
+ "Python interface to SyncRNG");
if (m == NULL)
return;
}
@@ -139,7 +173,7 @@ PyMODINIT_FUNC inittaus(void)
* Start of R code
*
*/
-SEXP R_tausworthe_seed(SEXP seed)
+SEXP R_syncrng_seed(SEXP seed)
{
int i, *pstate = NULL, *state = NULL;
int *pseed = INTEGER(seed);
@@ -159,7 +193,7 @@ SEXP R_tausworthe_seed(SEXP seed)
return Rstate;
}
-SEXP R_tausworthe_rand(SEXP state)
+SEXP R_syncrng_rand(SEXP state)
{
int *localstate = malloc(sizeof(int)*4);
int *pstate = INTEGER(state);