primarycensored
Loading...
Searching...
No Matches
nonparametric.stan
Go to the documentation of this file.
1
28real pstep_lcdf(real t, vector boundaries, vector pmf) {
29 int K = num_elements(pmf);
30 if (t < boundaries[2]) return negative_infinity();
31 if (t >= boundaries[K + 1]) return 0;
32 // Right-continuous CDF with jumps at the right edges
33 // boundaries[2], ..., boundaries[K + 1]. F(t) = cum_pmf[k] for
34 // t in [boundaries[k + 1], boundaries[k + 2]); equivalently the
35 // largest k with boundaries[k + 1] <= t. Boundary-on-jump cases
36 // (t == boundaries[k + 1]) advance k, matching R's
37 // `findInterval(left.open = FALSE)`.
38 int k = 1;
39 while (k < K && boundaries[k + 2] <= t) k += 1;
40 return log(cumulative_sum(pmf)[k]);
41}
42
55vector hazards_to_pmf(vector hazards) {
56 int K = num_elements(hazards);
57 vector[K] log_surv;
58 log_surv[1] = 0;
59 if (K > 1) {
60 log_surv[2:K] = cumulative_sum(log1m(hazards[1:(K - 1)]));
61 }
62 return hazards .* exp(log_surv);
63}
64
77real phazard_lcdf(real t, vector boundaries, vector hazards) {
78 return pstep_lcdf(t | boundaries, hazards_to_pmf(hazards));
79}
80
95vector primary_lcdf_vec(vector p, int primary_id,
96 array[] real primary_params, data real pwindow) {
97 int N = num_elements(p);
98 vector[N] out;
99 for (i in 1:N) {
100 out[i] = primary_lcdf(p[i] | primary_id, primary_params, pwindow);
101 }
102 return out;
103}
104
138 data real d, vector boundaries, vector pmf,
139 int primary_id, array[] real primary_params, data real pwindow
140) {
141 int K = num_elements(pmf);
142 // Integration support in u = d - p for p in [0, pwindow]. It is not
143 // clipped at 0 so boundaries that start below zero (delays with negative
144 // support) are handled; for non-negative boundaries the per-bin clip to
145 // [boundaries[k], boundaries[k + 1]] below gives the same result.
146 real u_min = d - pwindow;
147 real u_max = d;
148
149 // Structural-zero short-circuit. Below `boundaries[2]` F_step is zero
150 // and the bin-1 contribution carries `cum_before = 0`, so the integral
151 // collapses to 0. Returning `negative_infinity()` directly keeps
152 // `log(0)` off the autodiff tape so downstream `log_diff_exp(a, -inf)`
153 // evaluates cleanly with a zero gradient w.r.t. `pmf`.
154 if (u_max <= boundaries[2]) return negative_infinity();
155
156 // Sub-interval endpoints in u-space, clipped to [u_min, u_max].
157 vector[K] lo = fmax(u_min, head(boundaries, K));
158 vector[K] hi = fmin(u_max, tail(boundaries, K));
159
160 // F_step is right-continuous and on [b_k, b_{k+1}) takes the value
161 // sum_{j < k} pmf[j] (mass before bin k). cumulative_sum(pmf) gives
162 // the mass through and including bin k, so we shift right by one.
163 vector[K] cum_before;
164 cum_before[1] = 0;
165 if (K > 1) cum_before[2:K] = head(cumulative_sum(pmf), K - 1);
166
167 // 0/1 mask drops bins with `hi <= lo` from the reduction without a
168 // branch in the inner expression. Built on `data`-level inputs.
169 vector[K] active;
170 for (k in 1:K) active[k] = hi[k] > lo[k] ? 1 : 0;
171
172 // F_primary at lo/hi via two vectorised calls; one masked subtraction
173 // gives the per-bin difference for the dot product.
174 vector[K] f_lo = primary_lcdf_vec(d - lo, primary_id, primary_params,
175 pwindow);
176 vector[K] f_hi = primary_lcdf_vec(d - hi, primary_id, primary_params,
177 pwindow);
178 vector[K] f_diff = (exp(f_lo) - exp(f_hi)) .* active;
179
180 real integral = dot_product(cum_before, f_diff);
181
182 // Tail region [boundaries[K+1], u_max]: F_step = 1, contributing
183 // F_primary(d - tail_start) - F_primary(d - u_max).
184 real tail_start = fmax(boundaries[K + 1], u_min);
185 if (tail_start < u_max) {
186 real fp_tail = exp(primary_lcdf(d - tail_start | primary_id,
187 primary_params, pwindow));
188 real fp_end = exp(primary_lcdf(d - u_max | primary_id,
189 primary_params, pwindow));
190 integral += fp_tail - fp_end;
191 }
192
193 return log(integral);
194}
195
212 data real d, vector boundaries, vector hazards,
213 int primary_id, array[] real primary_params, data real pwindow
214) {
215 return discretestep_lcdf(
216 d | boundaries, hazards_to_pmf(hazards), primary_id, primary_params,
217 pwindow
218 );
219}
real phazard_lcdf(real t, vector boundaries, vector hazards)
real pstep_lcdf(real t, vector boundaries, vector pmf)
vector primary_lcdf_vec(vector p, int primary_id, array[] real primary_params, data real pwindow)
real discretestep_lcdf(data real d, vector boundaries, vector pmf, int primary_id, array[] real primary_params, data real pwindow)
vector hazards_to_pmf(vector hazards)
real discretehazard_lcdf(data real d, vector boundaries, vector hazards, int primary_id, array[] real primary_params, data real pwindow)
real primary_lcdf(real p, int primary_id, array[] real primary_params, data real pwindow)