about summary refs log tree commit diff
path: root/src/utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/utils.c')
-rw-r--r--src/utils.c181
1 files changed, 181 insertions, 0 deletions
diff --git a/src/utils.c b/src/utils.c
new file mode 100644
index 0000000..0e0205f
--- /dev/null
+++ b/src/utils.c
@@ -0,0 +1,181 @@
+#include <gsl/gsl_blas.h>
+#include <gsl/gsl_math.h>
+#include <gsl/gsl_randist.h>
+#include <gsl/gsl_sf.h>
+#include <gsl/gsl_sf_gamma.h>
+#include "utils.h"
+
+// This function exists so that guile code can access the value of
+// M_PI as provided by <gsl_math.h>.
+double pi ()
+{
+  /**
+   @return Value of pi
+  **/
+  return M_PI;
+}
+
+double volume_of_ball (unsigned int dimension)
+{
+  /**
+     @param dimension Dimension of the ball (2 for a circle, 3 for a sphere, etc.)
+     @return Volume of the unit ball
+   **/
+  return exp(ln_volume_of_ball(dimension));
+}
+
+double ln_volume_of_ball (unsigned int dimension)
+{
+  /**
+     @param dimension Dimension of the ball (2 for a circle, 3 for a sphere, etc.)
+     @return Natural logarithm of the volume of the unit ball
+   **/
+  return (dimension/2.0)*M_LNPI - gsl_sf_lngamma(1 + dimension/2.0);
+}
+
+double surface_area_of_ball (unsigned int dimension)
+{
+  /**
+     @param dimension Dimension of the ball (2 for a circle, 3 for a sphere, etc.)
+     @return Surface area of the unit ball
+   **/
+  return dimension * volume_of_ball(dimension);
+}
+
+double ln_surface_area_of_ball (unsigned int dimension)
+{
+  /**
+     @param dimension Dimension of the ball (2 for a circle, 3 for a sphere, etc.)
+     @return Natural logarithm of the surface area of the unit ball
+   **/
+  return log(dimension) + ln_volume_of_ball(dimension);
+}
+
+double lower_incomplete_gamma (double s, double x)
+{
+  return gsl_sf_gamma(s) * gsl_sf_gamma_inc_P(s, x);
+}
+
+double angle_between_vectors (const gsl_vector* x, const gsl_vector* y)
+{
+  /**
+     @param x Vector 1
+     @param y Vector 2
+     @return Angle between the two vectors in the range [0, pi]
+  **/
+  double dot_product;
+  gsl_blas_ddot(x, y, &dot_product);
+  // TODO: Is this a valid floating point comparison?
+  if (dot_product != 0)
+    return acos(dot_product / gsl_blas_dnrm2(x) / gsl_blas_dnrm2(y));
+  else return 0;
+}
+
+double dot_product (const gsl_vector* x, const gsl_vector* y)
+{
+  /**
+     @param x Vector 1
+     @param y Vector 2
+     @return Dot product between the two vectors
+  **/
+  double result;
+  gsl_blas_ddot(x, y, &result);
+  return result;
+}
+
+double gaussian_pdf (double x)
+{
+  /**
+     @param x
+     @return exp(-x^2/2) / sqrt(2*pi)
+   **/
+  return gsl_ran_gaussian_pdf(x, 1.0);
+}
+
+double gaussian_cdf (double x)
+{
+  /**
+     @param x
+     @return int_{-inf}^x gaussian_pdf(t) dt
+   **/
+  return 0.5*(1 + gsl_sf_erf(x/M_SQRT2));
+}
+
+double rerror (double approx, double exact)
+{
+  /**
+     @param approx Approximate value
+     @param exact Exact value
+     @return Relative error
+  **/
+  return fabs(1 - approx/exact);
+}
+
+double gprate (double start, double last, unsigned int n)
+{
+  /**
+     @param start First (0th) term of the geometric progression
+     @param last Last ('N-1'th) term of the geometric progression
+     @param n Number of terms in the geometric progression
+     @return The multiplicative factor of the geometric progression
+   **/
+  return pow(last/start, 1.0/(n - 1));
+}
+
+double gpterm (double a, double r, int n)
+{
+  /**
+     @param a First (0th) term of the geometric progression
+     @param r Factor of the geometric progression
+     @return The Nth term of the geometric progression, with N starting from 0
+   **/
+  return a * gsl_pow_uint(r, n);
+}
+
+#define BISECTION_EPSABS 0
+#define BISECTION_EPSREL 1e-6
+#define BISECTION_MAX_ITERATIONS 1000
+#define BISECTION_FUNCTION_EPSABS 1e-9
+double bisection (gsl_function* f, double a, double b)
+{
+  const gsl_root_fsolver_type* T = gsl_root_fsolver_bisection;
+  gsl_root_fsolver* s = gsl_root_fsolver_alloc(T);
+  double solution;
+  int status;
+
+  void error_handler (const char* reason, const char* file, int line, int gsl_errno)
+  {
+    fprintf(stderr, "Bisection error handler invoked.\n");
+    fprintf(stderr, "f(%g) = %g\n", a, GSL_FN_EVAL(f, a));
+    fprintf(stderr, "f(%g) = %g\n", b, GSL_FN_EVAL(f, b));
+    fprintf(stderr, "gsl: %s:%d: ERROR: %s\n", file, line, reason);
+    abort();
+  }
+
+  gsl_error_handler_t* old_handler = gsl_set_error_handler(error_handler);
+  gsl_root_fsolver_set(s, f, a, b);
+  do {
+    status = gsl_root_fsolver_iterate (s);
+    solution = gsl_root_fsolver_root (s);
+    a = gsl_root_fsolver_x_lower (s);
+    b = gsl_root_fsolver_x_upper (s);
+    status = gsl_root_test_interval (a, b, BISECTION_EPSABS, BISECTION_EPSREL);
+  } while (status == GSL_CONTINUE);
+  gsl_root_fsolver_free(s);
+  gsl_set_error_handler(old_handler);
+  return solution;
+}
+
+double bisection_rlimit (gsl_function* f, double a, double b)
+{
+  int sign = SIGNUM(GSL_FN_EVAL(f, a));
+  for (int i=0; i<BISECTION_MAX_ITERATIONS; i++)
+    if (sign*GSL_FN_EVAL(f, b) > 0) b *= 2;
+    else return b;
+  fprintf(stderr, "Bisection bracketing failed\n");
+  exit(1);
+}
+#undef BISECTION_EPSABS
+#undef BISECTION_EPSREL
+#undef BISECTION_MAX_ITERATIONS
+#undef BISECTION_FUNCTION_EPSABS