Skip to content

Add deserializer class for reading constraints easier#3013

Merged
rok-cesnovar merged 39 commits into
developfrom
feature/deserializer
Mar 11, 2021
Merged

Add deserializer class for reading constraints easier#3013
rok-cesnovar merged 39 commits into
developfrom
feature/deserializer

Conversation

@SteveBronder
Copy link
Copy Markdown
Collaborator

@SteveBronder SteveBronder commented Feb 26, 2021

Submission Checklist

  • Run unit tests: ./runTests.py src/test/unit
  • Run cpplint: make cpplint
  • Declare copyright holder and open-source license: see below

Summary

This does the FR for #3005 by making a deserializer class that handles constraints for the types and bounds used in the Stan compiler. It's a bit of a monster but handles pretty much all the parameter sizes we have in Stan. The idea here is that instead of the compiler generating code for paremeters like

      local_scalar_t__ sd_1 = in__.scalar();
      current_statement__ = 5;
      if (jacobian__) {
        current_statement__ = 5;
        sd_1 = stan::math::lb_constrain(sd_1, 0, lp__);
      } else {
        current_statement__ = 5;
        sd_1 = stan::math::lb_constrain(sd_1, 0);
      }

It can instead just use

      local_scalar_t__ sd_1 = in__.read_lb<local_scalar_t__, Jacobian__>(lp__, 0);

This works for eigen matrices and arrays containing arrays so something like the following is perfectly legal

      using big_vec = std::vector<std::vector<var_value<Eigen::Matrix<double, -1, -1>>>>;
      big_vec sd_1 = in__.read_lb<big_vec, Jacobian__>(0, lp__, 3, 3, 3, 3);

For general reading the function is read<RETURN_TYPE>(dims) where RETURN_TYPE is the type requested back and dims are the dimensions of the type. All of the constrain functions have the form

read_{constrain}<{return_type}, Jacobian>({constrain_args}, lp, {dims})

Where

  • {constrain} is the kind of the constraint like lb,ub,lub etc,
  • {return_type} is the requested return type,
  • Jacobian is whether to account for the Jacobian calculation
  • {constrain_args} is the arguments passed to the actual constrain function
  • lp is the the log prob that will be incremented if Jacobian is true
  • {dims} are the dimensions of the return type

This also adds read() methods for complex scalars, vectors, and matrices.

Intended Effect

This should simplify some of the compiler implementation for things like the new matrix type while also making things more performant by utilizing vectorized versions of the constrain functions when they are available.

How to Verify

About 2/3rds of this PR are testing, where we run all the standard tests from reader, then also check std::vector return types and var_value<Eigen> returns for all matrix tests. You can run the tests with

./runTests.py ./src/test/unit/io/deserializer_test.cpp \
 ./src/test/unit/io/deserializer_varmat_test.cpp \
 ./src/test/unit/io/deserializer_stdvector_test.cpp

Side Effects

There's two things I still need to add here, tests for the complex stuff and tests for matrices with the offset_and_multiplier constraints. I may need to make a Stan math PR for offset multiplier

Documentation

Copyright and Licensing

Please list the copyright holder for the work you are submitting (this will be you or your assignee, such as a university or company): Steve Bronder

By submitting this pull request, the copyright holder is agreeing to license the submitted work under the following licenses:

@SteveBronder SteveBronder changed the title Feature/deserializer Add deserializer class for reading constraints easier Feb 26, 2021
@stan-buildbot
Copy link
Copy Markdown
Contributor


Name Old Result New Result Ratio Performance change( 1 - new / old )
gp_pois_regr/gp_pois_regr.stan 3.45 3.38 1.02 2.17% faster
low_dim_corr_gauss/low_dim_corr_gauss.stan 0.02 0.02 1.01 1.0% faster
eight_schools/eight_schools.stan 0.11 0.12 0.98 -2.28% slower
gp_regr/gp_regr.stan 0.16 0.16 0.99 -1.49% slower
irt_2pl/irt_2pl.stan 5.16 5.27 0.98 -2.09% slower
performance.compilation 89.77 88.84 1.01 1.03% faster
low_dim_gauss_mix_collapse/low_dim_gauss_mix_collapse.stan 8.61 9.16 0.94 -6.5% slower
pkpd/one_comp_mm_elim_abs.stan 29.36 30.71 0.96 -4.58% slower
sir/sir.stan 129.35 131.76 0.98 -1.86% slower
gp_regr/gen_gp_data.stan 0.04 0.04 0.98 -1.64% slower
low_dim_gauss_mix/low_dim_gauss_mix.stan 2.99 2.98 1.0 0.35% faster
pkpd/sim_one_comp_mm_elim_abs.stan 0.39 0.37 1.04 3.83% faster
arK/arK.stan 1.78 1.78 1.0 0.09% faster
arma/arma.stan 0.75 0.74 1.01 0.51% faster
garch/garch.stan 0.57 0.56 1.01 0.96% faster
Mean result: 0.993683766006

