StanBlocks.jl
  • Overview
  • Implementations
  • @slic
  • Golf
  • ISBA-2024
  • Crowdsourcing

On this page

  • StanBlocks.jl implementation
  • Generated Stan models

Golf models reimplementation

Author

Nikolas Siccha

TO DO: elaborate

StanBlocks.jl implementation

TO DO: elaborate

Generated Stan models

  • golf_logistic
  • golf_angle
  • golf_angle_distance_2
  • golf_angle_distance_3_with_resids
  • golf_angle_distance_4
functions {
vector binomial_logit_lpmfs(
    array[] int y,
    array[] int args1,
    vector args2
) {
    int n = dims(y)[1];
    return jbroadcasted_binomial_logit_lpmfs(y, args1, args2);
}
vector jbroadcasted_binomial_logit_lpmfs(
    array[] int x1,
    array[] int x2,
    vector x3
) {
    int n = dims(x1)[1];
    vector[n] rv;
    for(i in 1:n) {
        rv[i] = binomial_logit_lpmfs(
            broadcasted_getindex(x1, i),
            broadcasted_getindex(x2, i),
            broadcasted_getindex(x3, i)
        );
    }
    return rv;
}
real binomial_logit_lpmfs(
    int args1,
    int args2,
    real args3
) {
    return binomial_logit_lpmf(args1 | args2, args3);
}
int broadcasted_getindex(array[] int x, int i) {
    int m = dims(x)[1];
    return x[i];
}
real broadcasted_getindex(vector x, int i) {
    int m = dims(x)[1];
    return x[i];
}
}
data {
    int y_n;
    array[y_n] int y;
    int n_n;
    array[n_n] int n;
    int x_n;
    vector[x_n] x;
}
transformed data {
}
parameters {
    real a;
    real b;
}
transformed parameters {
}
model {
    y ~ binomial_logit(n, (a + (b * x)));
}
generated quantities {
    vector[y_n] y_likelihood = binomial_logit_lpmfs(y, n, (a + (b * x)));
    array[x_n] int y_gen = binomial_logit_rng(n, (a + (b * x)));
}
functions {
vector binomial_lpmfs(
    array[] int y,
    array[] int args1,
    vector args2
) {
    int n = dims(y)[1];
    return jbroadcasted_binomial_lpmfs(y, args1, args2);
}
vector jbroadcasted_binomial_lpmfs(
    array[] int x1,
    array[] int x2,
    vector x3
) {
    int n = dims(x1)[1];
    vector[n] rv;
    for(i in 1:n) {
        rv[i] = binomial_lpmfs(
            broadcasted_getindex(x1, i),
            broadcasted_getindex(x2, i),
            broadcasted_getindex(x3, i)
        );
    }
    return rv;
}
real binomial_lpmfs(
    int args1,
    int args2,
    real args3
) {
    return binomial_lpmf(args1 | args2, args3);
}
int broadcasted_getindex(array[] int x, int i) {
    int m = dims(x)[1];
    return x[i];
}
real broadcasted_getindex(vector x, int i) {
    int m = dims(x)[1];
    return x[i];
}
}
data {
    int x_n;
    real R;
    real r;
    vector[x_n] x;
    int y_n;
    array[y_n] int y;
    int n_n;
    array[n_n] int n;
}
transformed data {
    vector[x_n] threshold_angle = asin(((R - r) ./ x));
}
parameters {
    real<lower=0> sigma;
}
transformed parameters {
    vector[x_n] p = ((2 * Phi((threshold_angle / sigma))) - 1);
}
model {
    y ~ binomial(n, p);
}
generated quantities {
    vector[y_n] y_likelihood = binomial_lpmfs(y, n, p);
    int y_gen = binomial_rng(n, p);
    real sigma_degrees = ((sigma * 180) / 3.141592653589793);
}
functions {
vector binomial_lpmfs(
    array[] int y,
    array[] int args1,
    vector args2
) {
    int n = dims(y)[1];
    return jbroadcasted_binomial_lpmfs(y, args1, args2);
}
vector jbroadcasted_binomial_lpmfs(
    array[] int x1,
    array[] int x2,
    vector x3
) {
    int n = dims(x1)[1];
    vector[n] rv;
    for(i in 1:n) {
        rv[i] = binomial_lpmfs(
            broadcasted_getindex(x1, i),
            broadcasted_getindex(x2, i),
            broadcasted_getindex(x3, i)
        );
    }
    return rv;
}
real binomial_lpmfs(
    int args1,
    int args2,
    real args3
) {
    return binomial_lpmf(args1 | args2, args3);
}
int broadcasted_getindex(array[] int x, int i) {
    int m = dims(x)[1];
    return x[i];
}
real broadcasted_getindex(vector x, int i) {
    int m = dims(x)[1];
    return x[i];
}
}
data {
    int x_n;
    real R;
    real r;
    vector[x_n] x;
    real distance_tolerance;
    real overshot;
    int y_n;
    array[y_n] int y;
    int n_n;
    array[n_n] int n;
}
transformed data {
    vector[x_n] threshold_angle = asin(((R - r) ./ x));
}
parameters {
    vector<lower=0.0>[2] sigma;
}
transformed parameters {
    real sigma_angle = sigma[1];
    vector[x_n] p_angle = ((2 * Phi((threshold_angle / sigma_angle))) - 1);
    real sigma_distance = sigma[2];
    vector[x_n] p_distance = (
        Phi(((distance_tolerance - overshot) ./ ((x + overshot) * sigma_distance))) -
        Phi(((-overshot) ./ ((x + overshot) * sigma_distance)))
    );
    vector[x_n] p = (p_angle .* p_distance);
}
model {
    sigma ~ normal(0, 1);
    y ~ binomial(n, p);
}
generated quantities {
    vector[y_n] y_likelihood = binomial_lpmfs(y, n, p);
    int y_gen = binomial_rng(n, p);
    real sigma_degrees = ((sigma_angle * 180) / 3.141592653589793);
}
functions {
vector normal_lpdfs(
    array[] int obs,
    vector loc,
    vector scale
) {
    int n = dims(obs)[1];
    return jbroadcasted_normal_lpdfs(obs, loc, scale);
}
vector jbroadcasted_normal_lpdfs(
    array[] int x1,
    vector x2,
    vector x3
) {
    int n = dims(x1)[1];
    vector[n] rv;
    for(i in 1:n) {
        rv[i] = normal_lpdfs(broadcasted_getindex(x1, i), broadcasted_getindex(x2, i), broadcasted_getindex(x3, i));
    }
    return rv;
}
real normal_lpdfs(
    int args1,
    real args2,
    real args3
) {
    return normal_lpdf(args1 | args2, args3);
}
int broadcasted_getindex(array[] int x, int i) {
    int m = dims(x)[1];
    return x[i];
}
real broadcasted_getindex(vector x, int i) {
    int m = dims(x)[1];
    return x[i];
}
}
data {
    int x_n;
    real R;
    real r;
    vector[x_n] x;
    real distance_tolerance;
    real overshot;
    int n_n;
    array[n_n] int n;
    int y_n;
    array[y_n] int y;
}
transformed data {
    vector[x_n] threshold_angle = asin(((R - r) ./ x));
    vector[n_n] vec_n = to_vector(n);
}
parameters {
    vector<lower=0.0>[2] sigma;
    real sigma_y;
}
transformed parameters {
    real sigma_angle = sigma[1];
    vector[x_n] p_angle = ((2 * Phi((threshold_angle / sigma_angle))) - 1);
    real sigma_distance = sigma[2];
    vector[x_n] p_distance = (
        Phi(((distance_tolerance - overshot) ./ ((x + overshot) * sigma_distance))) -
        Phi(((-overshot) ./ ((x + overshot) * sigma_distance)))
    );
    vector[x_n] p = (p_angle .* p_distance);
}
model {
    sigma ~ normal(0, 1);
    sigma_y ~ normal(0, 1);
    y ~ normal((vec_n .* p), (vec_n .* sqrt((((p .* (1 - p)) ./ to_vector(n)) + (sigma_y ^ 2)))));
}
generated quantities {
    vector[y_n] y_likelihood = normal_lpdfs(y, (vec_n .* p), (vec_n .* sqrt((((p .* (1 - p)) ./ to_vector(n)) + (sigma_y ^ 2)))));
    array[n_n] real y_gen = normal_rng((vec_n .* p), (vec_n .* sqrt((((p .* (1 - p)) ./ to_vector(n)) + (sigma_y ^ 2)))));
    real sigma_degrees = ((sigma_angle * 180) / 3.141592653589793);
}
functions {
real normal_lpdfs(
    real args1,
    int args2,
    int args3
) {
    return normal_lpdf(args1 | args2, args3);
}
vector binomial_lpmfs(
    array[] int y,
    array[] int args1,
    vector args2
) {
    int n = dims(y)[1];
    return jbroadcasted_binomial_lpmfs(y, args1, args2);
}
vector jbroadcasted_binomial_lpmfs(
    array[] int x1,
    array[] int x2,
    vector x3
) {
    int n = dims(x1)[1];
    vector[n] rv;
    for(i in 1:n) {
        rv[i] = binomial_lpmfs(
            broadcasted_getindex(x1, i),
            broadcasted_getindex(x2, i),
            broadcasted_getindex(x3, i)
        );
    }
    return rv;
}
real binomial_lpmfs(
    int args1,
    int args2,
    real args3
) {
    return binomial_lpmf(args1 | args2, args3);
}
int broadcasted_getindex(array[] int x, int i) {
    int m = dims(x)[1];
    return x[i];
}
real broadcasted_getindex(vector x, int i) {
    int m = dims(x)[1];
    return x[i];
}
}
data {
    int x_n;
    real R;
    real r;
    vector[x_n] x;
    real overshot;
    real distance_tolerance;
    int y_n;
    array[y_n] int y;
    int n_n;
    array[n_n] int n;
}
transformed data {
    vector[x_n] threshold_angle = asin(((R - r) ./ x));
}
parameters {
    vector<lower=0.0>[2] sigma;
}
transformed parameters {
    real sigma_angle = sigma[1];
    vector[x_n] p_angle = ((2 * Phi((threshold_angle / sigma_angle))) - 1);
    real sigma_distance = sigma[2];
    vector[x_n] p_distance = (
        Phi(((distance_tolerance - overshot) ./ ((x + overshot) * sigma_distance))) -
        Phi(((-overshot) ./ ((x + overshot) * sigma_distance)))
    );
    vector[x_n] p = (p_angle .* p_distance);
}
model {
    sigma ~ normal(0, 1);
    overshot ~ normal(1, 5);
    distance_tolerance ~ normal(3, 5);
    y ~ binomial(n, p);
}
generated quantities {
    real overshot_likelihood = normal_lpdfs(overshot, 1, 5);
    real overshot_gen = normal_rng(1, 5);
    real distance_tolerance_likelihood = normal_lpdfs(distance_tolerance, 3, 5);
    real distance_tolerance_gen = normal_rng(3, 5);
    vector[y_n] y_likelihood = binomial_lpmfs(y, n, p);
    int y_gen = binomial_rng(n, p);
    real sigma_degrees = ((sigma_angle * 180) / 3.141592653589793);
}
Source Code
---
title: "Golf models reimplementation"
---

