]> git.donarmstrong.com Git - fastq-tools.git/blobdiff - src/rng.c
A program to randomly sample reads from a fastq file.
[fastq-tools.git] / src / rng.c
diff --git a/src/rng.c b/src/rng.c
new file mode 100644 (file)
index 0000000..b503699
--- /dev/null
+++ b/src/rng.c
@@ -0,0 +1,241 @@
+
+/* This code taken from the GNU Scientific Library and adapted for use in
+ * fastq-tools. It is subject to the following licence.
+ */
+
+/* This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 3 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.  You should have received
+   a copy of the GNU General Public License along with this program;
+   if not, write to the Free Foundation, Inc., 59 Temple Place, Suite
+   330, Boston, MA 02111-1307 USA
+
+   Original implementation was copyright (C) 1997 Makoto Matsumoto and
+   Takuji Nishimura. Coded by Takuji Nishimura, considering the
+   suggestions by Topher Cooper and Marc Rieffel in July-Aug. 1997, "A
+   C-program for MT19937: Integer version (1998/4/6)"
+
+   This implementation copyright (C) 1998 Brian Gough. I reorganized
+   the code to use the module framework of GSL.  The license on this
+   implementation was changed from LGPL to GPL, following paragraph 3
+   of the LGPL, version 2.
+
+   Update:
+
+   The seeding procedure has been updated to match the 10/99 release
+   of MT19937.
+
+   Update:
+
+   The seeding procedure has been updated again to match the 2002
+   release of MT19937
+
+   The original code included the comment: "When you use this, send an
+   email to: matumoto@math.keio.ac.jp with an appropriate reference to
+   your work".
+
+   Makoto Matsumoto has a web page with more information about the
+   generator, http://www.math.keio.ac.jp/~matumoto/emt.html. 
+
+   The paper below has details of the algorithm.
+
+   From: Makoto Matsumoto and Takuji Nishimura, "Mersenne Twister: A
+   623-dimensionally equidistributerd uniform pseudorandom number
+   generator". ACM Transactions on Modeling and Computer Simulation,
+   Vol. 8, No. 1 (Jan. 1998), Pages 3-30
+
+   You can obtain the paper directly from Makoto Matsumoto's web page.
+
+   The period of this generator is 2^{19937} - 1.
+
+*/
+
+#include "rng.h"
+#include "common.h"
+#include <stdlib.h>
+#include <assert.h>
+
+
+/* default seed */
+unsigned long int default_seed = 4357;
+
+
+#define N 624   /* Period parameters */
+#define M 397
+
+/* most significant w-r bits */
+static const unsigned long UPPER_MASK = 0x80000000UL;   
+
+/* least significant r bits */
+static const unsigned long LOWER_MASK = 0x7fffffffUL;   
+
+
+static const unsigned long RNG_MIN = 0;
+static const unsigned long RNG_MAX = 0xffffffffUL;
+
+
+struct rng_t_
+{
+    unsigned long mt[N];
+    int mti;
+};
+
+
+static inline unsigned long mt_get(rng_t* state)
+{
+  unsigned long k ;
+  unsigned long int *const mt = state->mt;
+
+#define MAGIC(y) (((y)&0x1) ? 0x9908b0dfUL : 0)
+
+  if (state->mti >= N)
+    {   /* generate N words at one time */
+      int kk;
+
+      for (kk = 0; kk < N - M; kk++)
+        {
+          unsigned long y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
+          mt[kk] = mt[kk + M] ^ (y >> 1) ^ MAGIC(y);
+        }
+      for (; kk < N - 1; kk++)
+        {
+          unsigned long y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
+          mt[kk] = mt[kk + (M - N)] ^ (y >> 1) ^ MAGIC(y);
+        }
+
+      {
+        unsigned long y = (mt[N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
+        mt[N - 1] = mt[M - 1] ^ (y >> 1) ^ MAGIC(y);
+      }
+
+      state->mti = 0;
+    }
+
+  /* Tempering */
+  
+  k = mt[state->mti];
+  k ^= (k >> 11);
+  k ^= (k << 7) & 0x9d2c5680UL;
+  k ^= (k << 15) & 0xefc60000UL;
+  k ^= (k >> 18);
+
+  state->mti++;
+
+  return k;
+}
+
+double mt_get_double(rng_t* state)
+{
+  return mt_get(state) / 4294967296.0;
+}
+
+void mt_set(rng_t* state, unsigned long int s)
+{
+  int i;
+
+  if (s == 0)
+    s = 4357;   /* the default seed is 4357 */
+
+  state->mt[0]= s & 0xffffffffUL;
+
+  for (i = 1; i < N; i++)
+    {
+      /* See Knuth's "Art of Computer Programming" Vol. 2, 3rd
+         Ed. p.106 for multiplier. */
+
+      state->mt[i] =
+        (1812433253UL * (state->mt[i-1] ^ (state->mt[i-1] >> 30)) + i);
+      
+      state->mt[i] &= 0xffffffffUL;
+    }
+
+  state->mti = i;
+}
+
+#if 0 // these two seeding procedures are not used
+static void mt_1999_set(rng_t* state, unsigned long int s)
+{
+  int i;
+
+  if (s == 0)
+    s = 4357;   /* the default seed is 4357 */
+
+  /* This is the October 1999 version of the seeding procedure. It
+     was updated by the original developers to avoid the periodicity
+     in the simple congruence originally used.
+
+     Note that an ANSI-C unsigned long integer arithmetic is
+     automatically modulo 2^32 (or a higher power of two), so we can
+     safely ignore overflow. */
+
+#define LCG(x) ((69069 * x) + 1) &0xffffffffUL
+
+  for (i = 0; i < N; i++)
+    {
+      state->mt[i] = s & 0xffff0000UL;
+      s = LCG(s);
+      state->mt[i] |= (s &0xffff0000UL) >> 16;
+      s = LCG(s);
+    }
+
+  state->mti = i;
+}
+
+/* This is the original version of the seeding procedure, no longer
+   used but available for compatibility with the original MT19937. */
+
+static void mt_1998_set(rng_t* state, unsigned long int s)
+{
+  int i;
+
+  if (s == 0)
+    s = 4357;   /* the default seed is 4357 */
+
+  state->mt[0] = s & 0xffffffffUL;
+
+#define LCG1998(n) ((69069 * n) & 0xffffffffUL)
+
+  for (i = 1; i < N; i++)
+    state->mt[i] = LCG1998 (state->mt[i - 1]);
+
+  state->mti = i;
+}
+#endif
+
+rng_t* fastq_rng_alloc()
+{
+    rng_t* rng = malloc_or_die(sizeof(rng_t));
+    mt_set(rng, default_seed);
+    return rng;
+}
+
+
+void fastq_rng_free(rng_t* rng)
+{
+    free(rng);
+}
+
+void fastq_rng_seed(rng_t* rng, unsigned long seed)
+{
+    mt_set(rng, seed);
+}
+
+unsigned long fastq_rng_uniform_int(rng_t* rng, unsigned long k)
+{
+    unsigned long scale = (RNG_MAX - RNG_MIN) / k;
+    assert(scale > 0);
+    unsigned long r;
+
+    do {
+        r = (mt_get(rng) - RNG_MIN) / scale;
+    } while (r >= k);
+
+    return r;
+}
+