Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 18 additions & 6 deletions docs/exposing_new_functions.mld
Original file line number Diff line number Diff line change
Expand Up @@ -126,15 +126,27 @@ For example, the following line defines the signature [add(real, matrix) => matr
Functions such as the ODE integrators or [reduce_sum], which take in user-functions and a variable-length
list of arguments, are {b NOT} added to this list.

"Nice" variadic functions are added to the hashtable [Stan_math_signatures.stan_math_variadic_signatures].
"Nice" variadic functions are added to the hashtable [Generate.stan_math_variadic_signatures] using
the function [add_variadic_fn name ~return_type ?control_args ~required_fn_rt ?required_fn_args ()].
This is probably sufficient for most variadic functions, e.g. all the ODE solvers and DAE solvers are done
via this method.
[reduce_sum] is not "nice", since it is both variadic and {e polymorphic}, requiring certain arguments to have the same
(but {e not predetermined}) type. Therefore, [reduce_sum] is treated as special case in the [Typechecker]
module in the frontend folder.

Note that higher-order functions also usually require changes to the C++ code generation to work properly.
It is best to consult an existing example of how these are done before proceeding.
The arguments are perhaps clearest to understand by example. [return_type] is
the return type of the variadic function itself, e.g.
[UArray UVector] for the variadic ODES. [control_args] is a list of arguments
that come after the callback but before the arguments to the function. These
tend to be initializations, or tolerances. [required_fn_rt] is what the user
callback must return, e.g. [UVector] for the ODE system function. Finally,
[required_fn_args] is the arguments that the callback must accept first, such as
the time and state for ODE system functions.

This final argument determines the C++ code generation of the function, as the
`std::ostream*` argument will come immediately after the required_fn_args in the
list. Ensure that the C++ for the function is calling it accordingly. It is best
to consult an existing example of how these are done before proceeding.

Other functions, such as [reduce_sum] or the laplace marginal functions, are not
"nice". These are not added to this list, and are instead treated as special case in the [Typechecker] module in the frontend folder.

{1 Testing}

Expand Down
34 changes: 34 additions & 0 deletions src/stan_math_signatures/Generate.ml
Original file line number Diff line number Diff line change
Expand Up @@ -2681,6 +2681,40 @@ let () =
; (DataOnly, UInt) ]
~required_fn_rt:UnsizedType.UVector
~required_fn_args:[UnsizedType.(AutoDiffable, UVector)]
();
(* variadic versions of integrate_1d *)
add_variadic_fn "integrate_1d_gauss_kronrod" ~return_type:UnsizedType.UReal
~control_args:
UnsizedType.
[(* interval a, b *) (AutoDiffable, UReal); (AutoDiffable, UReal)]
~required_fn_rt:UnsizedType.UReal
~required_fn_args:
UnsizedType.[(* x, xc *) (AutoDiffable, UReal); (AutoDiffable, UReal)]
();
add_variadic_fn "integrate_1d_double_exponential"
~return_type:UnsizedType.UReal
~control_args:UnsizedType.[(AutoDiffable, UReal); (AutoDiffable, UReal)]
~required_fn_rt:UnsizedType.UReal
~required_fn_args:UnsizedType.[(AutoDiffable, UReal); (AutoDiffable, UReal)]
();
(* _tol version accept rel_tol, abs_tol, and max_depth/max_refinements *)
add_variadic_fn "integrate_1d_double_exponential_tol"
~return_type:UnsizedType.UReal
~control_args:
UnsizedType.
[ (AutoDiffable, UReal); (AutoDiffable, UReal); (DataOnly, UReal)
; (DataOnly, UReal); (DataOnly, UInt) ]
~required_fn_rt:UnsizedType.UReal
~required_fn_args:UnsizedType.[(AutoDiffable, UReal); (AutoDiffable, UReal)]
();
add_variadic_fn "integrate_1d_gauss_kronrod_tol"
~return_type:UnsizedType.UReal
~control_args:
UnsizedType.
[ (AutoDiffable, UReal); (AutoDiffable, UReal); (DataOnly, UReal)
; (DataOnly, UReal); (DataOnly, UInt) ]
~required_fn_rt:UnsizedType.UReal
~required_fn_args:UnsizedType.[(AutoDiffable, UReal); (AutoDiffable, UReal)]
()

