The R Project SVN R

Rev

Rev 87448 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 87448 Rev 89754
Line 36... Line 36...
36
/*
36
/*
37
   Note: the checks here for R_CheckUserInterrupt also do stack checking.
37
   Note: the checks here for R_CheckUserInterrupt also do stack checking.
38
 
38
 
39
   calloc/free are remapped for use in R, so allocation checks are done there.
39
   calloc/free are remapped for use in R, so allocation checks are done there.
40
   freeing is completed by an on.exit action in the R wrappers.
40
   freeing is completed by an on.exit action in the R wrappers.
-
 
41
 
-
 
42
   The Wilcoxon distribution is calculated using work from Andreas Loeffler
-
 
43
   https://upload.wikimedia.org/wikipedia/commons/f/f5/LoefflerWilcoxonMannWhitneyTest.pdf
-
 
44
   https://upload.wikimedia.org/wikipedia/de/1/19/MannWhitney_151102.pdf
41
*/
45
*/
42
 
46
 
-
 
47
#include <limits.h>
-
 
48
 
43
#include "nmath.h"
49
#include "nmath.h"
44
#include "dpq.h"
50
#include "dpq.h"
45
 
51
 
46
#ifndef MATHLIB_STANDALONE
52
#ifndef MATHLIB_STANDALONE
47
#include <R_ext/Utils.h>
53
#include <R_ext/Utils.h>
48
#endif
54
#endif
49
 
55
 
50
static double ***w; /* to store  cwilcox(i,j,k) -> w[i][j][k] */
56
static double *w; /* to store (one half of) the Wilcoxon distribution */
-
 
57
static int *sigma;
51
static int allocated_m, allocated_n;
58
static int allocated_m, allocated_n, max_k;
-
 
59
 
-
 
60
static int
-
 
61
cwilcox_sigma(int k, int m, int n) {
-
 
62
    /* this is used in w_fill_to_k to calculate w */
-
 
63
    int s=0, d, iter1, iter2;
-
 
64
 
-
 
65
    /* the factors of k must be at most k */
-
 
66
    iter1 = m < k ? m : k;
-
 
67
    iter2 = m+n < k ? m+n : k;
-
 
68
    for (d = 1; d <= iter1; d++) s += (k%d==0)*d;
-
 
69
    for (d = n+1; d <= iter2; d++) s -= (k%d==0)*d;
-
 
70
    return s;
-
 
71
}
52
 
72
 
53
static void
73
static void
54
w_free(int m, int n)
74
w_fill_to_k(int m, int n, int new_k)
55
{
75
{
-
 
76
    /*
-
 
77
     * lazily fill in the distribution up to new_k
-
 
78
     * store the last final index evaluated globally
-
 
79
     */
-
 
80
    if(new_k < max_k) return;
-
 
81
 
56
    int i, j;
82
    int i, k;
-
 
83
    double s;
57
 
84
 
-
 
85
    /* fill in the values for sigma */
58
    for (i = m; i >= 0; i--) {
86
    for(i=max_k+1; i<=new_k; i++)
-
 
87
        sigma[i] = cwilcox_sigma(i, m, n);
-
 
88
 
-
 
89
    /* fill in the values for the distribution */
59
	for (j = n; j >= 0; j--) {
90
    for (k=max_k+1; k<=new_k; k++) {
-
 
91
        if (k==0){
-
 
92
            w[0]=1; /* by definition 0 has only 1 partition */
-
 
93
        } else {
60
	    if (w[i][j] != 0)
94
            s = 0;
-
 
95
            for (i = 0; i<k; i++){
-
 
96
                /* recursion formula */
61
		free((void *) w[i][j]);
97
                s += w[i]*sigma[k-i];
62
	}
98
            }
63
	free((void *) w[i]);
99
            w[k] = s/k;
-
 
100
        }
64
    }
101
    }
65
    free((void *) w);
102
    max_k = new_k;
66
    w = 0; allocated_m = allocated_n = 0;
103
    return;
67
}
104
}
68
 
105
 
