Repository navigation
Flatten scal / arr / mat #937
Description
Summary:
Flatten the directory structure by getting rid of the scal, arr, mat folders. The goal is to make the Math library easier to navigate for developers and users.
Description:
Our current directory structure has looks like:
stan/math/- then
{prim, rev, fwd, mix}indicating that we're dealing with no-autodiff, reverse mode, forward mode, or mixed mode - then
{scal, arr, mat}indicated that we're dealing with scalar, array, or matrix, all from the point of view of the Stan language. Scalar is justdoubleor the autodiff variable, array includesstd::vector, and matrix includesEigen. - then
errfor error checking,funfor functions,metafor template meta programs,functorfor dealing with functors,probfor probability distributions - then finally functions are in separate headers.
We'd like to get rid of the {scal, arr, mat} level. We had originally done this to support the use-case of a client of the Math library wanting to compile with only scalars, only scalars + the standard template library (<vector> for std::vector), or compile with all of that and Eigen. I swear we had users request this back when we had the stan-users list on google groups, but I could never find that thread again. The motivation was compile times and minimal includes. (This might have been back in the days when compiling under Windows was limited due to lack of a decent compiler; those days are over.) This has caused a fair amount of technical overhead keeping these things separate. It would really simplify our development if we can assume we have access to std::vector and Eigen::Matrix in every function. Right now, we include the template metaprograms in the very delicate, correct order to instantiate things the right way. So... the order of instantiation is different in stan/math/prim/scal.hpp vs stan/math/prim/arr.hpp vs stan/math/prim/mat.hpp. What we want to do is to instantiate the template metaprograms in the order that the stan/math/*/mat.hpp instantiates them in.
The nice thing is that there is a correct way to instantiate the template metaprograms and we know what that is. We need to trace through those dependencies.
What the top-level includes will look like after we're done
1. stan/math/prim.hpp
2. stan/math/rev.hpp
3. stan/math/fwd.hpp
4. stan/math/mix.hpp
The current top-level includes
1. stan/math/prim/arr.hpp
2. stan/math/prim/mat.hpp
3. stan/math/prim/scal.hpp
4. stan/math/rev/arr.hpp
5. stan/math/rev/mat.hpp
6. stan/math/rev/scal.hpp
7. stan/math/fwd/arr.hpp
8. stan/math/fwd/mat.hpp
9. stan/math/fwd/scal.hpp
10. stan/math/mix/arr.hpp
11. stan/math/mix/mat.hpp
12. stan/math/mix/scal.hpp
Additional Information:
There are a few things we want to check:
- compile times don't go up for standard models
- everything still compiles
It's going to be a little tricky to do this. We should come up with some end-to-end tests for this to make sure it works on top of the lower-level unit tests that should continue to work.
Some unit tests will fail for the template metaprograms. The ones that will fail are for explicit checks that the base template metaprogram behaves in a certain way and we have specializations for std::vector or Eigen::Matrix. It's only once we include the specializations that the behavior will change.
The fix is to merge a bunch of files together. That's oversimplifying it, but that's essentially what we have to do. We just have to make sure things are merged in the right order. If done in that way, we'll maintain the correct behavior. I'll put together some examples below.
I believe we can script this so we don't have to do much by hand. In fact, I'm sure we can get a crude version working this way just by copying and pasting files in the right order.
There are going to be a lot of different ways we can do this. I'd like us to explore ways that keep the code-base working. Maybe even breaking this down into smaller chunks that we can merge as we go along. For example, one thing we may want to do is to merge all the template metaprograms into mat first and leave everything else alone.
We will need to modify make/test-math-dependencies. We will want to keep the rules for the autodiff types, but definitely not the ones for scal, arr, mat.
Current Version:
v2.17.0
Activity
drezap commentedon Feb 22, 2019
for foward we also have
core, is it preferred to just dump these infwdor create afwd/coresubdirectory?syclik commentedon Feb 23, 2019
so I believe you mean
stan/math/fwd/core.hpp. I think I originally posted this before we had it. Either way, I think we can leave those. (Unless you mean something else.)syclik commentedon Feb 23, 2019
I posted this on discourse, but if you have one or more of these skills, please join the effort:
-Mflag in g++)syclik commentedon Feb 23, 2019
One place to start is to consolidate the template metaprograms. We can start at the top of
stan/math/prim/mat.hppIf you look at the includes for
get.hpp, you'll notice that thearrversion needs to be included before thematversion. So when we consolidate the files, it'll look like:Cleaned up, of course.
drezap commentedon Feb 23, 2019
Yep that’s what I mean. So I’ve been ‘cat’int the mat/arr/scal.hpp flies together, and using Linux sed to remove strings from the include that sets stuff back a directory. Is it worth a PR if tests aren’t passing, for the purpose of review? I tried doing just fwd but that depends on prim so I’m starting prim now
syclik commentedon Feb 23, 2019
Yes, I think that makes sense. I think we're going to be going back and forth a lot on this one. We'll take a few steps forward, update a script, look at it carefully, figure out if it works, have to back it out, rinse and repeat.
It'll help to have GitHub's PR framework to compare.
Can you create a branch on this repo? It'll make it easier to coordinate.
drezap commentedon Feb 23, 2019
created branch
code-cleanup/issue-937-flattenwhich only contains theprim.hppnew top level include, if that's sufficient I can start making directoriesfun,functor,errinprimand start combining the files.I'll try not to abruptly leave next time we're mid conversation
drezap commentedon Feb 23, 2019
@syclik you're probably offline because it's saturday, but I'll be online all day monday and we can get this rolling, if you're available.
roualdes commentedon Feb 24, 2019
EDIT: This is a bit too crude to be helpful. Hopefully my next post is more helpful.
In the hopes of getting my head around all the details, here's my first thought for a bash script.
Some follow up thoughts.
prim,fwd,rev, andmix,prim,fwd,rev, andmixhave .hpp files two levels deep. For instance,corehas .hpp files one level belowfwd.What do you think?
roualdes commentedon Feb 25, 2019
Here's my next attempt to contribute something to this effort.
I'll try to be around tomorrow to join the team effort.
55 remaining items
rok-cesnovar commentedon Nov 30, 2019
I did follow the above discussion on and off but dont remember all the details so maybe this shares some of the ideas already discussed.
Below is for the /prim folder but the same goes for /fwd, /mix and /rev. We can leave /opencl out of this discussion for now, but that folder should also be revisited.
In each folder we have
{err, fun, functor, meta}and the same principles can be applied for all. Example given forerr.PR 1: make a top-level header
prim/err.hpp(For the meta subfolder this is already done) and replace all includes outside /prim/*/err/ with the top-level include. This will touch a lot of files but should make the next steps cleaner. Should also be straightforward to review, but lengthy. This PR should also include a check to prevent any subsequent PRs to break this work. This happened a lot for the meta.hpp before we added https://github.com/stan-dev/math/blob/develop/runChecks.py#L260PR 2: Flatten the tests for
prim/*/errinprim/err.PR 3: Flatten all the files to the folder with the most functions (probably prim/err/scal) and then move them to prim/err/ and fix the top-level header. I dont see another way then just copy pasting stuff in manually and go from there. This way would preserve the most git history for the files, I think. I am very much open to suggestions here.
PR 1 is going to touch the most files but should not cause much issues for other developers. PR 2 will probably also not be problematic. PR 3 is going to be the most problematic in terms of additional work for other developers when they will merge the changes. Outside of generalizing signatures there arent many long-term projects happening right now. There is the kernel generator but that is limited to /opencl. So this might be a great time to do this.
rok-cesnovar commentedon Nov 30, 2019
Starting with #1476
rok-cesnovar commentedon Dec 1, 2019
Ok, I have 3 PRs lined up that would flatten prim/meta:
#1476 flattens the tests for prim/meta
#1479 cleans up the tests for redundancy
#1480 does the flattening of stan/math/prim/*meta
I think this is the easiest way of doing it in terms of reviewing. We could also do meta flatten prim/rev/fwd/mix together but I feel that will be more difficult to review.
syclik commentedon Dec 3, 2019
rok-cesnovar commentedon Dec 16, 2019
Meta is now flattened and I think it went fairly well so if there are no objections I would proceed with flattening the /err folder (any suggestion by the reviewers are welcome off course).
The plan is to start by creating
{prim, rev, mix, fwd}/err.hppfiles and replace all includes of any/errheader outside theerrfolder with the include of the respective master err.hpp header file. This is the same as we did for/meta.After that we proceed with the same schedule of PRs as with the meta flatten (see this comment).
syclik commentedon Dec 16, 2019
bob-carpenter commentedon Dec 16, 2019
rok-cesnovar commentedon Jan 2, 2020
Once the tests pass we will have the meta, err and prob folders flattened. Thanks @mcol for all the thorough reviews of the recent PRs. I know they are painful to review. I also have the /functor flatten up on a branch. That one is really simple so it will be done in a single PR. It will require PRs on Stan/Cmdstan to fix include paths but those should be quick (see stan-dev/stan#2872).
So the first question is do we aim for having
scal/arr/matflattened entirely for the next release? Or should I hold off on flattening /fun after the release? If we should go through with it for the upcoming the second question is can we flatten /fun in the feature freeze period? I figure that would be the best time to do it as flattening /fun is going to cause a bunch of conflicts for developers trying to get their PRs through before the freeze. We could probably flatten fwd/fun and mix/fun without causing too much trouble for other open PRs, but prim/fun and rev/fun will be more problematic.My proposal would be to try and flatten fwd and mix before the feature freeze and then flatten prim and rev right after the freeze (11th Jan).
The other question is the order of merge in /fun. If a file has arr, mat and scal implementations what would be the preferred order. I would say either scal, arr, mat or mat, arr, scal to have ascending or descending dimensions. But am open to any other suggestions.
t4c1 commentedon Jan 2, 2020
I think scal should be first, as arr and mat often depend on scal implementation. Afaik arr and mat usually do not depend on each other so the order of these two should not matter.
bob-carpenter commentedon Jan 2, 2020