-
Notifications
You must be signed in to change notification settings - Fork 21
/
Copy pathsurvregc2.c
251 lines (237 loc) · 7.28 KB
/
survregc2.c
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
/*
** Survreg Compute 2 (survregc2)
** Compute the loglik and other parameters for a survreg fit.
** This is the version for the "callback". The code below
** was previously the dolik() routine and it's children found in
** survreg3, modified for a joint R/Splus syntax.
** This has exactly the same arguments as survregc1 and returns the
** same values: see that routine for more comments. This actually
** uses expr, rho, and z, however.
*/
#include <math.h>
#include "survS.h"
#include "survproto.h"
#define SMALL -200 /* exp(-200) is a really small loglik */
double survregc2(int n, int nvar, int nstrat, int whichcase,
double *beta, int dist, int *strat, double *offset,
double *time1, double *time2, double *status, double *wt,
double **covar, double **imat, double **JJ, double *u,
SEXP expr, SEXP rho, double *z, int nf,
int *frail, double *fdiag, double *jdiag ) {
int person, i,j,k;
int nvar2;
int strata;
double eta,
sigma;
int icount; /* running count of # of interval censored */
int fgrp =0; /* the =0 to quiet a compiler warning */
double loglik,
temp;
double temp1, temp2;
double sz, zz, zu;
double sig2;
/* add "=0" to keep the compiler from worrying about uninitialized vars */
/* double g, dg, ddg, dsig, ddsig, dsg; */
double g=0, dg=0, ddg=0, dsig=0, ddsig=0, dsg=0;
SEXP rmat;
double *funs[5];
double w;
nvar2 = nvar + nstrat;
loglik=0;
if (whichcase==0) {
for (i=0; i<nf; i++) {
fdiag[i] =0;
jdiag[i] =0;
}
for (i=0; i<nvar2+nf; i++) {
u[i] =0;
for (j=0; j<nvar2; j++) {
imat[j][i] =0 ;
JJ[j][i] =0;
}
}
}
strata =0;
sigma = exp(beta[nvar+nf]); /*single scale value case (fixed or estimate)*/
sig2 = 1/(sigma*sigma);
loglik =0;
/*
** First, get the array of distribution values
** We get them all at once to minimize the S-callback overhead
*/
icount =n;
for (person=0; person<n; person++) {
if (nstrat>1) {
strata= strat[person] -1; /*S likes to start counting at 1 */
sigma = exp(beta[strata+nvar+nf]);
}
eta =0;
for (i=0; i<nvar; i++) eta += beta[i] * covar[i][person];
eta += offset[person];
if (nf >0){
fgrp = frail[person] -1;
eta += beta[fgrp];
}
z[person] = (time1[person] - eta)/sigma;
if (status[person]==3) {
z[icount] = (time2[person] - eta)/sigma;
icount++;
}
}
/*
** The result of the eval will be a matrix of 5 rows and n colums, which
** we re-index for convenience. Note that the parent routine has given
** us the address of z WITHIN the evaluation frame rho, we just keep
** replacing the values it contains; expr then acts like a function of
** z.
** Actually, if there were any interval censored obs they take up 2 cols;
** icount from above contains the actual number of columns used.
*/
PROTECT(rmat = eval(expr, rho));
funs[0] = REAL(rmat);
for (i=0; i<4; i++) funs[i+1] = funs[i] + icount;
/*
** calculate the first and second derivative wrt eta,
** then the derivatives of the loglik (u, imat, JJ)
*/
icount =n;
for (person=0; person<n; person++) {
if (nstrat>1) {
strata= strat[person] -1; /*S likes to start counting at 1 */
sigma = exp(beta[strata+nvar]);
sig2 = 1/(sigma*sigma);
}
zz = z[person];
sz = zz * sigma;
j = status[person]; /*convert to integer */
switch(j) {
case 1: /* exact */
if (funs[2][person] <=0) {
/* off the probability scale -- avoid log(0), and set the
** derivatives to gaussian limits (almost any deriv will
** do, since the function value triggers step-halving).
*/
g = SMALL;
dg = -zz/sigma;
ddg = -1/sigma;
dsig =0; ddsig=0; dsg=0;
}
else {
g = log(funs[2][person]) - log(sigma);
temp1 = funs[3][person]/sigma;
temp2 = funs[4][person]*sig2;
dg = -temp1;
dsig= -(sz*temp1 +1);
ddg= temp2 - dg*dg;
dsg = sz * temp2 - dg*(1- sz*temp1);
ddsig = sz*sz*temp2 + sz*temp1*(1- sz*temp1);
}
break;
case 0: /* right censored */
if (funs[1][person] <=0) {
g = SMALL;
dg = zz/sigma;
ddg =0;
dsig =0; ddsig=0; dsg=0;
}
else {
g = log(funs[1][person]);
temp1 = -funs[2][person]/(funs[1][person]*sigma);
temp2 = -funs[3][person]*funs[2][person]*sig2/
funs[1][person];
dg = -temp1;
dsig= -sz * temp1;
ddg= temp2 - dg*dg;
dsg = sz * temp2 - dg*(1+dsig);
ddsig = sz*sz*temp2 - dsig*(1+dsig);
}
break;
case 2: /* left censored */
if (funs[2][person] <=0) {
/* off the probability scale -- avoid log(0) */
g = SMALL;
dg = -zz/sigma;
dsig =0; ddsig=0; dsg=0;
ddg =0;
}
else {
g = log(funs[0][person]);
temp1 = funs[2][person]/(funs[0][person]*sigma);
temp2 = funs[3][person]*funs[2][person]*sig2/
funs[0][person];
dg= -temp1;
dsig= -sz * temp1;
ddg= temp2 - dg*dg;
dsg = sz * temp2 - dg*(1+dsig);
ddsig = sz*sz*temp2 - dsig*(1+dsig);
}
break;
case 3: /* interval censored */
zu = z[icount];
/*stop roundoff in tails*/
if (zz>0) temp = funs[1][person] - funs[1][icount];
else temp = funs[0][icount] - funs[0][person];
if (temp <=0) {
/* off the probability scale -- avoid log(0) */
g = SMALL;
dg = 1;
ddg =0;
dsig =0; ddsig=0; dsg=0;
}
else {
funs[3][icount] *= funs[2][icount]; /*f', not f'/f */
funs[3][person] *= funs[2][person];
g = log(temp);
dg = -(funs[2][icount] -funs[2][person])/(temp*sigma);
ddg = (funs[3][icount] -funs[3][person])*sig2/temp - dg*dg;
dsig = (zz*funs[2][person] - zu*funs[2][icount])/temp;
ddsig= (zu*zu*funs[3][icount] - zz*zz*funs[3][person])
/temp - dsig*(1+dsig);
dsg = (zu*funs[3][icount] - zz*funs[3][person])/
(temp*sigma) - dg *(1+dsig);
}
icount++;
break;
}
loglik += g * wt[person];
/*
** Now the derivs wrt loglik
*/
if (whichcase==1) continue; /*only needed the loglik */
w = wt[person];
if (nf>0) {
fgrp = frail[person] -1;
u[fgrp] += dg * w;
fdiag[fgrp] -= ddg * w;
jdiag[fgrp] += dg*dg *w;
}
for (i=0; i<nvar; i++) {
temp = dg * covar[i][person] *w;
u[i+nf] += temp;
for (j=0; j<=i; j++) {
imat[i][j+nf] -= covar[i][person] *covar[j][person] *ddg *w;
JJ[i][j+nf] += temp * covar[j][person] * dg;
}
if (nf>0) {
imat[i][fgrp] -= covar[i][person] * ddg * w;
JJ [i][fgrp] += temp * dg;
}
}
if (nstrat!=0) { /* need derivative wrt log sigma */
k = strata+nvar;
u[k+nf] += w* dsig;
for (i=0; i<nvar; i++) {
imat[k][i+nf] -= dsg * covar[i][person] * w;
JJ[k][i+nf] += dsig* covar[i][person] *dg * w;
}
imat[k][k+nf] -= ddsig * w;
JJ[k][k+nf] += dsig*dsig * w;
if (nf>0) {
imat[k][fgrp] -= dsg * w;
JJ [k][fgrp] += dsig *dg *w;
}
}
}
UNPROTECT(1); /* release the memory pointed to by funs[] */
return(loglik);
}