TO DO: elaborate

## StanBlocks.jl implementation

TO DO: elaborate

## Generated Stan models

```{julia}
using StanBlocks, QuartoComponents

"Downloads and preprocesses the golf datasets"
golf_data(url) = begin 
    x, n, y = eachcol(mapreduce(row->(parse.(Float64, split(row))), hcat, filter(startswith(r"[0-9]"), readlines(download(url))))')
    (;x, n=Int.(n), y=Int.(y))
end

# Fetch the first dataset
dataset1 = golf_data("https://gist.githubusercontent.com/nsiccha/553d6ce6a784142e87fbfd7aaf4c5e99/raw/668b86ddd84b45b707e594dd313f717bef1a553d/dataset1.txt")

# Fetch the second dataset
dataset2 = golf_data("https://gist.githubusercontent.com/nsiccha/13fd14e1cc5e1520aa688c1f4df2f9a7/raw/726764870b46c72911e89668eef48a22a6c13035/dataset2.txt")

# Combine the two datasets
dataset12 = map(vcat, dataset1, dataset2)


golf_logistic = @slic begin 
    a ~ flat()
    b ~ flat()
    y ~ binomial_logit(n, a + b * x)
end
golf_angle = @slic begin 
    threshold_angle = asin((R - r) ./ x)
    sigma ~ flat(;lower=0)
    p = 2 * Phi(threshold_angle / sigma) - 1
    y ~ binomial(n, p)
    sigma_degrees = sigma * 180 / pi
end
r = (1.68/2)/12
R = (4.25/2)/12
golf_angle_distance_2 = golf_angle(quote 
    sigma ~ normal(0, 1; n=2, lower=0.)
    sigma_angle = sigma[1]
    sigma_distance = sigma[2]
    p_angle = 2 * Phi(threshold_angle / sigma_angle) - 1
    p_distance = (
        Phi((distance_tolerance - overshot) ./ ((x + overshot) * sigma_distance))
         - Phi((-overshot) ./ ((x + overshot) * sigma_distance))
    )
    p = p_angle .* p_distance
    sigma_degrees = sigma_angle * 180 / pi
end)

overshot = 1.
distance_tolerance = 3.
golf_angle_distance_3_with_resids = golf_angle_distance_2(quote
    vec_n = to_vector(n)
    sigma_y ~ normal(0, 1)
    y ~ normal(vec_n .* p, vec_n .* sqrt(p .* (1 - p) ./ to_vector(n) + sigma_y ^ 2))
end)
golf_angle_distance_4 = golf_angle_distance_2(quote 
    overshot ~ normal(1, 5; lower=0)
    distance_tolerance ~ normal(3, 5; lower=0)
end)

map(x->QuartoComponents.Code("stan", stan_code(x)), (;
    golf_logistic=golf_logistic(;dataset1...),
    golf_angle=golf_angle(;r, R, dataset1...),
    golf_angle_distance_2=golf_angle_distance_2(;r, R, overshot, distance_tolerance, dataset12...),
    golf_angle_distance_3_with_resids=golf_angle_distance_3_with_resids(;r, R, overshot, distance_tolerance, dataset12...),
    golf_angle_distance_4=golf_angle_distance_4(;r, R, overshot, distance_tolerance, dataset12...),
))|> QuartoComponents.Tabset 
```