gnuastro-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gnuastro-commits] master 7107667 1/3: Unified GSL random number generat


From: Mohammad Akhlaghi
Subject: [gnuastro-commits] master 7107667 1/3: Unified GSL random number generator environment setup
Date: Thu, 13 Sep 2018 14:27:51 -0400 (EDT)

branch: master
commit 7107667b67f49057d6cdf5f5606db93f63d841d0
Author: Mohammad Akhlaghi <address@hidden>
Commit: Mohammad Akhlaghi <address@hidden>

    Unified GSL random number generator environment setup
    
    Until now the three programs that use GSL's random number generator
    (MakeCatalog, MakeProfiles, and MakeNoise) would each call GSL's functions
    directly. But this is very inconvenient when an issue is found that must be
    checked and fixed in all of them. A wrapper internal function
    (`gal_checkset_gsl_rng') has been introduced with this commit to simplify
    this process.
    
    This was sparked by finding out we weren't writing the proper seed value
    into the FITS keyword of MakeProfile's outputs when `--envseed' was
    used. To avoid having to check/fix the problem in all such programs, we now
    have this high-level GSL wrapper.
---
 bin/mkcatalog/ui.c               |  8 +-----
 bin/mknoise/main.h               |  4 +--
 bin/mknoise/mknoise.c            |  7 ++---
 bin/mknoise/ui.c                 | 14 +++-------
 bin/mkprof/main.h                |  1 +
 bin/mkprof/mkprof.c              |  8 +++---
 bin/mkprof/ui.c                  |  8 +++---
 bootstrap.conf                   |  1 +
 doc/gnuastro.texi                | 43 +++++++++++++++++++-----------
 lib/checkset.c                   | 57 ++++++++++++++++++++++++++++++++++++++--
 lib/gnuastro-internal/checkset.h | 10 ++++---
 11 files changed, 110 insertions(+), 51 deletions(-)

diff --git a/bin/mkcatalog/ui.c b/bin/mkcatalog/ui.c
index 0298562..91a151b 100644
--- a/bin/mkcatalog/ui.c
+++ b/bin/mkcatalog/ui.c
@@ -1341,13 +1341,7 @@ ui_preparations_upperlimit(struct mkcatalogparams *p)
           "that is reported as the upper-limit");
 
   /* Set the random number generator. */
-  gsl_rng_env_setup();
-  p->rng=gsl_rng_alloc(gsl_rng_ranlxs1);
-  p->seed = ( p->envseed
-              ? gsl_rng_default_seed
-              : gal_timing_time_based_rng_seed() );
-  if(p->envseed) gsl_rng_set(p->rng, p->seed);
-  p->rngname=gsl_rng_name(p->rng);
+  p->rng=gal_checkset_gsl_rng(p->envseed, &p->rngname, &p->seed);
 
   /* Keep the minimum and maximum values of the random number generator. */
   p->rngmin=gsl_rng_min(p->rng);
diff --git a/bin/mknoise/main.h b/bin/mknoise/main.h
index 25ab114..c443f2c 100644
--- a/bin/mknoise/main.h
+++ b/bin/mknoise/main.h
@@ -54,8 +54,8 @@ struct mknoiseparams
   gal_data_t      *input;    /* Input image data in double precision.    */
   double      background;    /* Background in units of brightness.       */
   gsl_rng           *rng;    /* Main instance of random number generator.*/
-  char         *rng_type;    /* The type of the Random number gen.       */
-  int64_t       rng_seed;    /* Seed of Random number generator.         */
+  const char   *rng_name;    /* The type/name of the Random number gen.  */
+  uint64_t      rng_seed;    /* Seed of Random number generator.         */
   time_t         rawtime;    /* Starting time of the program.            */
 };
 
diff --git a/bin/mknoise/mknoise.c b/bin/mknoise/mknoise.c
index 9abbfe1..5c9d085 100644
--- a/bin/mknoise/mknoise.c
+++ b/bin/mknoise/mknoise.c
@@ -87,10 +87,11 @@ convertsaveoutput(struct mknoiseparams *p)
     }
   strcpy(keyname4, "RNGTYPE");
   gal_fits_key_list_add_end(&headers, GAL_TYPE_STRING, keyname4, 0,
-                            p->rng_type, 0, "Random number generator (by "
-                            "GSL) type.",  0, NULL);
+                            (void *)(p->rng_name), 0,
+                            "Random number generator (by GSL) type.",
+                            0, NULL);
   strcpy(keyname5, "RNGSEED");