69
static void
106
static void
70
w_init_maybe(int m, int n)
107
w_init_maybe(int m, int n)
71
{
108
{
-
 
109
    /* if the size is 0 just return, no need to recall cwilcox_sigma */
72
    int i;
110
    if (m==0 || n==0) return;
73
 
111
 
-
 
112
    /* if we need to resize, first free the existing array */
74
    if (m > n) {
113
    if ((w || sigma) && (m > allocated_m || n > allocated_n))
75
	i = n; n = m; m = i;
114
        wilcox_free();
76
    }
115
 
77
    if (w && (m > allocated_m || n > allocated_n))
116
    if (!w || !sigma) { /* initialize w[] */
78
	w_free(allocated_m, allocated_n); /* zeroes w */
117
        w = (double *) calloc(((size_t) m*n)/2+1, sizeof(double));
-
 
118
        sigma = (int *) calloc(((size_t) m*n)/2+1, sizeof(int));
79
 
119
 
80
    if (!w) { /* initialize w[][] */
-
 
81
	m = imax2(m, WILCOX_MAX);
-
 
82
	n = imax2(n, WILCOX_MAX);
-
 
83
	w = (double ***) calloc((size_t) m + 1, sizeof(double **));
-
 
84
#ifdef MATHLIB_STANDALONE
-
 
85
	if (!w) MATHLIB_ERROR(_("wilcox allocation error %d"), 1);
-
 
86
#endif
-
 
87
	for (i = 0; i <= m; i++) {
-
 
88
	    w[i] = (double **) calloc((size_t) n + 1, sizeof(double *));
-
 
89
#ifdef MATHLIB_STANDALONE
120
#ifdef MATHLIB_STANDALONE
90
	    /* the apparent leak here in the in-R case should be
-
 
91
	       swept up by the on.exit action */
-
 
92
	    if (!w[i]) {
-
 
93
		/* first free all earlier allocations */
-
 
94
		w_free(i-1, n);
-
 
95
		MATHLIB_ERROR(_("wilcox allocation error %d"), 2);
121
        if (!w || !sigma) MATHLIB_ERROR(_("wilcox allocation error %d"), 1);
96
	    }
-
 
97
#endif
122
#endif
98
	}
123
 
99
	allocated_m = m; allocated_n = n;
124
	allocated_m = m; allocated_n = n;
-
 
125
        max_k = -1;
100
    }
126
    }
101
}
127
}
102
 
128
 
103
static void
-
 
104
w_free_maybe(int m, int n)
-
 
105
{
-
 
106
    if (m > WILCOX_MAX || n > WILCOX_MAX)
-
 
107
	w_free(m, n);
-
 
108
}
-
 
109
 
-
 
110
 
-
 
