Automatic Differentiation
 
Loading...
Searching...
No Matches
wiener_full_lcdf_defective.hpp
Go to the documentation of this file.
1#ifndef STAN_MATH_PRIM_PROB_WIENER_FULL_LCDF_DEFECTIVE_HPP
2#define STAN_MATH_PRIM_PROB_WIENER_FULL_LCDF_DEFECTIVE_HPP
3
6
7namespace stan {
8namespace math {
9namespace internal {
10
31template <typename T_y, typename T_a, typename T_v, typename T_w, typename T_sw,
32 typename T_err>
33inline auto wiener7_cdf_grad_sw(const T_y& y, const T_a& a, const T_v& v,
34 const T_w& w, const T_sw& sw, T_err log_error) {
35 auto low = fmax(0.0, w - sw / 2.0);
36 auto high = fmin(1.0, w + sw / 2.0);
37 const auto lower_value
38 = wiener4_distribution<GradientCalc::ON>(y, a, v, low, log_error);
39 const auto upper_value
40 = wiener4_distribution<GradientCalc::ON>(y, a, v, high, log_error);
41 return 0.5 * (lower_value + upper_value) / sw;
42}
43
72template <GradientCalc Dist, typename F, typename T_y, typename T_a,
73 typename T_v, typename T_w, typename T_sv, typename T_sw,
74 typename T_err, std::enable_if_t<!Dist>* = nullptr>
75inline auto conditionally_grad_sw_cdf(F&& functor, T_y&& y_diff, T_a&& a,
76 T_v&& v, T_w&& w, T_sv&& sv, T_sw&& sw,
77 T_err log_error) {
78 return functor(y_diff, a, v, w, log_error);
79}
80
109template <GradientCalc Dist, typename F, typename T_y, typename T_a,
110 typename T_v, typename T_w, typename T_sv, typename T_sw,
111 typename T_err, std::enable_if_t<Dist>* = nullptr>
112inline auto conditionally_grad_sw_cdf(F&& functor, T_y&& y_diff, T_a&& a,
113 T_v&& v, T_w&& w, T_sv&& sv, T_sw&& sw,
114 T_err log_error) {
115 return functor(y_diff, a, v, w, sv, log_error);
116}
117
132template <GradientCalc Distribution = GradientCalc::OFF,
137 GradientCalc Conditionally_cdf = GradientCalc::ON,
138 typename Wiener7FunctorT, typename T_err, typename... TArgs>
139inline auto wiener7_integrate_cdf(const Wiener7FunctorT& wiener7_functor,
140 T_err&& hcubature_err, TArgs&&... args) {
141 const auto functor = [&wiener7_functor](auto&&... integration_args) {
142 return hcubature(
143 [&wiener7_functor](auto&& x, auto&& y, auto&& a, auto&& v, auto&& w,
144 auto&& t0, auto&& sv, auto&& sw, auto&& st0,
145 auto&& lerr) {
146 using ret_t
147 = return_type_t<decltype(x), decltype(a), decltype(v),
148 decltype(w), decltype(t0), decltype(sv),
149 decltype(sw), decltype(st0), decltype(lerr)>;
150 scalar_seq_view<decltype(x)> x_vec(x);
151 const auto temp = (sv == 0) ? 0 : square(x_vec[0]);
152 const auto factor = (sv == 0) ? 0 : x_vec[0] / (1 - temp);
153 const auto new_v = (sv == 0) ? v : v + sv * factor;
154 const auto new_w
155 = (sw == 0) ? w : w + sw * (x_vec[sv == 0 ? 0 : 1] - 0.5);
156 const auto idx
157 = (sv == 0 && sw == 0) ? 0 : (sv != 0 && sw != 0) ? 2 : 1;
158 const auto new_t0 = (st0 == 0) ? t0 : t0 + st0 * x_vec[idx];
159 if (y - new_t0 <= 0) {
160 return ret_t(0.0);
161 }
162 const auto dist = GradT ? 0
163 : wiener4_distribution<true>(
164 y - new_t0, a, new_v, new_w, lerr);
165 const auto temp2 = (sv == 0) ? 0
166 : -0.5 * square(factor) - LOG_SQRT_PI
167 - 0.5 * LOG_TWO + log1p(temp)
168 - 2.0 * log1m(temp);
169 const auto factor_sv = GradSV ? factor : 1;
170 const auto factor_sw
171 = GradSW ? ((sv == 0) ? (x_vec[0] - 0.5) : (x_vec[1] - 0.5)) : 1;
172 const auto integrand
173 = Distribution
174 ? dist
175 : GradT
176 ? conditionally_grad_sw_cdf<Conditionally_cdf>(
177 wiener7_functor, y - new_t0, a, v, new_w, sv, sw,
178 lerr)
179 : factor_sv * factor_sw
180 * conditionally_grad_sw_cdf<Conditionally_cdf>(
181 wiener7_functor, y - new_t0, a, new_v,
182 new_w, dist, sw, lerr);
183 return ret_t(integrand * exp(temp2));
184 },
185 integration_args...);
186 };
187
188 return estimate_with_err_check<0, 8, GradW7, GradientCalc::ON>(
189 functor, hcubature_err, args...);
190}
191} // namespace internal
192
260template <bool propto = false, typename T_y, typename T_a, typename T_t0,
261 typename T_w, typename T_v, typename T_sv, typename T_sw,
262 typename T_st0>
263inline auto wiener_lcdf_defective(const T_y& y, const T_a& a, const T_t0& t0,
264 const T_w& w, const T_v& v, const T_sv& sv,
265 const T_sw& sw, const T_st0& st0,
266 const double& precision_derivatives = 1e-8) {
268 using T_y_ref = ref_type_t<T_y>;
269 using T_a_ref = ref_type_t<T_a>;
270 using T_v_ref = ref_type_t<T_v>;
271 using T_w_ref = ref_type_t<T_w>;
272 using T_t0_ref = ref_type_t<T_t0>;
273 using T_sv_ref = ref_type_t<T_sv>;
274 using T_sw_ref = ref_type_t<T_sw>;
275 using T_st0_ref = ref_type_t<T_st0>;
277 using T_partials_return
279
280 T_y_ref y_ref = y;
281 T_a_ref a_ref = a;
282 T_v_ref v_ref = v;
283 T_w_ref w_ref = w;
284 T_t0_ref t0_ref = t0;
285 T_sv_ref sv_ref = sv;
286 T_sw_ref sw_ref = sw;
287 T_st0_ref st0_ref = st0;
288
289 auto y_val = to_ref(as_value_column_array_or_scalar(y_ref));
290 auto a_val = to_ref(as_value_column_array_or_scalar(a_ref));
291 auto v_val = to_ref(as_value_column_array_or_scalar(v_ref));
292 auto w_val = to_ref(as_value_column_array_or_scalar(w_ref));
293 auto t0_val = to_ref(as_value_column_array_or_scalar(t0_ref));
294 auto sv_val = to_ref(as_value_column_array_or_scalar(sv_ref));
295 auto sw_val = to_ref(as_value_column_array_or_scalar(sw_ref));
296 auto st0_val = to_ref(as_value_column_array_or_scalar(st0_ref));
297
298 if (!include_summand<propto, T_y, T_a, T_v, T_w, T_t0, T_sv, T_sw,
299 T_st0>::value) {
300 return ret_t(0);
301 }
302
303 static constexpr const char* function_name = "wiener_lcdf_defective";
304 check_consistent_sizes(function_name, "Random variable", y,
305 "Boundary separation", a, "Drift rate", v,
306 "A-priori bias", w, "Nondecision time", t0,
307 "Inter-trial variability in drift rate", sv,
308 "Inter-trial variability in A-priori bias", sw,
309 "Inter-trial variability in Nondecision time", st0);
310 check_positive_finite(function_name, "Random variable", y_val);
311 check_positive_finite(function_name, "Boundary separation", a_val);
312 check_finite(function_name, "Drift rate", v_val);
313 check_less(function_name, "A-priori bias", w_val, 1);
314 check_greater(function_name, "A-priori bias", w_val, 0);
315 check_nonnegative(function_name, "Nondecision time", t0_val);
316 check_finite(function_name, "Nondecision time", t0_val);
317 check_nonnegative(function_name, "Inter-trial variability in drift rate",
318 sv_val);
319 check_finite(function_name, "Inter-trial variability in drift rate", sv_val);
320 check_bounded(function_name, "Inter-trial variability in A-priori bias",
321 sw_val, 0, 1);
322 check_nonnegative(function_name,
323 "Inter-trial variability in Nondecision time", st0_val);
324 check_finite(function_name, "Inter-trial variability in Nondecision time",
325 st0_val);
326
327 const size_t N = max_size(y, a, v, w, t0, sv, sw, st0);
328 if (N == 0) {
329 return ret_t(0);
330 }
331 scalar_seq_view<T_y_ref> y_vec(y_ref);
332 scalar_seq_view<T_a_ref> a_vec(a_ref);
333 scalar_seq_view<T_v_ref> v_vec(v_ref);
334 scalar_seq_view<T_w_ref> w_vec(w_ref);
335 scalar_seq_view<T_t0_ref> t0_vec(t0_ref);
336 scalar_seq_view<T_sv_ref> sv_vec(sv_ref);
337 scalar_seq_view<T_sw_ref> sw_vec(sw_ref);
338 scalar_seq_view<T_st0_ref> st0_vec(st0_ref);
339 const size_t N_y_t0 = max_size(y, t0, st0);
340
341 for (size_t i = 0; i < N_y_t0; ++i) {
342 if (y_vec[i] <= t0_vec[i]) {
343 std::stringstream msg;
344 msg << ", but must be greater than nondecision time = " << t0_vec[i];
345 std::string msg_str(msg.str());
346 throw_domain_error(function_name, "Random variable", y_vec[i], " = ",
347 msg_str.c_str());
348 }
349 }
350 size_t N_beta_sw = max_size(w, sw);
351 for (size_t i = 0; i < N_beta_sw; ++i) {
352 if (unlikely(w_vec[i] - .5 * sw_vec[i] <= 0)) {
353 std::stringstream msg;
354 msg << ", but must be smaller than 2*(A-priori bias) = "
355 << 2.0 * w_vec[i];
356 std::string msg_str(msg.str());
357 throw_domain_error(function_name,
358 "Inter-trial variability in A-priori bias", sw_vec[i],
359 " = ", msg_str.c_str());
360 }
361 if (unlikely(w_vec[i] + .5 * sw_vec[i] >= 1)) {
362 std::stringstream msg;
363 msg << ", but must be smaller than 2*(1-A-priori bias) = "
364 << 2 * (1 - w_vec[i]);
365 std::string msg_str(msg.str());
366 throw_domain_error(function_name,
367 "Inter-trial variability in A-priori bias", sw_vec[i],
368 " = ", msg_str.c_str());
369 }
370 }
371
372 // for precs. 1e-6, 1e-12, see Hartmann et al. (2021), Henrich et al. (2023)
373 const T_partials_return log_error_cdf = log(1e-6); // precision for density
374 const auto error_bound = precision_derivatives; // precision for
375 // derivatives (controllable by user)
376 const auto lerror_bound = log(error_bound);
377 const T_partials_return absolute_error_hcubature = 0.0;
378 const T_partials_return relative_error_hcubature
379 = .9 * error_bound; // eps_rel(Integration)
380 const T_partials_return log_error_absolute = log(1e-12);
381 const int maximal_evaluations_hcubature = 6000;
382 T_partials_return lcdf = 0.0;
383 auto ops_partials = make_partials_propagator(y_ref, a_ref, t0_ref, w_ref,
384 v_ref, sv_ref, sw_ref, st0_ref);
385 ret_t result = 0.0;
386
387 // calculate density and partials
388 for (size_t i = 0; i < N; i++) {
389 if (sv_vec[i] == 0 && sw_vec[i] == 0 && st0_vec[i] == 0) {
390 result += wiener_lcdf_defective<propto>(y_vec[i], a_vec[i], t0_vec[i],
391 w_vec[i], v_vec[i],
392 precision_derivatives);
393 continue;
394 }
395 const T_partials_return y_value = y_vec.val(i);
396 const T_partials_return a_value = a_vec.val(i);
397 const T_partials_return v_value = v_vec.val(i);
398 const T_partials_return w_value = w_vec.val(i);
399 const T_partials_return t0_value = t0_vec.val(i);
400 const T_partials_return sv_value = sv_vec.val(i);
401 const T_partials_return sw_value = sw_vec.val(i);
402 const T_partials_return st0_value = st0_vec.val(i);
403 const int dim = (sv_value != 0) + (sw_value != 0) + (st0_value != 0);
404 check_positive(function_name,
405 "(Inter-trial variability in drift rate) + "
406 "(Inter-trial variability in A-priori bias) + "
407 "(Inter-trial variability in nondecision time)",
408 dim);
409
410 Eigen::Matrix<T_partials_return, -1, 1> xmin = Eigen::VectorXd::Zero(dim);
411 Eigen::Matrix<T_partials_return, -1, 1> xmax = Eigen::VectorXd::Ones(dim);
412 for (int i = 0; i < dim; i++) {
413 xmin[i] = 0;
414 xmax[i] = 1;
415 }
416 if (sv_value != 0) {
417 xmin[0] = -1;
418 xmax[0] = 1;
419 }
420 if (st0_value != 0) {
421 xmax[dim - 1] = fmin(1.0, (y_value - t0_value) / st0_value);
422 }
423
424 T_partials_return hcubature_err
425 = log_error_absolute - log_error_cdf + LOG_TWO + 1;
426
427 const auto params = std::make_tuple(y_value, a_value, v_value, w_value,
428 t0_value, sv_value, sw_value, st0_value,
429 log_error_absolute - LOG_TWO);
430
431 const T_partials_return cdf
432 = internal::wiener7_integrate_cdf<GradientCalc::ON, GradientCalc::OFF,
433 GradientCalc::OFF, GradientCalc::OFF,
434 GradientCalc::OFF, GradientCalc::OFF>(
435 [&](auto&&... args) {
436 return internal::wiener4_distribution<true>(args...);
437 },
438 hcubature_err, params, dim, xmin, xmax,
439 maximal_evaluations_hcubature, absolute_error_hcubature,
440 relative_error_hcubature / 2);
441 lcdf += log(cdf);
442
443 hcubature_err
444 = log_error_absolute - lerror_bound + log(fabs(cdf)) + LOG_TWO + 1;
445
446 // computation of derivative for t and precision check in order to give
447 // the value as deriv_t to edge1 and as -deriv_t to edge5
448
450 T_partials_return deriv_t_7
452 GradientCalc::OFF, GradientCalc::OFF, GradientCalc::OFF,
453 GradientCalc::OFF, GradientCalc::ON>(
454 [&](auto&&... args) {
455 return internal::wiener5_density<GradientCalc::ON>(args...);
456 },
457 hcubature_err, params, dim, xmin, xmax,
458 maximal_evaluations_hcubature, absolute_error_hcubature,
459 relative_error_hcubature / 2)
460 / cdf;
462 partials<0>(ops_partials)[i] = deriv_t_7;
463 }
465 partials<2>(ops_partials)[i] = -deriv_t_7;
466 }
467 }
468 T_partials_return deriv;
470 partials<1>(ops_partials)[i]
472 [&](auto&&... args) {
473 return internal::wiener4_cdf_grad_a(args...);
474 },
475 hcubature_err, params, dim, xmin, xmax,
476 maximal_evaluations_hcubature, absolute_error_hcubature,
477 relative_error_hcubature / 2)
478 / cdf;
479 }
481 partials<3>(ops_partials)[i]
482 = internal::wiener7_integrate_cdf<GradientCalc::OFF,
483 GradientCalc::ON>(
484 [&](auto&&... args) {
485 return internal::wiener4_cdf_grad_w(args...);
486 },
487 hcubature_err, params, dim, xmin, xmax,
488 maximal_evaluations_hcubature, absolute_error_hcubature,
489 relative_error_hcubature / 2)
490 / cdf;
491 }
493 partials<4>(ops_partials)[i]
495 [&](auto&&... args) {
496 return internal::wiener4_cdf_grad_v(args...);
497 },
498 hcubature_err, params, dim, xmin, xmax,
499 maximal_evaluations_hcubature, absolute_error_hcubature,
500 relative_error_hcubature / 2)
501 / cdf;
502 }
504 if (sv_value == 0) {
505 partials<5>(ops_partials)[i] = 0;
506 } else {
507 partials<5>(ops_partials)[i]
509 GradientCalc::OFF, GradientCalc::OFF, GradientCalc::ON>(
510 [&](auto&&... args) {
511 return internal::wiener4_cdf_grad_v(args...);
512 },
513 hcubature_err, params, dim, xmin, xmax,
514 maximal_evaluations_hcubature, absolute_error_hcubature,
515 relative_error_hcubature / 2)
516 / cdf;
517 }
518 }
520 if (sw_value == 0) {
521 partials<6>(ops_partials)[i] = 0;
522 } else {
523 if (st0_value == 0 && sv_value == 0) {
524 deriv = internal::estimate_with_err_check<5, 0, GradientCalc::OFF,
525 GradientCalc::ON>(
526 [](auto&&... args) {
527 return internal::wiener7_cdf_grad_sw(args...);
528 },
529 hcubature_err, y_value - t0_value, a_value, v_value, w_value,
530 sw_value, log_error_absolute - LOG_TWO);
531 deriv = deriv / cdf - 1 / sw_value;
532 } else {
534 GradientCalc::OFF, GradientCalc::OFF, GradientCalc::OFF,
535 GradientCalc::ON>(
536 [&](auto&&... args) {
537 return internal::wiener4_cdf_grad_w(args...);
538 },
539 hcubature_err, params, dim, xmin, xmax,
540 maximal_evaluations_hcubature, absolute_error_hcubature,
541 relative_error_hcubature / 2)
542 / cdf;
543 }
544 partials<6>(ops_partials)[i] = deriv;
545 }
546 }
548 if (st0_value == 0) {
549 partials<7>(ops_partials)[i] = 0;
550 } else if (y_value - (t0_value + st0_value) <= 0) {
551 partials<7>(ops_partials)[i] = -1 / st0_value;
552 } else {
553 const T_partials_return t0_st0 = t0_value + st0_value;
554 if (sw_value == 0 && sv_value == 0) {
555 deriv = internal::estimate_with_err_check<4, 0, GradientCalc::OFF,
556 GradientCalc::ON>(
557 [](auto&&... args) {
558 return internal::wiener4_distribution<GradientCalc::ON>(
559 args...);
560 },
561 lerror_bound + log(st0_value), y_value - t0_st0, a_value, v_value,
562 w_value, log_error_absolute - LOG_TWO);
563 deriv = deriv / st0_value / cdf - 1 / st0_value;
564 } else {
565 const int dim_st = (sv_value != 0) + (sw_value != 0);
566 const T_partials_return new_error = log_error_absolute - LOG_TWO;
567 const auto& params_st
568 = std::make_tuple(y_value, a_value, v_value, w_value, t0_st0,
569 sv_value, sw_value, 0, new_error);
571 GradientCalc::OFF, GradientCalc::OFF, GradientCalc::OFF,
572 GradientCalc::OFF, GradientCalc::OFF, GradientCalc::OFF>(
573 [&](auto&&... args) {
574 return internal::wiener4_distribution<GradientCalc::ON>(
575 args...);
576 },
577 hcubature_err, params_st, dim_st, xmin, xmax,
578 maximal_evaluations_hcubature, absolute_error_hcubature,
579 relative_error_hcubature / 2);
580 deriv = deriv / st0_value / cdf - 1 / st0_value;
581 }
582 partials<7>(ops_partials)[i] = deriv;
583 }
584 }
585 }
586 return result + ops_partials.build(lcdf);
587}
588} // namespace math
589} // namespace stan
590#endif
scalar_seq_view provides a uniform sequence-like wrapper around either a scalar or a sequence of scal...
#define unlikely(x)
typename return_type< Ts... >::type return_type_t
Convenience type for the return type of the specified template parameters.
auto wiener4_cdf_grad_w(const T_y &y, const T_a &a, const T_v &v, const T_w &w, T_cdf &&cdf, T_err log_err=log(1e-12))
Calculate derivative of the wiener4 distribution w.r.t.
auto wiener4_cdf_grad_v(const T_y &y, const T_a &a, const T_v &v, const T_w &w, T_cdf &&cdf, T_err log_err=log(1e-12))
Calculate derivative of the wiener4 distribution w.r.t.
auto wiener7_cdf_grad_sw(const T_y &y, const T_a &a, const T_v &v, const T_w &w, const T_sw &sw, T_err log_error)
Calculate the derivative of the wiener7 density w.r.t.
auto conditionally_grad_sw_cdf(F &&functor, T_y &&y_diff, T_a &&a, T_v &&v, T_w &&w, T_sv &&sv, T_sw &&sw, T_err log_error)
Helper function for agnostically calling wiener4 functions (to be integrated over) or directly callin...
auto estimate_with_err_check(F &&functor, T_err &&log_err, ArgsTupleT &&... args_tuple)
Utility function for estimating a function with a given set of arguments, checking the result against...
auto wiener4_cdf_grad_a(const T_y &y, const T_a &a, const T_v &v, const T_w &w, T_cdf &&cdf, T_err log_err=log(1e-12))
Calculate derivative of the wiener4 distribution w.r.t.
auto wiener7_integrate_cdf(const Wiener7FunctorT &wiener7_functor, T_err &&hcubature_err, TArgs &&... args)
Implementation function for preparing arguments and functor to be passed to the hcubature() function ...
void check_nonnegative(const char *function, const char *name, const T_y &y)
Check if y is non-negative.
fvar< T > fmin(const fvar< T > &x1, const fvar< T > &x2)
Definition fmin.hpp:14
void check_bounded(const char *function, const char *name, const T_y &y, const T_low &low, const T_high &high)
Check if the value is between the low and high values, inclusively.
static constexpr double e()
Return the base of the natural logarithm.
Definition constants.hpp:20
auto hcubature(const F &integrand, const ParsTuple &pars, const int dim, const Eigen::Matrix< T_a, Eigen::Dynamic, 1 > &a, const Eigen::Matrix< T_b, Eigen::Dynamic, 1 > &b, const int max_eval, const TAbsErr reqAbsError, const TRelErr reqRelError)
Compute the [dim]-dimensional integral of the function from to within specified relative and absol...
fvar< T > log(const fvar< T > &x)
Definition log.hpp:18
void throw_domain_error(const char *function, const char *name, const T &y, const char *msg1, const char *msg2)
Throw a domain error with a consistently formatted message.
auto wiener_lcdf_defective(const T_y &y, const T_a &a, const T_t0 &t0, const T_w &w, const T_v &v, const double &precision_derivatives=1e-4)
Log-CDF function for the 4-parameter Wiener distribution.
static constexpr double LOG_TWO
The natural logarithm of 2, .
Definition constants.hpp:80
auto as_value_column_array_or_scalar(T &&a)
Extract the value from an object and for eigen vectors and std::vectors convert to an eigen column ar...
void check_consistent_sizes(const char *)
Trivial no input case, this function is a no-op.
static constexpr double LOG_SQRT_PI
The natural logarithm of the square root of , .
fvar< T > log1p(const fvar< T > &x)
Definition log1p.hpp:12
void check_finite(const char *function, const char *name, const T_y &y)
Return true if all values in y are finite.
fvar< T > fmax(const fvar< T > &x1, const fvar< T > &x2)
Return the greater of the two specified arguments.
Definition fmax.hpp:23
void check_positive(const char *function, const char *name, const T_y &y)
Check if y is positive.
ref_type_t< T && > to_ref(T &&a)
This evaluates expensive Eigen expressions.
Definition to_ref.hpp:18
void check_less(const char *function, const char *name, const T_y &y, const T_high &high, Idxs... idxs)
Throw an exception if y is not strictly less than high.
int64_t max_size(const T1 &x1, const Ts &... xs)
Calculate the size of the largest input.
Definition max_size.hpp:20
fvar< T > log1m(const fvar< T > &x)
Definition log1m.hpp:12
void check_greater(const char *function, const char *name, const T_y &y, const T_low &low, Idxs... idxs)
Throw an exception if y is not strictly greater than low.
auto make_partials_propagator(Ops &&... ops)
Construct an partials_propagator.
void check_positive_finite(const char *function, const char *name, const T_y &y)
Check if y is positive and finite.
fvar< T > fabs(const fvar< T > &x)
Definition fabs.hpp:16
fvar< T > square(const fvar< T > &x)
Definition square.hpp:12
fvar< T > exp(const fvar< T > &x)
Definition exp.hpp:15
typename ref_type_if< true, T >::type ref_type_t
Definition ref_type.hpp:56
typename partials_return_type< Args... >::type partials_return_t
The lgamma implementation in stan-math is based on either the reentrant safe lgamma_r implementation ...
Extends std::true_type when instantiated with zero or more template parameters, all of which extend t...
Template metaprogram to calculate whether a summand needs to be included in a proportional (log) prob...