-  gal_fits_key_list_add_end(&headers, GAL_TYPE_INT64, keyname5, 0,
+  gal_fits_key_list_add_end(&headers, GAL_TYPE_UINT64, keyname5, 0,
                             &p->rng_seed, 0,
                             "Random number generator (by GSL) seed.",
                             0, NULL);
diff --git a/bin/mknoise/ui.c b/bin/mknoise/ui.c
index 2ab9849..54a807d 100644
--- a/bin/mknoise/ui.c
+++ b/bin/mknoise/ui.c
@@ -311,13 +311,7 @@ ui_preparations(struct mknoiseparams *p)
 
 
   /* Allocate the random number generator: */
-  gsl_rng_env_setup();
-  p->rng=gsl_rng_alloc(gsl_rng_ranlxs1);
-  p->rng_seed = ( p->envseed
-                  ? gsl_rng_default_seed
-                  : gal_timing_time_based_rng_seed() );
-  gsl_rng_set(p->rng, p->rng_seed);
-  gal_checkset_allocate_copy(gsl_rng_name(p->rng), &p->rng_type);
+  p->rng=gal_checkset_gsl_rng(p->envseed, &p->rng_name, &p->rng_seed);
 }
 
 
@@ -404,10 +398,9 @@ ui_read_check_inputs_setup(int argc, char *argv[], struct 
mknoiseparams *p)
     {
       printf(PROGRAM_NAME" "PACKAGE_VERSION" started on %s",
              ctime(&p->rawtime));
-      sprintf(message, "Random number generator type: %s",
-              gsl_rng_name(p->rng));
+      sprintf(message, "Random number generator type: %s", p->rng_name);
       gal_timing_report(NULL, message, 1);
-      sprintf(message, "Random number generator seed: %"PRId64, p->rng_seed);
+      sprintf(message, "Random number generator seed: %"PRIu64, p->rng_seed);
       gal_timing_report(NULL, message, 1);
     }
 }
@@ -439,7 +432,6 @@ ui_free_report(struct mknoiseparams *p, struct timeval *t1)
 {
   /* Free the allocated arrays: */
   free(p->cp.hdu);
-  free(p->rng_type);
   free(p->cp.output);
   gal_data_free(p->input);
 
diff --git a/bin/mkprof/main.h b/bin/mkprof/main.h
index 8d5eac0..4f6fa4e 100644
--- a/bin/mkprof/main.h
+++ b/bin/mkprof/main.h
@@ -170,6 +170,7 @@ struct mkprofparams
   float                  *t;  /* Truncation distance.                     */
   gsl_rng              *rng;  /* Main instance of random number generator.*/
   const char      *rng_name;  /* Name of random number generator.         */
+  uint64_t         rng_seed;  /* Fixed seed of random number generator.   */
   time_t            rawtime;  /* Starting time of the program.            */
   double               *cat;  /* Input catalog.                           */
   gal_data_t           *log;  /* Log data to be printed.                  */
diff --git a/bin/mkprof/mkprof.c b/bin/mkprof/mkprof.c
index 2dd18cb..60330e3 100644
--- a/bin/mkprof/mkprof.c
+++ b/bin/mkprof/mkprof.c
@@ -197,12 +197,12 @@ saveindividual(struct mkonthread *mkp)
   gal_fits_key_list_add(&keys, GAL_TYPE_FLOAT32, "TRUNCATION", 0,
                         &p->t[id], 0, "Truncation of profile in catalog",
                         0, NULL);
-  gal_fits_key_list_add(&keys, GAL_TYPE_LONG, "RNGSEED", 0,
-                        &mkp->rng_seed, 0, "Seed of random number generator",
-                        0, NULL);
   gal_fits_key_list_add(&keys, GAL_TYPE_STRING, "RNGNAME", 0,
                         (void *)(p->rng_name), 0,
                         "Name of random number generator", 0, NULL);
+  gal_fits_key_list_add(&keys, GAL_TYPE_LONG, "RNGSEED", 0,
+                        &mkp->rng_seed, 0, "Seed of random number generator",
+                        0, NULL);
   gal_fits_key_list_add(&keys, GAL_TYPE_SIZE_T, "NUMRANDOM", 0,
                         &p->numrandom, 0,
                         "Number of random points in central pixels", 0, NULL);
@@ -297,7 +297,7 @@ mkprof_build_single(struct mkonthread *mkp, long *fpixel_i, 
long *lpixel_i,
   /* Set the seed of the random number generator if the
      environment is not to be used. */
   if(mkp->p->envseed)
-    mkp->rng_seed=mkp->p->envseed;
+    mkp->rng_seed=mkp->p->rng_seed;
   else
     {
       mkp->rng_seed=gal_timing_time_based_rng_seed();
diff --git a/bin/mkprof/ui.c b/bin/mkprof/ui.c
index 391146a..ef0580e 100644
--- a/bin/mkprof/ui.c
+++ b/bin/mkprof/ui.c
@@ -1363,10 +1363,8 @@ ui_preparations(struct mkprofparams *p)
   if(p->wcs)
     ui_finalize_coordinates(p);
 
-  /* Allocate the random number generator: */
-  gsl_rng_env_setup();
-  p->rng=gsl_rng_alloc(gsl_rng_ranlxs1);
-  p->rng_name=gsl_rng_name(p->rng);
+  /* Prepare the random number generator. */
+  p->rng=gal_checkset_gsl_rng(p->envseed, &p->rng_name, &p->rng_seed);
 
   /* Make the log linked list. */
   ui_make_log(p);
@@ -1449,6 +1447,8 @@ ui_print_intro(struct mkprofparams *p)
       gal_timing_report(NULL, jobname, 1);
       free(jobname);
     }
+  else
+    gal_timing_report(NULL, "RNG seed differs for each profile.", 1);
 
   if(p->kernel==NULL)
     {
diff --git a/bootstrap.conf b/bootstrap.conf
index 9c6d47b..32118c1 100644
--- a/bootstrap.conf
+++ b/bootstrap.conf
@@ -227,6 +227,7 @@ gnulib_modules="
     mbstok_r
     inttypes
     system-posix
+    secure_getenv
     git-version-gen
 "
 
diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index d96f174..638559e 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -18475,6 +18475,8 @@ deviation of the final distribution (and thus bias the 
upper-limit
 measurement).
 
 @item --envseed
address@hidden Seed, Random number generator
address@hidden Random number generator, Seed
 Read the random number generator type and seed value from the environment
 (see @ref{Generating random numbers}). Random numbers are used in
 calculating the random positions of different samples of each object.
@@ -19619,6 +19621,8 @@ distribution. This can be done by setting the 
@code{GSL_RNG_TYPE} and
 with the @option{--envseed} option. To learn more about the process of
 generating random numbers, see @ref{Generating random numbers}.
 
address@hidden Seed, Random number generator
address@hidden Random number generator, Seed
 The seed values are fixed for every profile: with @option{--envseed},
 all the profiles have the same seed and without it, each will get a
 different seed using the system clock (which is accurate to within one
@@ -20047,6 +20051,8 @@ profile, see @ref{Sampling from a function}.
 
 @item -e
 @itemx --envseed
address@hidden Seed, Random number generator
address@hidden Random number generator, Seed
 Use the value to the @code{GSL_RNG_SEED} environment variable to
 generate the random Monte Carlo sampling distribution, see
 @ref{Sampling from a function} and @ref{Generating random
@@ -20666,7 +20672,6 @@ affordable!}!
 
 @cindex Psudo-random numbers
 @cindex Numbers, psudo-random
address@hidden Seed, psudo-random numbers
 Using only software, we can only produce what is called a psudo-random
 sequence of numbers. A true random number generator is a hardware (let's
 assume we have made sure it has no systematic biases), for example
@@ -20692,17 +20697,19 @@ them!). Through the two environment variables 
@code{GSL_RNG_TYPE} and
 @code{GSL_RNG_SEED} you can specify the generator and its seed
 respectively.
 
address@hidden Seed, Random number generator
address@hidden Random number generator, Seed
 If you don't specify a value for @code{GSL_RNG_TYPE}, GSL will use its
-default random number generator type. The default type is sufficient
-for most general applications. If no value is given for the
address@hidden environment variable and you have asked Gnuastro
-to read the seed from the environment (through the @option{--envseed}
-option), then GSL will use the default value of each generator to give
-identical outputs. If you don't explicitly tell Gnuastro programs to
-read the seed value from the environment variable, then they will use
-the system time (accurate to within a microsecond) to generate
-(apparently random) seeds. In this manner, every time you run the
-program, you will get a different random number distribution.
+default random number generator type. The default type is sufficient for
+most general applications. If no value is given for the @code{GSL_RNG_SEED}
+environment variable and you have asked Gnuastro to read the seed from the
+environment (through the @option{--envseed} option), then GSL will use the
+default value of each generator to give identical outputs. If you don't
+explicitly tell Gnuastro programs to read the seed value from the
+environment variable, then they will use the system time (accurate to
+within a microsecond) to generate (apparently random) seeds. In this
+manner, every time you run the program, you will get a different random
+number distribution.
 
 There are two ways you can specify values for these environment
 variables. You can call them on the same command-line for example:
@@ -20747,16 +20754,20 @@ can see the top few lines of the output of 
MakeProfiles:
 @example
 $ export GSL_RNG_TYPE="taus"
 $ export GSL_RNG_SEED=345
-$ astmkprof catalog.txt --envseed
+$ astmkprof -s1 --kernel=gaussian,2,5 --envseed
 GSL_RNG_TYPE=taus
 GSL_RNG_SEED=345
-MakeProfiles started on AAA BBB DD EE:FF:GG HHH
-  - 6 profiles read from catalog.txt 0.000236 seconds
-  - Random number generator (RNG) type: taus
+MakeProfiles A.B started on DDD MMM DD HH:MM:SS YYYY
+  - Building one gaussian kernel
+  - Random number generator (RNG) type: ranlxs1
   - RNG seed for all profiles: 345
+  ---- ./kernel.fits created.
+MakeProfiles finished in 0.111271 seconds
 @end example
 
 @noindent
address@hidden Seed, Random number generator
address@hidden Random number generator, Seed
 The first two output lines (showing the names of the environment
 variables) are printed by GSL before MakeProfiles actually starts
 generating random numbers. The Gnuastro programs will report the
@@ -20828,6 +20839,8 @@ noise}.
 
 @item -e
 @itemx --envseed
address@hidden Seed, Random number generator
address@hidden Random number generator, Seed
 Use the @code{GSL_RNG_SEED} environment variable for the seed used in
 the random number generator, see @ref{Generating random numbers}. With
 this option, the output image noise is always going to be identical
diff --git a/lib/checkset.c b/lib/checkset.c
index af5d01c..b58e96f 100644
--- a/lib/checkset.c
+++ b/lib/checkset.c
@@ -30,10 +30,9 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <unistd.h>
 #include <sys/stat.h>
 
-#include <fitsio.h>
-
 #include <gnuastro/data.h>
 
+#include <gnuastro-internal/timing.h>
 #include <gnuastro-internal/checkset.h>
 
 
@@ -44,6 +43,60 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 
 
+/**************************************************************/
+/**********               Environment              ************/
+/**************************************************************/
+/* The GSL random number generator (RNG) reads values from the
+   environment. This function is designed to make the job easier for any
+   program using GSL's RNG. If the user doesn't want to set the */
+gsl_rng *
+gal_checkset_gsl_rng(uint8_t envseed_bool, const char **name, uint64_t *seed)
+{
+  gsl_rng *rng;
+
+  /* Let GSL read the environment and convert the type name (as string) to
+     `gsl_rng_type'. After this function, `gsl_rng_default' contains the
+     generator's type and `gsl_rng_default_seed' contains the (possibly)
+     given seed.*/
+  gsl_rng_env_setup();
+
+  /* Allocate the random number generator based on the requested type and
+     save its name. If no `GSL_RNG_TYPE' is set, then use a fixed
+     generator.*/
+  rng=gsl_rng_alloc(secure_getenv("GSL_RNG_TYPE")
+                    ? gsl_rng_default
+                    : gsl_rng_ranlxs1);
+  *name = gsl_rng_name(rng);
+
+  /* Initialize the random number generator, depending on the
+     `envseed_bool' argument. */
+  *seed = ( envseed_bool
+            ? gsl_rng_default_seed
+            : gal_timing_time_based_rng_seed() );
+  gsl_rng_set(rng, *seed);
+
+  /* Return the GSL RNG structure. */
+  return rng;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 
 /**************************************************************/
 /**********          My String functions:          ************/
diff --git a/lib/gnuastro-internal/checkset.h b/lib/gnuastro-internal/checkset.h
index ee6314a..204c325 100644
--- a/lib/gnuastro-internal/checkset.h
+++ b/lib/gnuastro-internal/checkset.h
@@ -27,6 +27,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
    must be included before the C++ preparations below */
 #include <math.h>
 #include <fitsio.h>
+#include <gsl/gsl_rng.h>
 #include <gnuastro-internal/options.h>
 
 /* C++ Preparations */
@@ -49,9 +50,12 @@ __BEGIN_C_DECLS  /* From C++ preparations */
 
 
 
-
-
-
+/**************************************************************/
+/**********               Environment              ************/
+/**************************************************************/
+gsl_rng *
+gal_checkset_gsl_rng(uint8_t envseed_bool, const char **name,
+                     uint64_t *seed);
 
 
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]