111
#ifndef MATHLIB_STANDALONE
129
#ifndef MATHLIB_STANDALONE
112
static int ic = 99999;
130
static int ic = 99999;
113
#endif
131
#endif
114
/* This counts the number of choices with statistic = k */
132
/* This counts the number of choices with statistic = k */
115
static double
133
static double
116
cwilcox(int k, int m, int n)
134
cwilcox(int k, int m, int n)
117
{
135
{
118
    int c, i, j,
136
    int c, i, j,
119
	u = m * n;
137
	u = m * n;
-
 
138
#ifndef MATHLIB_STANDALONE
-
 
139
    if (!ic--) {
-
 
140
	R_CheckUserInterrupt();
-
 
141
	ic = 99999;
-
 
142
    }
-
 
143
#endif
120
    if (k < 0 || k > u)
144
    if (k < 0 || k > u)
121
	return(0);
145
	return(0);
122
    c = (int)(u / 2);
146
    c = (int)(u / 2);
123
    if (k > c)
147
    if (k > c)
124
	k = u - k; /* hence  k <= floor(u / 2) */
148
	k = u - k; /* hence  k < floor(u / 2) */
125
    if (m < n) {
149
    if (m < n) {
126
	i = m; j = n;
150
	i = m; j = n;
127
    } else {
151
    } else {
128
	i = n; j = m;
152
	i = n; j = m;
129
    } /* hence  i <= j */
153
    } /* hence  i <= j */
130
 
154
 
131
    if (j == 0) /* and hence i == 0 */
155
    /* if any of these values are 0 we return k==0 */
132
	return (k == 0);
156
    if (i == 0 || j == 0 || k == 0) return (k == 0);
133
 
157
 
134
 
158
    /*
135
    /* We can simplify things if k is small.  Consider the Mann-Whitney
-
 
136
       definition, and sort y.  Then if the statistic is k, no more
159
     * previous iterations called cwilcox(k, i, k) here if j>0 and k<j
137
       than k of the y's can be <= any x[i], and since they are sorted
160
     * however, I'm intentionally not doing that since `sigma` and `w` are
138
       these can only be in the first k.  So the count is the same as
161
     * cached for fixed values of m,n. Swapping m,n will force a realloc
139
       if there were just k y's.
162
     * and lots of additional w_fill_to_k() calls.
140
    */
163
    */
141
    if (j > 0 && k < j) return cwilcox(k, i, k);
-
 
142
 
164
 
143
#ifndef MATHLIB_STANDALONE
165
    /* initialize space for the distribution if it doesn't yet exist */
144
    if (!ic--) {
166
    if(!w || !sigma || i != allocated_m || j != allocated_n)
145
	R_CheckUserInterrupt();
167
        w_init_maybe(i,j);
146
	ic = 99999;
-
 
147
    }
-
 
148
#endif
-
 
149
 
168
 
150
    if (w[i][j] == 0) {
-
 
151
	w[i][j] = (double *) calloc((size_t) c + 1, sizeof(double));
169
    /* fill in values up to k (caching results) */
152
#ifdef MATHLIB_STANDALONE
-
 
153
	if (!w[i][j]) MATHLIB_ERROR(_("wilcox allocation error %d"), 3);
-
 
154
#endif
-
 
155
	for (int l = 0; l <= c; l++)
-
 
156
	    w[i][j][l] = -1;
-
 
157
    }
-
 
158
    if (w[i][j][k] < 0) {
-
 
159
	if (j == 0) /* and hence i == 0 */
-
 
160
	    w[i][j][k] = (k == 0);
170
    w_fill_to_k(i,j,k);
161
	else
-
 
162
	    w[i][j][k] = cwilcox(k - j, i - 1, j) + cwilcox(k, i, j - 1);
-
 
163
 
171
 
164
    }
-
 
165
    return(w[i][j][k]);
172
    return w[k];
166
}
173
}
167
 
174
 
