Skip to content

Conversation

@Franzi2114
Copy link
Collaborator

Summary

This is a short PR building upon the PRs to add the wiener_pdf (PR #2822), wiener_cdf and wiener_ccdf (PR #3042) functions and refers to issue #3256.

The only thing that this PR changes is the names of the cdf and ccdf functions as they are implemented defectively, which means that the functions do not integrate to 1, but to the probability to hit one or the other response boundary. Therefore, the standard way of calculating truncated and censored models with the truncation operator (T[,] ) yields wrong results and the manual way to compute such models should be chosen.

Papers

  • Henrich, F., Hartmann, R., Pratz, V., Voss, A., & Klauer, K.C. (2023). The Seven-parameter Diffusion Model: An Implementation in Stan for Bayesian Analyses. Behavior Research Methods. https://doi.org/10.3758/s13428-023-02179-1
  • Henrich, F., & Klauer, K. C. (in press). Modeling Truncated and Censored Data With the Diffusion Model in Stan. Behavior Research Methods.

Release notes

Change names for wiener_lc(c)df to wiener_lc(c)df_defective

Checklist

  • Copyright holder: Franziska Henrich

    The copyright holder is typically you or your assignee, such as a university or company. By submitting this pull request, the copyright holder is agreeing to the license the submitted work under the following licenses:
    - Code: BSD 3-clause (https://opensource.org/licenses/BSD-3-Clause)
    - Documentation: CC-BY 4.0 (https://creativecommons.org/licenses/by/4.0/)

  • the basic tests are passing

    • unit tests pass (to run, use: ./runTests.py test/unit)
    • header checks pass, (make test-headers)
    • dependencies checks pass, (make test-math-dependencies)
    • docs build, (make doxygen)
    • code passes the built in C++ standards checks (make cpplint)
  • the code is written in idiomatic C++ and changes are documented in the doxygen

  • the new changes are tested

Copy link
Member

@WardBrian WardBrian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @Franzi2114

If you can provide me the Stan signatures of these new functions I can put together the compiler PR rather quickly!

If you have the time, it would also be great to at least add these to the functions reference documentation https://github.com/stan-dev/docs/blob/master/src/functions-reference/positive_lower-bounded_distributions.qmd#L158

@Franzi2114
Copy link
Collaborator Author

Thanks @Franzi2114

If you can provide me the Stan signatures of these new functions I can put together the compiler PR rather quickly!

Do you mean this one from the Stan_math_signatures.ml file in stanc3?

With the old name I had the following line:
; ([Lpdf; Ccdf; Cdf], "wiener", [DReal; DReal; DReal; DReal; DReal; DReal; DReal; DReal], SoA)

Would it now be this one?
; ([Lpdf; Ccdf_defective; Cdf_defective], "wiener", [DReal; DReal; DReal; DReal; DReal; DReal; DReal; DReal], SoA)

@Franzi2114
Copy link
Collaborator Author

If you have the time, it would also be great to at least add these to the functions reference documentation https://github.com/stan-dev/docs/blob/master/src/functions-reference/positive_lower-bounded_distributions.qmd#L158

What is this? Are here all possible function calls listed?

Why is it wiener_lupdf here with the u inside the name? How would it look like for the cdf functions?

Actually, all functions are implemented in the way that the user is able to set the precision of the partial derivatives. This shall increase the speed of the computations. This is implemented like this, with the last parameter for the precision:

inline 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 T_sv& sv,
                                  const T_sw& sw, const T_st0& st0,
                                  const double& precision_derivatives = 1e-8) {

Is this already possible with these signatures or should we also add an entry like:

`real` **`wiener_lupdf`**`(real y | real alpha, real tau, real beta, real delta, real var_delta, real var_beta, real var_tau, real precision)`<br>\newline

@WardBrian
Copy link
Member

Do you mean this one from the Stan_math_signatures.ml file in stanc3?

I don't mean in OCaml code, just the valid signatures. Right now, here's whats there for wiener_lpdf with 6 or 8 arguments

wiener_lpdf(real, real, real, real, real, real) => real
wiener_lpdf(real, real, real, real, real, real, real, real) => real
wiener_lpdf(vector, vector, vector, vector, vector, vector) => real
wiener_lpdf(vector, vector, vector, vector, vector, vector, vector, vector) => real

Looking at this PR, it looks like the cdf/ccdf takes either 5 or 8 arguments, rather than 6 or 8. Is that correct?

What is this? Are here all possible function calls listed?

This is the document that gets turned into https://mc-stan.org/docs/functions-reference/positive_lower-bounded_distributions.html#wiener-first-passage-time-distribution

In particular, I would mostly need your help writing out the math and the names for the arguments, etc. The specially formatted comments etc I can handle (they're used for things like generating an index of all functions)

@WardBrian
Copy link
Member

Actually, all functions are implemented in the way that the user is able to set the precision of the partial derivatives.

This is not currently implemented by the compiler, but it would be possible to expose to the user with new overloads. We're lucky that we can still tell them apart just by length (if one of the non-precision overloads had 7 arguments, then 7+precision = 8 and that would be ambiguous with the 8-argument non-precision)

@stan-buildbot

This comment was marked as off-topic.

@Franzi2114 Franzi2114 merged commit 062d304 into stan-dev:develop Dec 11, 2025
34 checks passed
@Franzi2114
Copy link
Collaborator Author

Ok, so the following function calls should work:

wiener_lpdf(y, a, t0, w, v, sv)                              -> 6 arguments
wiener_lpdf(y, a, t0, w, v, sv, precision)             -> 7 arguments
wiener_lpdf(y, a, t0, w, v, sv, sw, st0)                 -> 8 arguments 
wiener_lpdf(y, a, t0, w, v, sv, sw, st0, precision) -> 9 arguments 

In both variants with real and vector (where the precision is always a real):

wiener_lpdf(real, real, real, real, real, real) => real
wiener_lpdf(real, real, real, real, real, real, real) => real
wiener_lpdf(real, real, real, real, real, real, real, real) => real
wiener_lpdf(real, real, real, real, real, real, real, real, real) => real
wiener_lpdf(vector, vector, vector, vector, vector, vector) => real
wiener_lpdf(vector, vector, vector, vector, vector, vector, real) => real
wiener_lpdf(vector, vector, vector, vector, vector, vector, vector, vector) => real
wiener_lpdf(vector, vector, vector, vector, vector, vector, vector, vector, real) => real

This is analog with the cdf/ccdf functions:

wiener_lc(c)df(y, a, t0, w, v)   -> 5 arguments
wiener_lc(c)df(y, a, t0, w, v, precision)   -> 6 arguments
wiener_lc(c)df(y, a, t0, w, v, sv, sw, st0)   -> 8 arguments 
wiener_lc(c)df(y, a, t0, w, v, sv, sw, st0, precision) -> 9 arguments 

In both variants with real and vector (where the precision is always a real):

wiener_lcdf(real, real, real, real, real) => real
wiener_lcdf(real, real, real, real, real, real) => real
wiener_lcdf(real, real, real, real, real, real, real, real) => real
wiener_lcdf(real, real, real, real, real, real, real, real, real) => real
wiener_lcdf(vector, vector, vector, vector, vector) => real
wiener_lcdf(vector, vector, vector, vector, vector, real) => real
wiener_lcdf(vector, vector, vector, vector, vector, vector, vector, vector) => real
wiener_lcdf(vector, vector, vector, vector, vector, vector, vector, vector, real) => real
wiener_lccdf(real, real, real, real, real) => real
wiener_lccdf(real, real, real, real, real, real) => real
wiener_lccdf(real, real, real, real, real, real, real, real) => real
wiener_lccdf(real, real, real, real, real, real, real, real, real) => real
wiener_lccdf(vector, vector, vector, vector, vector) => real
wiener_lccdf(vector, vector, vector, vector, vector, real) => real
wiener_lccdf(vector, vector, vector, vector, vector, vector, vector, vector) => real
wiener_lccdf(vector, vector, vector, vector, vector, vector, vector, vector, real) => real

Does this help?

@WardBrian
Copy link
Member

That sounds good!

@Franzi2114 I'm getting an unused variable warning for params_dt7 in the new code -- is that a bug, or just a variable that should be cleaned up?

@WardBrian
Copy link
Member

@Franzi2114, wiener_lccdf_defective in stan/math/prim/prob/wiener4_lccdf_defective.hpp is missing a default value for precision_derivatives. Looking at the lcdf, should it be 1e-4?

@Franzi2114
Copy link
Collaborator Author

is missing a default value for precision_derivatives. Looking at the lcdf, should it be 1e-4?

Oh, indeed! Yes, this should also be 1e-4 as in the other function. Do you want to add this or shall I do another PR?

@Franzi2114
Copy link
Collaborator Author

unused variable warning for params_dt7 in the new code -- is that a bug, or just a variable that should be cleaned up?

I just checked this. This is not used in the code and can therefore be deleted in both wiener_full_lcdf_defective and wiener_full_lccdf_defective. Probably, this is an artefact from one of our numerous review rounds ... sorry for that!

If you want, I can do another PR where I add the precision default value and delete these two unused variables. Or do you want to do it, @WardBrian?

@WardBrian
Copy link
Member

I’m happy to do it, there are few other uninteresting testing-related changes that are needed that I will be doing as well. Thanks for confirming!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants