LibRan  0.1
Pseudo-random number distribution generator
LRpiece.c
Go to the documentation of this file.
1 
56 /*
57  * Copyright 2019 R.K. Owen, Ph.D.
58  * License see lgpl.md (Gnu Lesser General Public License)
59  */
60 #ifdef __cplusplus
61 extern "C" {
62 #endif
63 
64 #include <stdlib.h>
65 #include <math.h>
66 #include "libran.h"
67 
78 int LR_pcs_new(LR_obj *o, int n) {
79  LR_pcs *ptr = (LR_pcs *) o->aux;
80 
81  if (o->t != piece
82  && o->t != lspline)
83  return o->errno = LRerr_BadLRType;
84 
85  ptr->n = n;
86  ptr->nn = 1; /* always start with one interval */
87  ptr->c = 0;
88  ptr->norm = 0.;
89  ptr->flags = 0;
90 
91  if (!(ptr->bdrs = (double *) calloc(n, sizeof(double))))
92  goto bad0;
93 
94  if (!(ptr->c = (double *) calloc(n, sizeof(double))))
95  goto bad1;
96 
97  if (!(ptr->sc = (double *) calloc(n + 1, sizeof(double))))
98  goto bad2;
99 
100  return LRerr_OK;
101 
102 bad2:
103  free((void *) ptr->sc);
104 
105 bad1:
106  free((void *) ptr->c);
107 
108 bad0:
109  free((void *) ptr->bdrs);
110 
111  return o->errno = LRerr_AllocFail;
112 }
113 
122 int LR_pcs_rm(LR_obj *o) {
123  LR_pcs *aux;
124  if (o && (o->t == piece || o->t == lspline)
125  && o->aux) {
126  aux = (LR_pcs *) o->aux;
127  free((void *) aux->bdrs);
128  free((void *) aux->c);
129  free((void *) aux->sc);
130  return LRerr_OK;
131  }
132  return o->errno = LRerr_Unspecified;
133 }
134 
158 int LR_pcs_set(LR_obj *o, double x, double p) {
159  int i = 0;
160  double t, tp;
161  LR_pcs *aux = (LR_pcs *) o->aux;
162  if (aux->n < aux->nn + 1) {
163  /* too many values given */
164  return o->errno = LRerr_TooManyValues;
165  }
166  if (p < 0) {
167  /* invalid probability */
168  return o->errno = LRerr_InvalidInputValue;
169  }
170  if (o->d == LR_double) {
171  if (x < o->a.d || x > o->b.d)
172  /* bad range */
173  return o->errno = LRerr_InvalidRange;
174  } else if (o->d == LR_float) {
175  if (x < o->a.f || x > o->b.f)
176  /* bad range */
177  return o->errno = LRerr_InvalidRange;
178  }
179  t = aux->bdrs[0];
180  tp = aux->c[0];
181  for (int i = 0, i1 = 1; i <= aux->nn; i++,i1++) {
182  if (aux->nn == i1) { /* got to top entry */
183  aux->bdrs[i] = x;
184  aux->c[i] = p;
185  aux->nn++;
186  return LRerr_OK;
187  }
188  if (x > t) {
189  /* compare to next one, next round */
190  t = aux->bdrs[i1];
191  tp = aux->c[i1];
192  } else {
193  /* insert here, but keep current */
194  t = aux->bdrs[i];
195  tp = aux->c[i];
196  aux->bdrs[i] = x;
197  /* use current for comparison */
198  x = t;
199  p = tp;
200  t = aux->bdrs[i1];
201  tp = aux->c[i1];
202  }
203  }
204  aux->nn++;
205 
206  return LRerr_OK;
207 }
208 
221  double zero = 0.0, one = 1.0, delta = .000001;
222  double v= zero;
223  LR_pcs *aux = (LR_pcs *) o->aux;
224 
225  /* move up the set of values */
226  for (int i = aux->nn - 1, i1 = aux->nn - 2; i >= 1; i--, i1--) {
227  aux->bdrs[i] = aux->bdrs[i1];
228  aux->c[i] = aux->c[i1];
229  }
230  if (o->d == LR_double) {
231  aux->bdrs[0] = o->a.d;
232  aux->bdrs[aux->nn] = o->b.d;
233  aux->c[0] = o->x.d;
234  } else if (o->d == LR_float) {
235  aux->bdrs[0] = (double) o->a.f;
236  aux->bdrs[aux->nn] = (double) o->b.f;
237  aux->c[0] = (double) o->x.f;
238  }
239 
240  /* integrate over each interval */
241  aux->norm = zero;
242  for (int i = 0, i1 = 1; i < aux->nn; i++, i1++) {
243  aux->norm +=
244  aux->sc[i] = aux->c[i] * (aux->bdrs[i1] - aux->bdrs[i]);
245  }
246 
247  /* collect and rescale the CDF */
248  aux->norm = one/aux->norm;
249  for (int i = 0; i < aux->nn; i++) {
250  v += aux->sc[i];
251  aux->sc[i] = v * aux->norm;
252  }
253  /* shift the CDF set up */
254  if (aux->sc[aux->nn-1] < one - delta
255  || one + delta < aux->sc[aux->nn-1]) {
256  /* the last value should be 1.0 */
257  return o->errno = LRerr_SuspiciousValues;
258  }
259  for (int i = aux->nn-1; i > 0; i--) {
260  aux->sc[i] = aux->sc[i-1];
261  }
262  aux->sc[0] = zero;
263  aux->sc[aux->nn] = one;
264  /* norm success */
265  ((LR_pcs *) o->aux)->flags |= LR_AUX_NORM;
266 
267  return LRerr_OK;
268 }
269 
277 double LRd_piece_RAN(LR_obj *o) {
278  LR_pcs *aux = (LR_pcs *) o->aux;
279  double x, dx, zero = 0.0;
280  int i = 0;
281 
282  /* must have successfully normalized */
283  if (!(aux->flags & LR_AUX_NORM)) {
285  return NAN;
286  }
287 
288  x = o->ud(o);
289  /* find interval */
290  while (x > aux->sc[i]) i++;
291 
292  if (aux->c[i-1] == zero) return aux->bdrs[i-1];
293 
294  dx = (x - aux->sc[i-1]) / (aux->c[i-1] * aux->norm);
295  return aux->bdrs[i-1] + dx;
296 }
297 
305 double LRd_piece_PDF(LR_obj *o, double x) {
306  LR_pcs *aux = (LR_pcs *) o->aux;
307  double zero = 0.0;
308 
309  /* must have successfully normalized */
310  if (!(aux->flags & LR_AUX_NORM)) {
312  return NAN;
313  }
314 
315  if (x <= o->a.d || x > o->b.d) {
316  return zero;
317  } else {
318  /* find interval */
319  int i = 0;
320  while (x > aux->bdrs[i]) i++;
321  return aux->c[i-1] * aux->norm;
322  }
323 }
324 
332 double LRd_piece_CDF(LR_obj *o, double x) {
333  LR_pcs *aux = (LR_pcs *) o->aux;
334  double zero = 0.0, one = 1.0;
335 
336  /* must have successfully normalized */
337  if (!(aux->flags & LR_AUX_NORM)) {
339  return NAN;
340  }
341 
342  if (x <= o->a.d) {
343  return zero;
344  } else if (x >= o->b.d) {
345  return one;
346  } else {
347  /* find interval */
348  int i = 0;
349  while (x > aux->bdrs[i]) i++;
350  return aux->sc[i-1] + aux->c[i-1]*aux->norm*(x-aux->bdrs[i-1]);
351  }
352 }
353 
361  LR_pcs *aux = (LR_pcs *) o->aux;
362  float x, dx, zero = 0.0;
363  int i = 0;
364 
365  /* must have successfully normalized */
366  if (!(aux->flags & LR_AUX_NORM)) {
368  return NAN;
369  }
370 
371  x = o->ud(o);
372  /* find interval */
373  while (x > aux->sc[i]) i++;
374 
375  if (aux->c[i-1] == zero) return aux->bdrs[i-1];
376 
377  dx = (x - aux->sc[i-1]) / (aux->c[i-1] * aux->norm);
378  return aux->bdrs[i-1] + dx;
379 }
380 
388 float LRf_piece_PDF(LR_obj *o, float x) {
389  LR_pcs *aux = (LR_pcs *) o->aux;
390  float zero = 0.0;
391 
392  /* must have successfully normalized */
393  if (!(aux->flags & LR_AUX_NORM)) {
395  return NAN;
396  }
397 
398  if (x <= o->a.f || x > o->b.f) {
399  return zero;
400  } else {
401  /* find interval */
402  int i = 0;
403  while (x > aux->bdrs[i]) i++;
404  return aux->c[i-1] * aux->norm;
405  }
406 }
407 
415 float LRf_piece_CDF(LR_obj *o, float x) {
416  LR_pcs *aux = (LR_pcs *) o->aux;
417  float zero = 0.0, one = 1.0;
418 
419  /* must have successfully normalized */
420  if (!(aux->flags & LR_AUX_NORM)) {
422  return NAN;
423  }
424 
425  if (x <= o->a.f) {
426  return zero;
427  } else if (x >= o->b.f) {
428  return one;
429  } else {
430  /* find interval */
431  int i = 0;
432  while (x > aux->bdrs[i]) i++;
433  return aux->sc[i-1] + aux->c[i-1]*aux->norm*(x-aux->bdrs[i-1]);
434  }
435 }
436 
437 #ifdef __cplusplus
438 }
439 #endif
double * sc
Definition: libran.h:211
LR_val b
Definition: libran.h:139
#define LRerr_SuspiciousValues
Definition: libran.h:44
#define LRerr_OK
Definition: libran.h:32
LR_data_type d
Definition: libran.h:137
Definition: libran.h:59
#define LRerr_TooManyValues
Definition: libran.h:40
void * aux
Definition: libran.h:168
Definition: libran.h:60
int LR_pcs_rm(LR_obj *o)
LR_pcs_rm(LR_obj *o) - strip out the LR_pcs object part of LR_obj.
Definition: LRpiece.c:122
int LR_pcs_set(LR_obj *o, double x, double p)
LR_pcs_set(LR_obj *o, double x) - add interval boundary (will order internally).
Definition: LRpiece.c:158
LR_val x
Definition: libran.h:142
A special object for defining some of the random variate distributions.
Definition: libran.h:206
int nn
Definition: libran.h:208
float LRf_piece_PDF(LR_obj *o, float x)
LRf_piece_PDF(LR_obj *o, float x) - float piecewise uniform probablity distribution function...
Definition: LRpiece.c:388
int LR_pcs_new(LR_obj *o, int n)
LR_pcs_new(LR_obj *o, int n) - create a new piecewise uniform object set of segments.
Definition: LRpiece.c:78
#define LRerr_InvalidRange
Definition: libran.h:42
#define LR_AUX_NORM
Definition: libran.h:223
int n
Definition: libran.h:207
double LRd_piece_CDF(LR_obj *o, double x)
LRd_piece_CDF(LR_obj *o, double x) - double piecewise uniform cumulative distribution function...
Definition: LRpiece.c:332
#define LRerr_NoAuxNormalizeDone
Definition: libran.h:37
float LRf_piece_RAN(LR_obj *o)
LRf_piece_RAN(LR_obj *o) - float random piecewise uniform distribution.
Definition: LRpiece.c:360
int LR_pcs_norm(LR_obj *o)
LR_pcs_norm(LR_obj *o) - normalize the interval scale factors.
Definition: LRpiece.c:220
float LRf_piece_CDF(LR_obj *o, float x)
LRf_piece_CDF(LR_obj *o, float x) - float piecewise uniform cumulative distribution function...
Definition: LRpiece.c:415
double(* ud)(LR_obj *)
Definition: libran.h:154
#define LRerr_AllocFail
Definition: libran.h:45
LR_type t
Definition: libran.h:136
double * c
Definition: libran.h:210
int flags
Definition: libran.h:213
double LRd_piece_RAN(LR_obj *o)
LRd_piece_RAN(LR_obj *o) - double random piecewise uniform distribution random variate.
Definition: LRpiece.c:277
double norm
Definition: libran.h:212
int errno
Definition: libran.h:169
LR_val a
Definition: libran.h:138
#define LRerr_BadLRType
Definition: libran.h:35
double d
Definition: libran.h:87
float f
Definition: libran.h:86
The LibRan common header file.
#define LRerr_Unspecified
Definition: libran.h:33
#define LRerr_InvalidInputValue
Definition: libran.h:41
double LRd_piece_PDF(LR_obj *o, double x)
LRd_piece_PDF(LR_obj *o, double x) - double piecewise uniform probablity distribution function...
Definition: LRpiece.c:305
the fundamental LibRan random variate distribution object
Definition: libran.h:134
double * bdrs
Definition: libran.h:209