168
double dwilcox(double x, double m, double n, int give_log)
175
double dwilcox(double x, double m, double n, int give_log)
169
{
176
{
170
#ifdef IEEE_754
177
#ifdef IEEE_754
Line 181... Line 188...
181
	return(R_D__0);
188
	return(R_D__0);
182
    x = R_forceint(x);
189
    x = R_forceint(x);
183
    if ((x < 0) || (x > m * n))
190
    if ((x < 0) || (x > m * n))
184
	return(R_D__0);
191
	return(R_D__0);
185
 
192
 
-
 
193
    if (m > INT_MAX)
-
 
194
	MATHLIB_ERROR("m(%g) > INT_MAX", m);
-
 
195
    if (n > INT_MAX)
-
 
196
	MATHLIB_ERROR("n(%g) > INT_MAX", n);
-
 
197
    if (x > INT_MAX)
-
 
198
	MATHLIB_ERROR("x(%g) > INT_MAX", x);
-
 
199
 
186
    int mm = (int) m, nn = (int) n, xx = (int) x;
200
    int mm = (int) m, nn = (int) n, xx = (int) x;
187
    w_init_maybe(mm, nn);
-
 
188
    double d = give_log ?
201
    double d = give_log ?
189
	log(cwilcox(xx, mm, nn)) - lchoose(m + n, n) :
202
	log(cwilcox(xx, mm, nn)) - lchoose(m + n, n) :
190
	    cwilcox(xx, mm, nn)  /  choose(m + n, n);
203
	    cwilcox(xx, mm, nn)  /  choose(m + n, n);
191
 
204
 
192
    return(d);
205
    return(d);
Line 211... Line 224...
211
    if (q < 0.0)
224
    if (q < 0.0)
212
	return(R_DT_0);
225
	return(R_DT_0);
213
    if (q >= m * n)
226
    if (q >= m * n)
214
	return(R_DT_1);
227
	return(R_DT_1);
215
 
228
 
-
 
229
    if (m > INT_MAX)
-
 
230
	MATHLIB_ERROR("m(%g) > INT_MAX", m);
-
 
231
    if (n > INT_MAX)
-
 
232
	MATHLIB_ERROR("n(%g) > INT_MAX", n);
216
    int mm = (int) m, nn = (int) n;
233
    int mm = (int) m, nn = (int) n;
217
    w_init_maybe(mm, nn);
-
 
218
    double c = choose(m + n, n),
234
    double c = choose(m + n, n),
219
	p = 0;
235
	p = 0;
220
    /* Use summation of probs over the shorter range */
236
    /* Use summation of probs over the shorter range */
221
    if (q <= (m * n / 2)) {
237
    if (q <= (m * n / 2)) {
222
	for (int i = 0; i <= q; i++)
238
	for (int i = 0; i <= q; i++)
Line 255... Line 271...
255
	return(m * n);
271
	return(m * n);
256
 
272
 
257
    if(log_p || !lower_tail)
273
    if(log_p || !lower_tail)
258
	x = R_DT_qIv(x); /* lower_tail,non-log "p" */
274
	x = R_DT_qIv(x); /* lower_tail,non-log "p" */
259
 
275
 
-
 
276
    if (m > INT_MAX)
-
 
277
	MATHLIB_ERROR("m(%g) > INT_MAX", m);
-
 
278
    if (n > INT_MAX)
-
 
279
	MATHLIB_ERROR("n(%g) > INT_MAX", n);
260
    int mm = (int) m, nn = (int) n;
280
    int mm = (int) m, nn = (int) n;
261
    w_init_maybe(mm, nn);
-
 
262
    double c = choose(m + n, n),
281
    double c = choose(m + n, n),
263
	p = 0.;
282
	p = 0.;
264
    int q = 0;
283
    int q = 0;
265
    if (x <= 0.5) {
284
    if (x <= 0.5) {
266
	x = x - 10 * DBL_EPSILON;
285
	x = x - 10 * DBL_EPSILON;
Line 303... Line 322...
303
 
322
 
304
    if ((m == 0) || (n == 0))
323
    if ((m == 0) || (n == 0))
305
	return(0);
324
	return(0);
306
 
325
 
307
    r = 0.0;
326
    r = 0.0;
-
 
327
    if ((m + n) > INT_MAX)
-
 
328
	MATHLIB_ERROR("m+n(%g) > INT_MAX", m + n);
308
    k = (int) (m + n);
329
    k = (int) (m + n);
309
    x = (int *) calloc((size_t) k, sizeof(int));
330
    x = (int *) calloc((size_t) k, sizeof(int));
310
#ifdef MATHLIB_STANDALONE
331
#ifdef MATHLIB_STANDALONE
311
    if (!x) MATHLIB_ERROR(_("wilcox allocation error %d"), 4);
332
    if (!x) MATHLIB_ERROR(_("wilcox allocation error %d"), 4);
312
#endif
333
#endif
Line 321... Line 342...
321
    return(r - n * (n - 1) / 2);
342
    return(r - n * (n - 1) / 2);
322
}
343
}
323
 
344
 
324
void wilcox_free(void)
345
void wilcox_free(void)
325
{
346
{
-
 
347
    free(w);
-
 
348
    free(sigma);
-
 
349
    w = NULL; sigma = NULL;
326
    w_free_maybe(allocated_m, allocated_n);
350
    allocated_m = allocated_n = 0;
-
 
351
    max_k = -1;
327
}
352
}