Stanc.Std: Move over Analysis module - #1661
Conversation
0e4e28a to
60fbb2b
Compare
60fbb2b to
76c1fb4
Compare
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## std/stan_math_backend #1661 +/- ##
=========================================================
- Coverage 92.16% 92.11% -0.05%
=========================================================
Files 70 70
Lines 10126 10139 +13
=========================================================
+ Hits 9333 9340 +7
- Misses 793 799 +6
🚀 New features to boost your workflow:
|
| stan::model::assign(psi_con, lcm_sym19__, | ||
| "assigning variable psi_con", stan::model::index_uni(i)); | ||
| stan::model::assign(psi_con, 1, "assigning variable psi_con", | ||
| stan::model::index_uni(i)); |
There was a problem hiding this comment.
Looks like constant propagation got a bit smarter, but why?
There was a problem hiding this comment.
I spent a few hours on trying to debug this and I couldn’t pinpoint the change.
I also threw whatever free credits of Claude github gives me, and it spun in circles but couldn’t identify anything either after spending the entire month’s allocation.
In the end, I think the fact that this wasn’t being propagated in master was a bug, and the relevant optimizations are only turned on for Oexperimental, so I gave up looking for the cause… if you can find anything without wasting too much time, I would still be curious!
There was a problem hiding this comment.
Yes, this was probably a bug in master and not worth chasing down. However, note that the anomaly happens in constant propagation, which is enabled for O1, even though it didn't trigger without some experimental passes first. If you're curious and want to waste even more time I found a "minimal" example:
let%expect_test "constant propagation" =
let mir =
Test_utils.mir_of_string {|
data {
vector[2] X;
int sum_y;
real alpha_occ;
vector[2] logit_p;
}
generated quantities {
vector[2] logit_psi = alpha_occ + alpha_occ * X;
array[2] real psi_con;
if (1) {
real psi = inv_logit(logit_psi[1]);
real qT = prod(logit_p);
psi_con[1] = inv(psi * qT + 1);
} else {
psi_con[1] = 1;
}
real psi = inv_logit(logit_psi[2]);
real qT = prod(logit_p);
psi_con[2] = inv(psi * qT + 1);
} |} in
let open Analysis_and_optimization.Optimize in
let mir = expression_propagation mir in
let mir = lazy_code_motion mir in
let mir = constant_propagation mir in
Fmt.str "@[<v>%a@]" Middle.Program.Typed.pp mir |> print_endline;
[%expect {| ... |}]There was a problem hiding this comment.
The if (1) seems to be the load-bearing part. If you change it to something semantically equivalent, like if (2), then the constant does indeed get moved down
There was a problem hiding this comment.
My theories:
- Some part of the optimization pipeline is iteration-order-dependent by accident, and this branch gets a favorable order
- There is something in
masterthat is accidentally sensitive to the location metadata, and isn't here (though I've tried to find the likely places this would be, and came up empty)
Assuming we're both happy not knowing, what do you think of the rest of the changes?
There was a problem hiding this comment.
Accidental order-dependence sounds plausible. The rest of the changes look good.
76c1fb4 to
473e303
Compare
473e303 to
1017e44
Compare
1017e44 to
96f1f18
Compare
96f1f18 to
d2b371f
Compare
d2b371f to
fcbb41b
Compare
The most notable change here is the addition of our own vendored polymorphic set. This is based on OCaml's set implementation, but with polymorphic comparison swapped in. Remarkably, I've found that it is dramatically faster than Base.Set.Poly in our uses, presumably because
Base.Set.Polyis storing the comparison function in the runtime representation still, even though it never changesSubmission Checklist
Release notes
Copyright and Licensing
By submitting this pull request, the copyright holder is agreeing to
license the submitted work under the BSD 3-clause license (https://opensource.org/licenses/BSD-3-Clause)
Stack created with GitHub Stacks CLI • Give Feedback 💬