File: helper.c

package info (click to toggle)
libmath-random-perl 0.72-3
  • links: PTS, VCS
  • area: non-free
  • in suites: forky, sid, trixie
  • size: 316 kB
  • sloc: ansic: 1,433; perl: 1,253; makefile: 8; sh: 1
file content (269 lines) | stat: -rw-r--r-- 8,356 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
/* NOTE: RETURN CODES HAVE BEEN CHANGED TO MATCH PERL, I.E.
   1 - NOW MEANS OK
   0 - NOW MEANS ERROR
   */

#include "randlib.h"
#include <stdio.h>
#include <stdlib.h>
#include "helper.h"

static long   *iwork = NULL; /* perl long array, alloc. in 'rspriw'  */
static double *fwork = NULL; /* perl float array, alloc. in 'rsprfw' */
static double *parm  = NULL; /* maintained by 'psetmn' for 'pgenmn'  */

/****************************************************************************
                Perl <-> C (Long) Integer Helper Functions
 (these pass single values back and forth, to load/read/manage working array)
 ****************************************************************************/

long gvpriw(long index) {
  /* Gets the Value at index of the PeRl (long) Integer Working array */
  extern long *iwork;
  
  return *(iwork + index);
}

int rspriw(long size) {
  /* Request Size for PeRl's (long) int Working array
   * returns:
   * 1 if successful
   * 0 if out of memory
   */
  extern long *iwork;
  static long siwork = 0L;

  if (size <= siwork) return 1;
  /* else reset array */
  if (iwork != NULL) free(iwork);
  iwork = (long *) malloc(sizeof(long) * size);
  if (iwork != NULL) {
    siwork = size;
    return 1;
  }
  fputs(" Unable to allocate randlib (long) int working array:\n",stderr);
  fprintf(stderr," Requested number of entries = %ld\n",size);
  fputs(" Out of memory in RSPRIW - ABORT\n",stderr);
  siwork = 0L;
  return 0;
}

/****************************************************************************
                Perl <-> C Float Helper Functions
 (these pass single values back and forth, to load/read/manage working array)
 ****************************************************************************/

double gvprfw(long index) {
  /* Gets the Value at index of the PeRl Float Working array */
  extern double *fwork;
  
  return *(fwork + index);
}

void svprfw(long index, double value) {
  /* Sets Value in PeRl's Float Working array */
  extern double *fwork;

  *(fwork + index) = value;
}
    
int rsprfw(long size) {
  /* Request Size for PeRl's Float Working array
   * returns:
   * 1 if successful
   * 0 if out of memory
   */
  extern double *fwork;
  static long sfwork = 0L;

  if (size <= sfwork) return 1;
  /* else reset array */
  if (fwork != NULL) free(fwork);
  fwork = (double*) malloc(sizeof(double) * size);
  if (fwork != NULL) {
    sfwork = size;
    return 1;
  }
  fputs(" Unable to allocate randlib float working array:\n",stderr);
  fprintf(stderr," Requested number of entries = %ld\n",size);
  fputs(" Out of memory in RSPRFW - ABORT\n",stderr);
  sfwork = 0L;
  return 0;
}

/*****************************************************************************
                           Randlib Helper Functions
      These routines call those randlib routines which depend on pointers
              (typically those with array input and/or output)
 *****************************************************************************/
void pgnprm(long n) {
  /* Perl's GeNerate PeRMutation
   * Fills perl's (long) integer working array with 0, ... ,n-1
   * and randomly permutes it.
   * Note: if n <= 0, it does what you'd expect:
   * N == 1: array of 0 of length 1
   * N <  1: array of length 0
   */

  /* NOTE: EITHER HERE OR IN PERL IWORK MUST HAVE SIZE CHECKED */

  extern long *iwork;
  long i;

  /* Fills working array ... */
  for (i=0L;i<n;i++)
    *(iwork + i) = i;

  /* ... and randomly permutes it */
  genprm(iwork,i);
}

void pgnmul (long n, long ncat) {
  /* Perl's GeNerate MULtinomial observation.
   * Method: uses void genmul(long n,double *p,long ncat,long *ix) in 'randlib.c'
   * Arguments:
   * n    - number of events to be classified.
   * ncat - number of categories into which the events are classified.
   * Notes:
   * *p - must be set up first in perl's double working array *fwork.
   *      must have at least ncat-1 categories and otherwise make sense.
   * *ix - (results) will be perl's (long) integer working array *iwork.
   */

  /* NOTE: FROM PERL, FWORK MUST HAVE SIZE CHECKED AND BE FILLED */
  /* ALSO, HERE OR IN PERL IWORK MUST HAVE SIZE CHECKED */

  extern long   *iwork;
  extern double *fwork;

  /* since all is OK so far, get the obs */
  genmul(n, fwork, ncat, iwork);
}

