You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
It's a little early, but once we get the `lpdf` function working with the above we will want to get out a pen and paper to simplify and find common subexpressions we only need to calculate once.
74
72
For instance in the normal we can compute `y - mu` and `1/sigma`
// return `logp` and handle rules for propogating partials for each autodiff type.
282
+
// return `logp` and handle rules for propagating partials for each autodiff type.
287
283
return ops_partials.build(logp);
288
284
```
289
285
290
286
The `logp` is used to accumulate the log probability density function's value,
291
287
where `propto` is used to decide whether or not that value should have constants
292
288
added or dropped.
293
289
294
-
The odd bits here are mostly the `if`s that are of the form
295
-
`include_summand<propto>::value` and `!is_constant_all<T_loc>::value`. We want to
290
+
The odd bits here are mostly the `if`s that include
291
+
`include_summand<propto>` and `!is_constant_all<T_loc>`. We want to
296
292
only compute the partials and accumulate the constants if those values are not
297
293
constant (`double`), so we have an if statement here, which since the conditional
298
294
is a type trait whose value is known at compile time we won't pay for any of these
@@ -324,7 +320,7 @@ them into operands adjoint.
324
320
The for loop version is nice and simple, but there's a few things for performance
325
321
that we can do better. For instance, in the for loop version we are constantly
326
322
reading and writing to memory from a bunch of different places. We can fix that by
327
-
rewriting the above to use multiple loops, but unless we have seperate loops
323
+
rewriting the above to use multiple loops, but unless we have separate loops
328
324
that turn on and off for when combinations of partials need to be calculated
329
325
then we lose places where we can share calculations between partials.
330
326
@@ -381,7 +377,7 @@ For instance, when calculating `inv_sigma`, if that expression is used for
381
377
calculating multiple partials then we want to evaluate it once on that line
382
378
and reuse the precomputed operation multiple times in the preceding code. However
383
379
if it's not used multiple times then we just want an expression that will then
384
-
later be evaluated at it's final destination. The same happens for `y_scaled_sq`
380
+
later be evaluated at its final destination. The same happens for `y_scaled_sq`
385
381
and `scaled_diff`.
386
382
387
383
One odd piece of code here is
@@ -424,7 +420,7 @@ let the compiler see we are doing division by 1 and will remove the operation.
424
420
But that's it, you can see the full `normal_lpdf` function [here](https://github.com/stan-dev/math/blob/develop/stan/math/prim/prob/normal_lpdf.hpp) in Stan that uses the Eigen version.
425
421
426
422
One other little piece you'll want to do is add a `normal_lpdf` function with the exact same signature
427
-
but without the `propto`paremeter. Unless told otherwise we don't assume users want the proportional constants
423
+
but without the `propto`parameter. Unless told otherwise we don't assume users want the proportional constants
428
424
added so we have a default signature that does not require setting the `propto` parameter.
Copy file name to clipboardExpand all lines: doxygen/contributor_help_pages/common_pitfalls.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -203,7 +203,7 @@ class my_big_type {
203
203
204
204
We can see in the above that the standard style of a move (the constructor taking an rvalue reference) is to copy the pointer and then null out the original pointer. But in Stan, particularly for reverse mode, we need to keep memory around even if it's only a temporary for when we call the gradient calculations in the reverse pass. And since memory for reverse mode is stored in our arena allocator no copying happens in the first place.
205
205
206
-
When working with arithmetic types, keep in mind that moving Scalars is often less optimal than simply taking their copy. For instance, Stan's `var` type is a PIMPL implimentation, so it simply holds a pointer of size 8 bytes. A `double` is also 8 bytes which just so happens to fit exactly in a [word](https://en.wikipedia.org/wiki/Word_(computer_architecture)) of most modern CPUs. While a reference to a double is also 8 bytes, unless the function is inlined by the compiler, the computer will have to place the reference into cache, then go fetch the value that is being referenced which now takes up two words instead of one!
206
+
When working with arithmetic types, keep in mind that moving Scalars is often less optimal than simply taking their copy. For instance, Stan's `var` type is a PIMPL implementation, so it simply holds a pointer of size 8 bytes. A `double` is also 8 bytes which just so happens to fit exactly in a [word](https://en.wikipedia.org/wiki/Word_(computer_architecture)) of most modern CPUs. While a reference to a double is also 8 bytes, unless the function is inlined by the compiler, the computer will have to place the reference into cache, then go fetch the value that is being referenced which now takes up two words instead of one!
207
207
208
208
The general rules to follow for passing values to a function are:
209
209
@@ -227,7 +227,7 @@ The pointer is cheap to copy around and is safe to copy into lambdas for
227
227
228
228
As an example, see the implementation of `mdivide_left`
@@ -46,14 +46,14 @@ The Stan Math library is spit into 4 main source folders that hold functions, ty
46
46
47
47
- prim: General `Scalar`, `Matrix`, and `std::vector<T>` types
48
48
- rev: Specializations for reverse mode automatic differentiation
49
-
- fwd: Specializtions for forward mode automatic differentiation.
49
+
- fwd: Specializations for forward mode automatic differentiation.
50
50
- mix: Sources to allow mixes of forward and reverse mode.
51
51
- opencl: Sources for doing reverse mode automatic differentiation on GPUs.
52
52
53
53
Within each of those folders you will find any one of the following folders
54
54
55
-
- core: Base implimentations of custom scalars or backend setup.
56
-
- Ex: in `prim` this is operators for complex numbers and the setup for threading, `rev`'s core is the scalar and it's base operators for reverse mode and the stack allocator, and `fwd` has the scalar for forward mode autodiff and it's operators.
55
+
- core: Base implementations of custom scalars or backend setup.
56
+
- Ex: in `prim` this is operators for complex numbers and the setup for threading, `rev`'s core is the scalar and its base operators for reverse mode and the stack allocator, and `fwd` has the scalar for forward mode autodiff and its operators.
57
57
- err: Functions that perform a check and if true throw an error.
58
58
- fun: The math functions exposed to the Stan language.
59
59
- functor: Functions that take in other functions and data as input such as `reduce_sum()`
@@ -97,7 +97,7 @@ This is pretty standard C++ besides (1), (2), and (3) which I'll go over here.
97
97
TL;DR: Before accessing individual coefficients of an Eigen type, use `to_ref()` to make sure it's a type that's safe to access by coefficient.
98
98
99
99
100
-
In the Stan math library we allow functions to accept eigen expressions. This is rather nice as for instance the code
100
+
In the Stan math library we allow functions to accept Eigen expressions. This is rather nice as for instance the code
101
101
102
102
```cpp
103
103
Eigen::MatrixXd x = multiply(add(A, multiply(B, C)), add(D, E));
Using lazily evaluated expressions allows Eigen to avoid redundant copies, reads, and writes to our data. However, this comes at a cost.
112
112
113
-
In (2), when we access the coefficients of `x`, if it's type is similar to the wacky expression above we can get incorrect results as Eigen does not gurantee any safety of results when performing coefficient level access on a expression type that transforms it's inputs. So `to_ref()` looks at it's input type, and if the input type is an Eigen expression that it evaluates the expression so that all the computations are performed and the return object is then safe to access.
113
+
In (2), when we access the coefficients of `x`, if its type is similar to the wacky expression above we can get incorrect results as Eigen does not guarantee any safety of results when performing coefficient level access on a expression type that transforms its inputs. So `to_ref()` looks at its input type, and if the input type is an Eigen expression that it evaluates the expression so that all the computations are performed and the return object is then safe to access.
114
114
115
115
But! Suppose our input is something like
116
116
@@ -128,13 +128,13 @@ If we used `auto` here then if the return type of `to_ref()` was an `Eigen::Matr
128
128
129
129
#### (2) Using `value_type_t<>` and Friends
130
130
131
-
The [type trait](@ref type_traits)`value_type_t` is one of several type traits we use in the library to query information about types. `value_type_t` will return the inner type of a container,
132
-
so `value_type_t<Eigen::Matrix<double, -1, -1>>` will return `double`, `std::vector<std::vector<double>>` will return a `std::vector<double>` and `value_type_t<double>` will simply return a double.
133
-
See the module on type traits for a
131
+
The type trait `value_type_t` is one of several type traits we use in the library to query information about types. `value_type_t` will return the inner type of a container,
132
+
so `value_type_t<Eigen::Matrix<double, -1, -1>>` will return `double`, `value_type_t<std::vector<std::vector<double>>>` will return a `std::vector<double>` and `value_type_t<double>` will simply return a double.
133
+
See the module on type traits for a guide on Stan's specific type traits.
134
134
135
135
#### (3) Accessing Eigen matrices though `.coeff()` and `.coeffRef()`
136
136
137
-
This is a small bit, but Eigen performs bounds checks by default when using `[]` or `()` to access elements. However `.coeff()` and `.coeffRef()` do not. Because Stan model's perform bounds checking at a higher level it's safe to remove the bounds checks here.
137
+
This is a small bit, but Eigen performs bounds checks by default when using `[]` or `()` to access elements. However `.coeff()` and `.coeffRef()` do not. Because Stan model's perform bounds checking at a higher level its safe to remove the bounds checks here.
138
138
139
139
#### Testing
140
140
@@ -182,7 +182,7 @@ struct DenseStorage {
182
182
}
183
183
```
184
184
185
-
It's very common for us to want to access just the `val_` or `adj_` of the `vari`'s inside of the `var`'s and so we have written custom methods `.adj()` and `.val()` using Eigen's plugin system which returns an expression of an `Eigen::Matrix<double, Rows, Cols>` representing the `var`'s values and adjoints, respectivly.
185
+
It's very common for us to want to access just the `val_` or `adj_` of the `vari`'s inside of the `var`'s and so we have written custom methods `.adj()` and `.val()` using Eigen's plugin system which returns an expression of an `Eigen::Matrix<double, Rows, Cols>` representing the `var`'s values and adjoints, respectively.
186
186
187
187
#### Using type traits to Expose Our New Function
188
188
@@ -264,7 +264,7 @@ all the outputs and inputs. (reverse pass)
264
264
265
265
Reverse mode autodiff in Math requires a huge number of temporaries and
266
266
intermediates to be computed and saved for the reverse pass. There are
267
-
so many allocations that the overhead of `malloc()` becomes noticable. To
267
+
so many allocations that the overhead of `malloc()` becomes noticeable. To
268
268
avoid this, Math provides its own memory arena. The assumptions of
269
269
the Math arena are:
270
270
@@ -312,7 +312,7 @@ auto myfunc(const T& x) {
312
312
313
313
## (2) Setting up the Reverse Pass
314
314
315
-
Once we have stored the data we need for the reverse pass we need to actually write that reverse pass! We need to take our adjoint calculation and put it onto the callback stack so that when the users call `grad()` the adjoints are propogated upwards properly.
315
+
Once we have stored the data we need for the reverse pass we need to actually write that reverse pass! We need to take our adjoint calculation and put it onto the callback stack so that when the users call `grad()` the adjoints are propagated upwards properly.
316
316
317
317
For this we have a function called `reverse_pass_callback()`. Calling `reverse_pass_callback()` with a functor `f` creates an object on the callback stack that will call `f`.
318
318
@@ -433,7 +433,7 @@ inline auto sin(const Container& x) {
433
433
}
434
434
```
435
435
436
-
In Stan math, a `container` type is an `std::vector` that holds either other `std::vector`s or `Eigen::Matrix` types. So in the first function we use `apply_scalar_unary` to apply `sin()` to either `Scalar`s, `std::vector`s holding scalars, or `Eigen::Matrix` types. The second function which uses `apply_vector_unary()` will apply it's lambda to the container's whose elements are also containers or Eigen matrices.
436
+
In Stan math, a `container` type is an `std::vector` that holds either other `std::vector`s or `Eigen::Matrix` types. So in the first function we use `apply_scalar_unary` to apply `sin()` to either `Scalar`s, `std::vector`s holding scalars, or `Eigen::Matrix` types. The second function which uses `apply_vector_unary()` will apply its lambda to the container's whose elements are also containers or Eigen matrices.
437
437
438
438
439
439
### Binary Functions (and least-upper-bound return type semantics)
0 commit comments