LibRan  0.1
Pseudo-random number distribution generator
LRlspline.c
Go to the documentation of this file.
1 
65 /*
66  * Copyright 2019 R.K. Owen, Ph.D.
67  * License see lgpl.md (Gnu Lesser General Public License)
68  */
69 #ifdef __cplusplus
70 extern "C" {
71 #endif
72 
73 #include <stdlib.h>
74 #include <math.h> /* sqrt, sqrtf, NAN */
75 #include "libran.h"
76 #include <stdio.h>
77 
88 int LR_lspl_new(LR_obj *o, int n) {
89  return LR_pcs_new(o,n);
90 }
91 
101  return LR_pcs_rm(o);
102 }
103 
128 int LR_lspl_set(LR_obj *o, double x, double p) {
129  int ret = LR_pcs_set(o,x,p);
130  /* must have at least one good value set */
131  if ((!ret) && (p > 0))
132  ((LR_pcs *) o->aux)->flags |= LR_AUX_SET;
133  return ret;
134 }
135 
148  double zero = 0.0, half = 0.5, one = 1.0, delta = .000001;
149  double v = zero;
150  LR_pcs *aux = (LR_pcs *) o->aux;
151 
152  /* must have at least one good value set else why bother? */
153  if (!(aux->flags & LR_AUX_SET))
154  return o->errno = LRerr_UnmetPreconditions;
155 
156  /* move up the set of values */
157  for (int i = aux->nn - 1, i1 = aux->nn - 2; i >= 1; i--, i1--) {
158  aux->bdrs[i] = aux->bdrs[i1];
159  aux->c[i] = aux->c[i1];
160  }
161  if (o->d == LR_double) {
162  aux->bdrs[0] = o->a.d;
163  aux->bdrs[aux->nn] = o->b.d;
164  aux->c[0] = o->x.d;
165  } else if (o->d == LR_float) {
166  aux->bdrs[0] = (double) o->a.f;
167  aux->bdrs[aux->nn] = (double) o->b.f;
168  aux->c[0] = (double) o->x.f;
169  }
170 
171  /* integrate over each interval */
172  aux->norm = zero;
173  for (int i = 0, i1 = 1; i < aux->nn; i++, i1++) {
174  aux->norm +=
175  aux->sc[i] = half * (aux->c[i1] + aux->c[i])
176  * (aux->bdrs[i1] - aux->bdrs[i]);
177  }
178 
179  /* collect and rescale the CDF */
180  aux->norm = one/aux->norm;
181  for (int i = 0; i < aux->nn; i++) {
182  v += aux->sc[i];
183  aux->sc[i] = v * aux->norm;
184  }
185  /* shift the CDF set up */
186  if (aux->sc[aux->nn-1] < one - delta
187  || one + delta < aux->sc[aux->nn-1]) {
188  /* the last value should be 1.0 */
189  return o->errno = LRerr_SuspiciousValues;
190  }
191  for (int i = aux->nn-1; i > 0; i--) {
192  aux->sc[i] = aux->sc[i-1];
193  }
194  aux->sc[0] = zero;
195  aux->sc[aux->nn] = one;
196  /* norm success */
197  ((LR_pcs *) o->aux)->flags |= LR_AUX_NORM;
198 
199  return LRerr_OK;
200 }
201 
210  LR_pcs *aux = (LR_pcs *) o->aux;
211  double x, y, dy, slope, zero = 0.0, two = 2.0;
212  int i = 0;
213 
214  /* must have successfully normalized */
215  if (!(aux->flags & LR_AUX_NORM)) {
217  return NAN;
218  }
219 
220  x = o->ud(o);
221  /* find interval */
222  while (x >= aux->sc[i]) i++;
223 
224  /* use inverse method to return variate */
225  slope = ((aux->c[i] - aux->c[i-1]) * aux->norm) /
226  (aux->bdrs[i] - aux->bdrs[i-1]);
227 
228  y = aux->c[i-1] * aux->norm;
229  x -= aux->sc[i-1];
230  dy = (sqrt(y*y + two*slope*(x)) - y)/slope;
231 
232  y = aux->bdrs[i-1] + dy;
233 /*
234  printf(">>>>>% 8.5f % 8.5f % 8.5f\n",
235  y, aux->sc[i-1] + x, LRd_CDF(o, y));
236 */
237  return y;
238 }
239 
247 double LRd_lspline_PDF(LR_obj *o, double x) {
248  LR_pcs *aux = (LR_pcs *) o->aux;
249 
250  /* must have successfully normalized */
251  if (!(aux->flags & LR_AUX_NORM)) {
253  return NAN;
254  }
255 
256  if (x <= o->a.d || x >= o->b.d) {
257  return 0.0;
258  } else {
259  /* find interval */
260  int i = 0;
261  double slope, y;
262  while (x > aux->bdrs[i]) i++;
263  slope = (aux->c[i] - aux->c[i-1]) /
264  (aux->bdrs[i] - aux->bdrs[i-1]);
265  y = (aux->c[i-1] + (slope * (x - aux->bdrs[i-1])))
266  *aux->norm;
267 /*
268  printf("lspline_PDF>>>>>% 8.5f % 8.5f\n", x, y);
269 */
270  return y;
271  }
272 }
273 
281 double LRd_lspline_CDF(LR_obj *o, double x) {
282  LR_pcs *aux = (LR_pcs *) o->aux;
283  double zero = 0.0, one = 1.0, half = 0.5, y;
284 
285  /* must have successfully normalized */
286  if (!(aux->flags & LR_AUX_NORM)) {
288  return NAN;
289  }
290 
291  if (x <= o->a.d) {
292  return zero;
293  } else if (x >= o->b.d) {
294  return one;
295  } else {
296  /* find interval */
297  int i = 0;
298  double diff, slope;
299  while (x > aux->bdrs[i]) i++;
300  diff = (x - aux->bdrs[i-1]);
301  slope = (aux->c[i] - aux->c[i-1]) /
302  (aux->bdrs[i] - aux->bdrs[i-1]);
303  y = (aux->c[i-1] + (slope * diff));
304  y = aux->sc[i-1] + half * (y + aux->c[i-1])*diff*aux->norm;
305 /*
306  printf("lspline_CDF>>>>>% 8.5f % 8.5f\n", x, y);
307 */
308  return y;
309  }
310 }
311 
319  LR_pcs *aux = (LR_pcs *) o->aux;
320  float x, y, dy, slope, zero = 0.0, two = 2.0;
321  int i = 0;
322 
323  /* must have successfully normalized */
324  if (!(aux->flags & LR_AUX_NORM)) {
326  return NAN;
327  }
328 
329  x = o->uf(o);
330  /* find interval */
331  while (x >= aux->sc[i]) i++;
332 
333  /* use inverse method to return variate */
334  slope = ((aux->c[i] - aux->c[i-1]) * aux->norm) /
335  (aux->bdrs[i] - aux->bdrs[i-1]);
336 
337  y = aux->c[i-1] * aux->norm;
338  x -= aux->sc[i-1];
339  dy = (sqrtf(y*y + two*slope*(x)) - y)/slope;
340 
341  y = aux->bdrs[i-1] + dy;
342 /*
343  printf(">>>>>% 8.5f % 8.5f % 8.5f\n",
344  y, aux->sc[i-1] + x, LRf_CDF(o, y));
345 */
346  return y;
347 }
348 
356 float LRf_lspline_PDF(LR_obj *o, float x) {
357  LR_pcs *aux = (LR_pcs *) o->aux;
358 
359  /* must have successfully normalized */
360  if (!(aux->flags & LR_AUX_NORM)) {
362  return NAN;
363  }
364 
365  if (x <= o->a.f || x >= o->b.f) {
366  return 0.0;
367  } else {
368  /* find interval */
369  int i = 0;
370  float slope, y;
371  while (x > aux->bdrs[i]) i++;
372  slope = (aux->c[i] - aux->c[i-1]) /
373  (aux->bdrs[i] - aux->bdrs[i-1]);
374  y = (aux->c[i-1] + (slope * (x - aux->bdrs[i-1])))
375  *aux->norm;
376 /*
377  printf("lspline_PDF>>>>>% 8.5f % 8.5f\n", x, y);
378 */
379  return y;
380  }
381 }
382 
390 float LRf_lspline_CDF(LR_obj *o, float x) {
391  LR_pcs *aux = (LR_pcs *) o->aux;
392  float zero = 0.0, one = 1.0, half = 0.5, y;
393 
394  /* must have successfully normalized */
395  if (!(aux->flags & LR_AUX_NORM)) {
397  return NAN;
398  }
399 
400  if (x <= o->a.f) {
401  return zero;
402  } else if (x >= o->b.f) {
403  return one;
404  } else {
405  /* find interval */
406  int i = 0;
407  float diff, slope;
408  while (x > aux->bdrs[i]) i++;
409  diff = (x - aux->bdrs[i-1]);
410  slope = (aux->c[i] - aux->c[i-1]) /
411  (aux->bdrs[i] - aux->bdrs[i-1]);
412  y = (aux->c[i-1] + (slope * diff));
413  y = aux->sc[i-1] + half * (y + aux->c[i-1])*diff*aux->norm;
414 /*
415  printf("lspline_CDF>>>>>% 8.5f % 8.5f\n", x, y);
416 */
417  return y;
418  }
419 }
420 
421 #ifdef __cplusplus
422 }
423 #endif
int LR_lspl_new(LR_obj *o, int n)
LR_lspl_new(LR_obj *o, int n) - create a new linear spline object.
Definition: LRlspline.c:88
int LR_lspl_rm(LR_obj *o)
LR_lspl_rm(LR_obj *o) - strip out the LR_lspl object part of LR_obj.
Definition: LRlspline.c:100
double * sc
Definition: libran.h:211
LR_val b
Definition: libran.h:139
#define LRerr_OK
Definition: libran.h:32
#define LRerr_SuspiciousValues
Definition: libran.h:44
LR_data_type d
Definition: libran.h:137
void * aux
Definition: libran.h:168
float LRf_lspline_PDF(LR_obj *o, float x)
LRf_lspline_PDF(LR_obj *o, float x) - float linear spline probablity distribution function...
Definition: LRlspline.c:356
LR_val x
Definition: libran.h:142
#define LR_AUX_SET
Definition: libran.h:224
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
#define LRerr_UnmetPreconditions
Definition: libran.h:43
A special object for defining some of the random variate distributions.
Definition: libran.h:206
int nn
Definition: libran.h:208
int LR_lspl_set(LR_obj *o, double x, double p)
LR_lspl_set(LR_obj *o, double x) - add interval boundary (will order internally). ...
Definition: LRlspline.c:128
float LRf_lspline_RAN(LR_obj *o)
LRf_lspline_RAN(LR_obj *o) - float random linear spline distribution.
Definition: LRlspline.c:318
#define LR_AUX_NORM
Definition: libran.h:223
#define LRerr_NoAuxNormalizeDone
Definition: libran.h:37
double LRd_lspline_CDF(LR_obj *o, double x)
LRd_lspline_CDF(LR_obj *o, double x) - double linear spline cumulative distribution function...
Definition: LRlspline.c:281
double LRd_lspline_PDF(LR_obj *o, double x)
LRd_lspline_PDF(LR_obj *o, double x) - double linear spline probablity distribution function...
Definition: LRlspline.c:247
double(* ud)(LR_obj *)
Definition: libran.h:154
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
double * c
Definition: libran.h:210
int flags
Definition: libran.h:213
double norm
Definition: libran.h:212
int errno
Definition: libran.h:169
LR_val a
Definition: libran.h:138
double LRd_lspline_RAN(LR_obj *o)
LRd_lspline_RAN(LR_obj *o) - double random linear spline distribution random variate.
Definition: LRlspline.c:209
double d
Definition: libran.h:87
float f
Definition: libran.h:86
float(* uf)(LR_obj *)
Definition: libran.h:153
float LRf_lspline_CDF(LR_obj *o, float x)
LRf_lspline_CDF(LR_obj *o, float x) - float linear spline cumulative distribution function...
Definition: LRlspline.c:390
int LR_lspl_norm(LR_obj *o)
LR_lspl_norm(LR_obj *o) - normalize the interval scale factors.
Definition: LRlspline.c:147
The LibRan common header file.
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
the fundamental LibRan random variate distribution object
Definition: libran.h:134
double * bdrs
Definition: libran.h:209