(** Print a module definition to [file] that contains the signatures computed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ parameters {
model {
real y = integrate_1d(integrand, 0, 1, x, x_r, x_i);
real z = integrate_1d(integrand, 0, 1, x, x_r, x_i, 1e-8);

x ~ normal(y + z, 1.0);
}

16 changes: 16 additions & 0 deletions test/integration/good/integrate_1d_double_exponential.stan
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
functions {
real integrand(real x, real xc, vector theta, matrix alpha) {
return 0.0;
}
}

parameters {
vector[10] theta;
matrix[2,4] alpha;
}
model {
real y = integrate_1d_double_exponential(integrand, 0, 1, theta, alpha);
real z = integrate_1d_double_exponential_tol(integrand, 0, 1, 1e-8, 0.0, 1, theta, alpha);

y + z ~ normal(0, 1.0);
}
16 changes: 16 additions & 0 deletions test/integration/good/integrate_1d_gauss_kronrod.stan
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
functions {
real integrand(real x, real xc, vector theta, matrix alpha) {
return 0.0;
}
}

parameters {
vector[10] theta;
matrix[2,4] alpha;
}
model {
real y = integrate_1d_gauss_kronrod(integrand, 0, 1, theta, alpha);
real z = integrate_1d_gauss_kronrod_tol(integrand, 0, 1, 1e-8, 0.0, 1, theta, alpha);

y+z ~ normal(0, 1.0);
}
70 changes: 70 additions & 0 deletions test/integration/good/pretty.expected
Original file line number Diff line number Diff line change
Expand Up @@ -3758,6 +3758,76 @@ model {
y_p ~ normal(0, 1);
}

[exit 0]
$ ../../../../install/default/bin/stanc --auto-format integrate_1d_double_exponential.stan
functions {
real integrand(real x, real xc, vector theta, matrix alpha) {
return 0.0;
}
}
parameters {
vector[10] theta;
matrix[2, 4] alpha;
}
model {
real y = integrate_1d_double_exponential(integrand, 0, 1, theta, alpha);
real z = integrate_1d_double_exponential_tol(integrand, 0, 1, 1e-8, 0.0, 1,
theta, alpha);

y + z ~ normal(0, 1.0);
}

[exit 0]
$ ../../../../install/default/bin/stanc --auto-format integrate_1d_gauss_kronrod.stan
functions {
real integrand(real x, real xc, vector theta, matrix alpha) {
return 0.0;
}
}
parameters {
vector[10] theta;
matrix[2, 4] alpha;
}
model {
real y = integrate_1d_gauss_kronrod(integrand, 0, 1, theta, alpha);
real z = integrate_1d_gauss_kronrod_tol(integrand, 0, 1, 1e-8, 0.0, 1,
theta, alpha);

y + z ~ normal(0, 1.0);
}

[exit 0]
$ ../../../../install/default/bin/stanc --auto-format integrate_1d_good.stan
functions {
real foo(real x, real xc, array[] real theta, array[] real x_r,
array[] int x_i) {
return x ^ 2;
}
}
data {
array[2] real x_r;
array[10] int x_i;
}
transformed data {
array[3] real theta_d;
real int_foo1 = integrate_1d(foo, 0.2, 1.3, theta_d, x_r, x_i, 0.01);
}
parameters {
real lb;
real ub;
array[3] real theta;
}
model {
real int_foo2 = integrate_1d(foo, 0.2, 1.3, theta, x_r, x_i, 0.01);
real int_foo3 = integrate_1d(foo, lb, 1.3, theta, x_r, x_i, 0.01);
real int_foo4 = integrate_1d(foo, 0.2, ub, theta, x_r, x_i, 0.01);
real int_foo5 = integrate_1d(foo, lb, ub, theta, x_r, x_i, 0.01);
real int_foo6 = integrate_1d(foo, 0.2, 1.3, theta_d, x_r, x_i, 0.01);
real int_foo7 = integrate_1d(foo, lb, 1.3, theta_d, x_r, x_i, 0.01);
real int_foo8 = integrate_1d(foo, 0.2, ub, theta_d, x_r, x_i, 0.01);
real int_foo9 = integrate_1d(foo, lb, ub, theta_d, x_r, x_i, 0.01);
}

[exit 0]
$ ../../../../install/default/bin/stanc --auto-format io_example.stan
transformed data {
Expand Down
32 changes: 0 additions & 32 deletions test/integration/good/warning/pretty.expected
Original file line number Diff line number Diff line change
Expand Up @@ -119,38 +119,6 @@ Warning in 'int_div_user.stan', line 7, column 6 to column 10:
write the division as
a[1] * 1.0 / b[2]
If rounding is intended please use the integer division operator %/%.
[exit 0]
$ ../../../../../install/default/bin/stanc --auto-format integrate_1d_good.stan
functions {
real foo(real x, real xc, array[] real theta, array[] real x_r,
array[] int x_i) {
return x ^ 2;
}
}
data {
array[2] real x_r;
array[10] int x_i;
}
transformed data {
array[3] real theta_d;
real int_foo1 = integrate_1d(foo, 0.2, 1.3, theta_d, x_r, x_i, 0.01);
}
parameters {
real lb;
real ub;
array[3] real theta;
}
model {
real int_foo2 = integrate_1d(foo, 0.2, 1.3, theta, x_r, x_i, 0.01);
real int_foo3 = integrate_1d(foo, lb, 1.3, theta, x_r, x_i, 0.01);
real int_foo4 = integrate_1d(foo, 0.2, ub, theta, x_r, x_i, 0.01);
real int_foo5 = integrate_1d(foo, lb, ub, theta, x_r, x_i, 0.01);
real int_foo6 = integrate_1d(foo, 0.2, 1.3, theta_d, x_r, x_i, 0.01);
real int_foo7 = integrate_1d(foo, lb, 1.3, theta_d, x_r, x_i, 0.01);
real int_foo8 = integrate_1d(foo, 0.2, ub, theta_d, x_r, x_i, 0.01);
real int_foo9 = integrate_1d(foo, lb, ub, theta_d, x_r, x_i, 0.01);
}

[exit 0]
$ ../../../../../install/default/bin/stanc --auto-format integrate_ode_adams.stan
functions {
Expand Down