Jenkins Console Log
Blue Ocean
Commit hash: 6c6aa3f


Machine information ProductName: Mac OS X ProductVersion: 10.11.6 BuildVersion: 15G22010

CPU:
Intel(R) Xeon(R) CPU E5-1680 v2 @ 3.00GHz

G++:
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 7.0.2 (clang-700.1.81)
Target: x86_64-apple-darwin15.6.0
Thread model: posix

Clang:
Apple LLVM version 7.0.2 (clang-700.1.81)
Target: x86_64-apple-darwin15.6.0
Thread model: posix

@stan-buildbot
Copy link
Copy Markdown
Contributor


Name Old Result New Result Ratio Performance change( 1 - new / old )
gp_pois_regr/gp_pois_regr.stan 3.45 3.51 0.98 -1.69% slower
low_dim_corr_gauss/low_dim_corr_gauss.stan 0.02 0.02 1.02 1.75% faster
eight_schools/eight_schools.stan 0.11 0.11 0.98 -1.53% slower
gp_regr/gp_regr.stan 0.15 0.16 0.95 -5.04% slower
irt_2pl/irt_2pl.stan 5.25 5.3 0.99 -0.96% slower
performance.compilation 91.77 89.05 1.03 2.97% faster
low_dim_gauss_mix_collapse/low_dim_gauss_mix_collapse.stan 8.62 8.67 0.99 -0.57% slower
pkpd/one_comp_mm_elim_abs.stan 29.95 30.14 0.99 -0.64% slower
sir/sir.stan 135.22 131.02 1.03 3.11% faster
gp_regr/gen_gp_data.stan 0.04 0.04 1.02 1.57% faster
low_dim_gauss_mix/low_dim_gauss_mix.stan 2.98 3.01 0.99 -1.18% slower
pkpd/sim_one_comp_mm_elim_abs.stan 0.38 0.39 0.96 -4.29% slower
arK/arK.stan 1.79 1.79 1.0 -0.08% slower
arma/arma.stan 0.74 0.73 1.02 1.96% faster
garch/garch.stan 0.57 0.54 1.05 4.73% faster
Mean result: 1.00073932831

Jenkins Console Log
Blue Ocean
Commit hash: 0c1057a


Machine information ProductName: Mac OS X ProductVersion: 10.11.6 BuildVersion: 15G22010

CPU:
Intel(R) Xeon(R) CPU E5-1680 v2 @ 3.00GHz

G++:
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 7.0.2 (clang-700.1.81)
Target: x86_64-apple-darwin15.6.0
Thread model: posix

Clang:
Apple LLVM version 7.0.2 (clang-700.1.81)
Target: x86_64-apple-darwin15.6.0
Thread model: posix

@SteveBronder
Copy link
Copy Markdown
Collaborator Author

@rok-cesnovar do you know what's up with the github check here? It's just giving back

Run echo "CXX=clang++-6.0" >> make/local
No matching tests found.
exit now (03/05/21 07:02:52 UTC)

Copy link
Copy Markdown
Member

@bbbales2 bbbales2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partial review to get comments on read-and-check-constraints versions of functions

template <typename S, typename K>
using conditional_var_val_t
= std::conditional_t<is_var_matrix<S>::value && is_var<T>::value,
return_var_matrix_t<K, S, K>, K>;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this exist somewhere else in the code already? @rok-cesnovar do you recognize it?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SteveBronder Oh yeah also this -- similar names but different function. We should rename this to just something kinda different so they don't get confused.