int psetmn(long p) {
  /*
   * Perl's SET Multivariate Normal
   * p - dimension of multivariate normal deviate
   *
   * Input:
   * fwork must be loaded as follows prior to call:
   *    Origin = 0 indexing           Origin = 1 indexing
   *    (reverse odometer)
   *       fwork[0]                 <-> mean[1]
   *       fwork[1]                 <-> mean[2]
   *        ...                          ...
   *       fwork[p - 1]             <-> mean[p]
   *       fwork[0 + 0*p + p]       <-> covm[1,1]
   *       fwork[1 + 0*p + p]       <-> covm[2,1]
   *        ...                          ...
   *       fwork[i-1 + (j-1)*p + p] <-> covm[i,j]
   *        ...                          ...
   *       fwork[p-1 + (p-1)*p + p] <-> covm[p,p]
   * Tot:  p*p + p elements                  p*p + p elements
   * This should all be done by the Perl calling routine.
   * 
   * Side Effects:
   * parm[p*(p+3)/2 + 1] is a file static array which contains all the
   * information needed to generate the deviates.
   * fwork is essentially destroyed (but not reallocated).
   *
   * Returns:
   * 1 if initialization succeeded
   * 0 if out of memory
   *
   * Method:
   * Calls 'setgmn' in "randlib.c":
   * void setgmn(double *meanv,double *covm,long p,double *parm)
   */
  
  extern double *fwork, *parm;
  static long oldp = 0L; /* p from last reallocate of parm */

  if (p > oldp) { /* pmn_param is too small; reallocate */
    if (parm != NULL) free(parm);
    parm = (double *) malloc(sizeof(double)*(p*(p+3L)/2L + 1L));
    if (parm == NULL) {
      fputs("Out of memory in PSETMN - ABORT",stderr);
      fprintf(stderr,
	      "P = %ld; Requested # of doubles %ld\n",p,p*(p+3L)/2L + 1L);
      oldp = 0L;
      return 0;
    } else {
      oldp = p; /* keep track of last reallocation */
    }
  }
  /* initialize parm */
  setgmn(fwork, fwork + p, p, parm);
  return 1;
}

int pgenmn(void) {
  /* 
   * Perl's GENerate Multivariate Normal
   *
   * Input: (None)
   * 
   * p - dimension of multivariate normal deviate - gotten from parm[].
   * 'psetmn' must be called successfully before this routine is called.
   * If that be so, then fwork[] has enough space for the deviate
   * and scratch space used by the routine, and parm[] has the
   * parameters needed.
   *
   * Output:
   * 0 - generation failed
   * 1 - generation succeeded
   *
   * Side Effects:
   * fwork[0] ... fwork[p-1] will contain the deviate.
   *
   * Method:
   * Calls 'genmn' in "randlib.c":
   * void genmn(double *parm,double *x,double *work)
   */
  
  extern double *fwork, *parm;

  /* NOTE: CHECK OF PARM ONLY NEEDED IF PERL SET/GENERATE IS SPLIT */

  if (parm != NULL) { /* initialized OK */
    long p = (long) *(parm);
    genmn(parm,fwork,fwork+p); /* put deviate in fwork */
    return 1;

  } else { /* not initialized - ABORT */
    fputs("PGENMN called before PSETMN called successfully - ABORT\n",
	  stderr);
    fputs("parm not properly initialized in PGENMN - ABORT\n",stderr);
    return 0;
  }
}

void salfph(char* phrase)
{
/*
**********************************************************************
     void salfph(char* phrase)
               Set ALl From PHrase

                              Function

     Uses a phrase (character string) to generate two seeds for the RGN
     random number generator, then sets the initial seed of generator 1
     to the results.  The initial seeds of the other generators are set
     accordingly, and all generators' states are set to these seeds.

                              Arguments
     phrase --> Phrase to be used for random number generation

                              Method
     Calls 'setall' (from com.c) with the results of 'phrtsd' (here in
     randlib.c).  Please see those functions' comments for details.
**********************************************************************
*/
extern void phrtsd(char* phrase,long *seed1,long *seed2);
extern void setall(long iseed1,long iseed2);
static long iseed1, iseed2;

phrtsd(phrase,&iseed1,&iseed2);
setall(iseed1,iseed2);
}