Comment thread src/stan/io/deserializer.hpp
Comment thread src/stan/io/deserializer.hpp Outdated
Comment thread src/stan/io/deserializer.hpp Outdated
Comment thread src/stan/io/deserializer.hpp Outdated
require_not_vt_complex<Ret>* = nullptr>
auto read(Size m) {
if (unlikely(m == 0)) {
return map_vector_t(nullptr, m);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the way the previous reader handed size zero things? This seems fine just curious.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this is how it was done before.

Kind of a side note to this, @bob-carpenter is there a math reason we can't have size zero simplex vectors but can have size zero vectors?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's that simplex vectors have the sum to 1 constraint, and a length 0 thing doesn't sum to one.

Comment thread src/stan/io/deserializer.hpp Outdated
Comment thread src/stan/io/deserializer.hpp Outdated
Comment thread src/stan/io/deserializer.hpp Outdated
Comment thread src/stan/io/deserializer.hpp Outdated
@stan-buildbot
Copy link
Copy Markdown
Contributor


Name Old Result New Result Ratio Performance change( 1 - new / old )
gp_pois_regr/gp_pois_regr.stan 3.45 3.51 0.98 -1.75% slower
low_dim_corr_gauss/low_dim_corr_gauss.stan 0.02 0.02 1.0 -0.24% slower
eight_schools/eight_schools.stan 0.11 0.11 0.99 -1.43% slower
gp_regr/gp_regr.stan 0.16 0.16 0.99 -0.56% slower
irt_2pl/irt_2pl.stan 5.18 5.2 1.0 -0.49% slower
performance.compilation 91.42 88.63 1.03 3.05% faster
low_dim_gauss_mix_collapse/low_dim_gauss_mix_collapse.stan 8.64 8.61 1.0 0.31% faster
pkpd/one_comp_mm_elim_abs.stan 29.73 29.7 1.0 0.1% faster
sir/sir.stan 130.64 132.5 0.99 -1.42% slower
gp_regr/gen_gp_data.stan 0.04 0.04 0.97 -3.0% slower
low_dim_gauss_mix/low_dim_gauss_mix.stan 2.99 2.98 1.0 0.48% faster
pkpd/sim_one_comp_mm_elim_abs.stan 0.38 0.37 1.0 0.12% faster
arK/arK.stan 1.78 1.8 0.99 -0.99% slower
arma/arma.stan 0.75 0.74 1.0 0.38% faster
garch/garch.stan 0.54 0.54 1.0 -0.16% slower
Mean result: 0.996448219861

Jenkins Console Log
Blue Ocean
Commit hash: 7359b50


Machine information ProductName: Mac OS X ProductVersion: 10.11.6 BuildVersion: 15G22010

CPU:
Intel(R) Xeon(R) CPU E5-1680 v2 @ 3.00GHz

G++:
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 7.0.2 (clang-700.1.81)
Target: x86_64-apple-darwin15.6.0
Thread model: posix

Clang:
Apple LLVM version 7.0.2 (clang-700.1.81)
Target: x86_64-apple-darwin15.6.0
Thread model: posix

@rok-cesnovar
Copy link
Copy Markdown
Member

@rok-cesnovar do you know what's up with the github check here? It's just giving back

yeah, this is unrelated. Happens on develop too. Will looki into it.

Copy link
Copy Markdown
Member

@bbbales2 bbbales2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's the rest of the review on the code -- after the code gets sorted out I'll do the tests.

Comment thread src/stan/io/deserializer.hpp Outdated
Comment thread src/stan/io/deserializer.hpp Outdated
Comment thread src/stan/io/deserializer.hpp Outdated
Comment thread src/stan/io/deserializer.hpp Outdated
Comment thread src/stan/io/deserializer.hpp Outdated
Comment thread src/stan/io/deserializer.hpp Outdated
@bbbales2
Copy link
Copy Markdown
Member

bbbales2 commented Mar 9, 2021

I think both. Docs will be good just to have them.

The script is testing that the compiling works so it should be more thorough and automatic -- similar to expressions testing.

@bbbales2
Copy link
Copy Markdown
Member

bbbales2 commented Mar 9, 2021

Script is mostly written -- so hopefully won't be long turnaround time on this. There's also a temporary list over here: stan-dev/cmdstan#980 (comment) so that any compiler-writing can start based on that.

@SteveBronder
Copy link
Copy Markdown
Collaborator Author

Pinging @rybern FYI this should get merged tmrw so the compiler impl can start using it

@stan-buildbot
Copy link
Copy Markdown
Contributor


Name Old Result New Result Ratio Performance change( 1 - new / old )
gp_pois_regr/gp_pois_regr.stan 3.41 3.48 0.98 -2.02% slower
low_dim_corr_gauss/low_dim_corr_gauss.stan 0.02 0.02 0.99 -1.34% slower
eight_schools/eight_schools.stan 0.12 0.11 1.02 2.4% faster
gp_regr/gp_regr.stan 0.16 0.16 0.99 -1.12% slower
irt_2pl/irt_2pl.stan 5.25 5.19 1.01 1.15% faster
performance.compilation 89.92 88.58 1.02 1.48% faster
low_dim_gauss_mix_collapse/low_dim_gauss_mix_collapse.stan 8.51 8.7 0.98 -2.18% slower
pkpd/one_comp_mm_elim_abs.stan 29.83 30.4 0.98 -1.92% slower
sir/sir.stan 128.24 131.99 0.97 -2.92% slower
gp_regr/gen_gp_data.stan 0.04 0.04 0.99 -0.84% slower
low_dim_gauss_mix/low_dim_gauss_mix.stan 2.89 3.0 0.96 -4.01% slower
pkpd/sim_one_comp_mm_elim_abs.stan 0.38 0.41 0.91 -9.65% slower
arK/arK.stan 1.77 1.75 1.01 1.29% faster
arma/arma.stan 0.61 0.59 1.03 2.73% faster
garch/garch.stan 0.58 0.57 1.02 2.02% faster
Mean result: 0.991030962463

Jenkins Console Log
Blue Ocean
Commit hash: 78e8beb


Machine information ProductName: Mac OS X ProductVersion: 10.11.6 BuildVersion: 15G22010

CPU:
Intel(R) Xeon(R) CPU E5-1680 v2 @ 3.00GHz

G++:
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 7.0.2 (clang-700.1.81)
Target: x86_64-apple-darwin15.6.0
Thread model: posix

Clang:
Apple LLVM version 7.0.2 (clang-700.1.81)
Target: x86_64-apple-darwin15.6.0
Thread model: posix

@SteveBronder
Copy link
Copy Markdown
Collaborator Author

@bbbales2 good to go?

@rok-cesnovar
Copy link
Copy Markdown
Member

Can you push a commit here to bump jenkins?

@bbbales2
Copy link
Copy Markdown
Member

@SteveBronder yeah I'm happy with what is here. You good with it? Jump pushed a commit to get Jenkins to go again.

@SteveBronder
Copy link
Copy Markdown
Collaborator Author

Yep!

@rybern
Copy link
Copy Markdown

rybern commented Mar 10, 2021

Congrats!!

Would a matching interface for the _free variables make sense? In stanc3, we generate the _constrain and _free calls in the same way, so this PR will let me simplify the _constrain calls, but with a new _free interface I can get rid of the old code altogether. (Same thing with checks to a lesser extent)

@SteveBronder
Copy link
Copy Markdown
Collaborator Author

Ty! Yes so transform_inits() I've been thinking about transform_inits() for the free functions and one good idea and one okay idea

So the var_context in the signature here is a bit of trouble because that class is an abstract base class (it only has undefined virtual functions with no other members). So the actual class going into that function is one of it's children like stan::io::array_context etc. who does have those functions defined. One rule with virtual methods is that they can't have templates so we can't do the exact same trick we did with deserializer.

  inline void transform_inits(
      const stan::io::var_context& context,
      Eigen::Matrix<double, Eigen::Dynamic, 1>& params_r,
      std::ostream* pstream = nullptr) const final {
//...
}

But in Stan, transform_inits() is only used in initialize.hpp and standalone_gqs.

Looking at both of those functions that use transform_inits() we know that they are trying to supply the model with the parameters names, an input array, the parameter dimesions, and an output array. But we know the model already knows the
dimensions and who cares about names!

So I think we could just use a serializer and deserializer!

What we could do is add a transform_inits() functions with the signature

transform_inits(Eigen::VectorXd& input_r, Eigen::VectorXd& output_r, std::ostream* pstream__ = nullptr) {
    stan::io::deserializer deserializer(input_r);
    // Made stuff calling the read<>() functions.
    Eigen::MatrixXd X = deserializer.read<Eigen::MatrixXd>(N, M);
    // Write to serializer
    stan::io::serializer serializer(output_r);
    serializer.serialize_free_lb(X, lb);

Thinking about it more could we just do the free's in deserializer and write

transform_inits(Eigen::VectorXd& input_r, Eigen::VectorXd& output_r, std::ostream* pstream__ = nullptr) {
    stan::io::deserializer deserializer(input_r);
    stan::io::serializer serializer(output_r);
    // Make stuff calling the read_free_lb<>() functions.
    serializer.serialize(deserializer.read_free_lb<Eigen::MatrixXd>(lb, N, M));

@bbbales2 do you have any opinions on whether the free functions should be in the serializer or deserializer? I think it would be nice to keep the serializer simple and just put all this in the serializer

I have to double check that this works, but if so does that work for @rybern? My only concern is that we have to worry about parameter order, though last time I looked at the contexts it just takes the vector you give it and uses that data to create sub arrays of those dimensions internally so I think this would be fine. Tagging @betanalpha as I know he has had opinions on this in the past

@bbbales2
Copy link
Copy Markdown
Member

I can get rid of the old code altogether

The upside here would be the cleanup right?

// Write to serializer
stan::io::serializer serializer(output_r);
serializer.serialize_free_lb(X, lb);

That looks right to me.

keep the serializer simple and just put all this in the serializer

Since we have the option, separate seems good.

The things missing on this are like the array forms of simplex_free, corr_matrix_free, etc. Maybe we shoulda just put all the array stuff in Math. None of that would be hard to write or test. The array forms for the functions we haven't written are straightforward (ub/lb/lub/offset_multiplier were the hard ones).

I'm guessing that it would probably take 2-3 days to get the Math components of this through. Same with the Stan side of things. So if we started now I'd guess we'd be done by this time next week.

If this cleans up the code quite a bit, then worth it.

The only thing that worries me is:

What we could do is add a transform_inits() functions with the signature

I'm hoping that "add" is actually a "replace"? Cause I assume we'd be deleting the old-style transform_inits.

Touching the var_contexts scares me a bit cause I don't know what downstream code exists that would need to be updated.

At worst we could just serialize to a local variable and then push those values onto the var_context. This part of the code shouldn't be performance sensitive.

@SteveBronder
Copy link
Copy Markdown
Collaborator Author

The things missing on this are like the array forms of simplex_free, corr_matrix_free, etc. Maybe we shoulda just put all the array stuff in Math. None of that would be hard to write or test. The array forms for the functions we haven't written are straightforward (ub/lb/lub/offset_multiplier were the hard ones).

Yeah we could either do these in the deserializer (since it's just calling simplex_free on each submatrix in the array) or do them in math. I'm fine with either way

I'm hoping that "add" is actually a "replace"? Cause I assume we'd be deleting the old-style transform_inits.

Yeah so I was thinking of a triage'd style thing where we

  1. Add the things for deserializer/serializer along with the virtual functions for the new transform_inits() in model_base/model_base_crtp (Since those virtual functions are not called yet it's fine if they are not defined in the model)
  2. Ryan writes the stuff to do the deserializer/serializer form of transform inits in the model class
  3. We change the stan code to use the new pattern in initialize and standalone generated quantities hpp files

Unless we want to do one big PR in Stan that does (1) and (3), then merge them at the same time as Ryan updates the stanc3 code

Touching the var_contexts scares me a bit cause I don't know what downstream code exists that would need to be updated.

At worst we could just serialize to a local variable and then push those values onto the var_context. This part of the code shouldn't be performance sensitive.

Yeah I agree, like looking around it seems like this is fine but we should probs reach out to folks we wrote this stuff to confirm what we are talking about here is going to work smoothly

@bbbales2
Copy link
Copy Markdown
Member

Hmm well yeah since you mention it all the array free stuff can just go here in a serializer class and we don't need to mess with Math. That's one pull instead of two.

Since you have a picture of serializer in your head, you want to go ahead and kick that off? I remain inclined to ditch all things integer here, fwiw.

@stan-buildbot
Copy link
Copy Markdown
Contributor


Name Old Result New Result Ratio Performance change( 1 - new / old )
gp_pois_regr/gp_pois_regr.stan 3.56 3.61 0.99 -1.27% slower
low_dim_corr_gauss/low_dim_corr_gauss.stan 0.02 0.02 1.0 -0.41% slower
eight_schools/eight_schools.stan 0.11 0.11 1.04 3.77% faster
gp_regr/gp_regr.stan 0.16 0.16 0.99 -1.1% slower
irt_2pl/irt_2pl.stan 5.17 5.29 0.98 -2.34% slower
performance.compilation 91.07 88.68 1.03 2.63% faster
low_dim_gauss_mix_collapse/low_dim_gauss_mix_collapse.stan 8.69 8.48 1.02 2.38% faster
pkpd/one_comp_mm_elim_abs.stan 29.71 29.92 0.99 -0.7% slower
sir/sir.stan 132.9 126.23 1.05 5.02% faster
gp_regr/gen_gp_data.stan 0.04 0.04 1.02 1.68% faster
low_dim_gauss_mix/low_dim_gauss_mix.stan 2.93 2.91 1.01 0.72% faster
pkpd/sim_one_comp_mm_elim_abs.stan 0.41 0.39 1.06 5.91% faster
arK/arK.stan 1.79 1.78 1.01 0.54% faster
arma/arma.stan 0.59 0.59 1.0 -0.22% slower
garch/garch.stan 0.56 0.56 1.0 -0.27% slower
Mean result: 1.01159165626

Jenkins Console Log
Blue Ocean
Commit hash: 0e2ecb8


Machine information ProductName: Mac OS X ProductVersion: 10.11.6 BuildVersion: 15G22010

CPU:
Intel(R) Xeon(R) CPU E5-1680 v2 @ 3.00GHz

G++:
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 7.0.2 (clang-700.1.81)
Target: x86_64-apple-darwin15.6.0
Thread model: posix

Clang:
Apple LLVM version 7.0.2 (clang-700.1.81)
Target: x86_64-apple-darwin15.6.0
Thread model: posix

@SteveBronder
Copy link
Copy Markdown
Collaborator Author

Yeah sure I'm trying to put together some docs for the compiler today and I'm going to give up on that in like 20 mins or so and I'll ge started on this

@SteveBronder
Copy link
Copy Markdown
Collaborator Author

It won't let me click the merge button but Ben feel free to merge. @rok-cesnovar do I need some privileges I don't have? Tagging @syclik as well

@rok-cesnovar
Copy link
Copy Markdown
Member

You have write privileges in this repo so this is definitely weird.

@rok-cesnovar rok-cesnovar merged commit ccb25c0 into develop Mar 11, 2021
@rok-cesnovar rok-cesnovar deleted the feature/deserializer branch March 11, 2021 08:38
@rybern
Copy link
Copy Markdown

rybern commented Mar 11, 2021

Sorry for the delay!

@SteveBronder I think what you described works great for my purposes (I probably haven't grokked the whole story though)

@bbbales2

The upside here would be the cleanup right?

I do think it'll simplify of the hairier bits of OCaml, because the logic would be easier and match the new constraints, and it'll generalize better for tuples. Also, maybe we won't have to deal with _free__ variables across unrelated parts of the compiler.

It might have a little performance gain too, right?

Just to make things concrete for my benefit, here's @nhuurre's example:

parameters {
  array[10] simplex[3] param;
}

For constraints we can now generate:

param = in__.read_simplex<T, jacobian__>(lp__, 10, 3);

For transform_inits, we're currently generating this big boy:

      std::vector<Eigen::Matrix<double, -1, 1>> param_free__;
      param_free__ = std::vector<Eigen::Matrix<double, -1, 1>>(10, Eigen::Matrix<double, -1, 1>(
        (3 - 1)));
      stan::math::fill(param_free__, std::numeric_limits<double>::quiet_NaN());
      
      current_statement__ = 1;
      for (int sym1__ = 1; sym1__ <= 10; ++sym1__) {
        current_statement__ = 1;
        assign(param_free__, cons_list(index_uni(sym1__), nil_index_list()),
          stan::math::simplex_free(param[(sym1__ - 1)]),
          "assigning variable param_free__");}
      for (int sym1__ = 1; sym1__ <= 10; ++sym1__) {
        for (int sym2__ = 1; sym2__ <= (3 - 1); ++sym2__) {
          vars__.emplace_back(param_free__[(sym1__ - 1)][(sym2__ - 1)]);}}

I'm imagining that it's possible to do something more direct along the lines of vars__.emplace_back<..>(.., param, 10, 3) and that that might be more efficient.

@bbbales2
Copy link
Copy Markdown
Member

This has the code to do something like:

std::vector<Eigen::VectorXd> param_free__ = deserializer.simplex_free(param);

I think Steve's working on a replacement for the vars__.emplace_back bit.

@rybern
Copy link
Copy Markdown

rybern commented Mar 12, 2021

Awesome!

@SteveBronder
Copy link
Copy Markdown
Collaborator Author

Yeah Ryan you may actually be able to write something like

stan::io::deserializer deserializer(input_vec__)
stan::io::serializer serializer(vars__);
serialize.write(deserializer.free_lb<std::vector<std::vector<Matrix>>>(lb, lp, {dims...})

Is it just those free functions called in transform inits or does something else happen?

@rybern
Copy link
Copy Markdown

rybern commented Mar 17, 2021

@SteveBronder sorry Steve I missed that you asked a question here

Is it just those free functions called in transform inits or does something else happen?

I think in transform_inits it's just doing the free stuff, @seantalts could you confirm?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants