First stanc3 release candidate!

Thanks to tons of hard work from @Matthijs, @enetsee, Ryan Bernstein, @Bob_Carpenter, Palmer Lao and @Adam_Haber we’ve got a really promising release candidate out for stanc3 that we think is replicating Stan 2 functionality in the new compiler (first milestone!). It looks like we’ve collectively written about 13,000 lines of OCaml code in the past 10 months, 3100 of which is in the analysis and optimization package, new with this compiler. The C++ compiler has about 20k lines for comparison.

The Stan project doesn’t have an amazing collection of test models yet (we’re working on it! Send us yours via PM, email, GitHub issue or PR) so please try it out and let us know if you see any issues! We’d love to accept Stan snippets that cause problems or models & data that need optimization.

Copying from the release page,

Here we have 80 models working from the stat_comp_benchmarks and example_models repos, as well as the “mother model” that @mitzimorris designed to stress test the compiler.

Killer features we currently don’t have hooked up that we hope to by the official 1.0 release:

  • The optimizer - currently it has a bunch of standard compiler passes and quite a few symbolic replacements that help with performance and numerical stability, but it’s not tested fully yet.
  • Model class additions
  • Faster compile times

To try out this compiler with CmdStan, simply download the binary for your operating system from the release binaries below and drop it into cmdstan/bin/stanc - everything else should just work from then on (assuming you don’t modify any of the compiler C++ files and cause CmdStan to regenerate bin/stanc from source).

Does anyone have suggestions for an easier packaging situation for CmdStan? We could theoretically package a tar.gz for each OS that deletes all the stan2 source code / makefiles and replaces it with a stanc3 binary - would that make it easier for folks to try out?

@ariddell, @ahartikainen - is there an easy way to make PyStan pip package that uses this release candidate? I know tensorflow has a ‘tf-nightly’ package, maybe we could do something similar? @bgoodri @jonah any ideas for making an RStan or CmdStanR version that people could use to do beta testing on this release candidate? Thanks all!

9 Likes

Any resource/doc to help developers understand the design & implementation?

The best doc we have right now for design and implementation is on the README. It hasn’t been updated with any of the optimization and analysis stuff yet - I assume @Matthijs, Ryan, and @enetsee will be on that once those parts have been refactored. If you go over that and find you have topics or questions that weren’t covered and wouldn’t mind writing them up I’d be happy to fill in details.

What are u looking for exactly? Do you want us to test the new stanc with some model and then compare the results to the vanilla stanc results? If so, what versions should I take and compare?

It’s super cool that stanc3 is maturing… it makes closures, lambdas and what if not make feel so much closer to becoming reality.

1 Like

Yeah, basically if you can try compiling + fitting with stanc3 on models you care about and double check that it gets the same fits and hopefully in about the same amount of time. The old compiler hasn’t changed much so I think it should be compatible with any 2.16+ ish version you have already. Thank you!

Agreed! I think the next step for those is probably just to make a design doc / RFC about what the syntax will look like so we can air the ideas a little before building them.

This is super cool, especially that it’s a drop-in replacement.

P.S. Thanks for citing me, but so as not to take any credit around the people who really built this, I’d like to point out that my contributions were mostly around helping understand what the old compiler did. I only wrote a bit of OCaml code for the generator and that’s all been refactored in order to produce readable output code with a formatter.

functions {
  matrix Foo() {
    return [ [1,2,3,4,5,6,7,8,9,10]
           , [1,2,3,4,5,6,7,8,9,10]
           , [1,2,3,4,5,6,7,8,9,10] ];
  }
}
model {
}

on cmdstan 2.20.0 release with OCAML v1.0.0-rc1 compiler downloaded binary produces:

andre@ubuntu:~/cmdstan-2.20.0$ make models/test1

--- Translating Stan model to C++ code ---
bin/stanc  --o=models/test1.hpp models/test1.stan

--- Compiling, linking C++ code ---
g++ -std=c++1y -pthread -Wno-sign-compare     -O3 -I src -I stan/src -I stan/lib/stan_math/ -I stan/lib/stan_math/lib/eigen_3.3.3 -I stan/lib/stan_math/lib/boost_1.69.0 -I stan/lib/stan_math/lib/sundials_4.1.0/include    -DBOOST_RESULT_OF_USE_TR1 -DBOOST_NO_DECLTYPE -DBOOST_DISABLE_ASSERTS -DBOOST_PHOENIX_NO_VARIADIC_EXPRESSION     -c  -x c++ -o models/test1.o models/test1.hpp
models/test1.hpp: In function ‘Eigen::Matrix<double, -1, -1> test1_model_namespace::Foo(std::ostream*)’:
models/test1.hpp:49:74: error: no matching function for call to ‘to_row_vector(<brace-enclosed initializer list>)’
                                                                  9, 10})});
                                                                          ^
In file included from stan/lib/stan_math/stan/math/prim/mat.hpp:237:0,
                 from stan/lib/stan_math/stan/math/rev/mat.hpp:12,
                 from stan/lib/stan_math/stan/math.hpp:4,
                 from stan/src/stan/model/model_header.hpp:4,
                 from models/test1.hpp:3:
stan/lib/stan_math/stan/math/prim/mat/fun/to_row_vector.hpp:15:44: note: candidate: template<class T, int R, int C> Eigen::Matrix<T, 1, -1> stan::math::to_row_vector(const Eigen::Matrix<T, R, C>&)
 inline Eigen::Matrix<T, 1, Eigen::Dynamic> to_row_vector(
                                            ^
stan/lib/stan_math/stan/math/prim/mat/fun/to_row_vector.hpp:15:44: note:   template argument deduction/substitution failed:
models/test1.hpp:49:74: note:   couldn't deduce template parameter ‘T’
                                                                  9, 10})});
                                                                          ^
In file included from stan/lib/stan_math/stan/math/prim/mat.hpp:237:0,
                 from stan/lib/stan_math/stan/math/rev/mat.hpp:12,
                 from stan/lib/stan_math/stan/math.hpp:4,
                 from stan/src/stan/model/model_header.hpp:4,
                 from models/test1.hpp:3:
stan/lib/stan_math/stan/math/prim/mat/fun/to_row_vector.hpp:23:44: note: candidate: template<class T> Eigen::Matrix<T, 1, -1> stan::math::to_row_vector(const std::vector<_RealType>&)
 inline Eigen::Matrix<T, 1, Eigen::Dynamic> to_row_vector(
                                            ^
stan/lib/stan_math/stan/math/prim/mat/fun/to_row_vector.hpp:23:44: note:   template argument deduction/substitution failed:
models/test1.hpp:49:74: note:   couldn't deduce template parameter ‘T’
                                                                  9, 10})});
                                                                          ^
In file included from stan/lib/stan_math/stan/math/prim/mat.hpp:237:0,
                 from stan/lib/stan_math/stan/math/rev/mat.hpp:12,
                 from stan/lib/stan_math/stan/math.hpp:4,
                 from stan/src/stan/model/model_header.hpp:4,
                 from models/test1.hpp:3:
stan/lib/stan_math/stan/math/prim/mat/fun/to_row_vector.hpp:29:49: note: candidate: Eigen::Matrix<double, 1, -1> stan::math::to_row_vector(const std::vector<int>&)
 inline Eigen::Matrix<double, 1, Eigen::Dynamic> to_row_vector(
                                                 ^
stan/lib/stan_math/stan/math/prim/mat/fun/to_row_vector.hpp:29:49: note:   no known conversion for argument 1 from ‘<brace-enclosed initializer list>’ to ‘const std::vector<int>&’
make/program:38: recipe for target 'models/test1' failed
make: *** [models/test1] Error 1

on

Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/5/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 5.4.0-6ubuntu1~16.04.11' --with-bugurl=file:///usr/share/doc/gcc-5/README.Bugs --enable-languages=c,ada,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-5 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-5-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-5-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-5-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.11)

test1.hpp (8.7 KB)

Model 2

functions {
  vector Foo() {
    return [1,2,3,4,5,6,7,8,9,10]';
  }  
  vector bar(real mu) {
    vector[10] l = mu * Foo();
    return l;
  }
}
model {
}

produces:

--- Compiling, linking C++ code ---
g++ -std=c++1y -pthread -Wno-sign-compare     -O3 -I src -I stan/src -I stan/lib/stan_math/ -I stan/lib/stan_math/lib/eigen_3.3.3 -I stan/lib/stan_math/lib/boost_1.69.0 -I stan/lib/stan_math/lib/sundials_4.1.0/include    -DBOOST_RESULT_OF_USE_TR1 -DBOOST_NO_DECLTYPE -DBOOST_DISABLE_ASSERTS -DBOOST_PHOENIX_NO_VARIADIC_EXPRESSION     -c  -x c++ -o models/test2.o models/test2.hpp
models/test2.hpp: In function ‘Eigen::Matrix<typename boost::math::tools::promote_args<T>::type, -1, 1> test2_model_namespace::bar(const T0__&, std::ostream*)’:
models/test2.hpp:77:50: error: expected primary-expression before ‘,’ token
     assign(l, nil_index_list(), multiply(mu, Foo(, pstream__)), "assigning variable l");
                                                  ^
make/program:38: recipe for target 'models/test2' failed
make: *** [models/test2] Error 1

Model 3

functions {
  vector bar(real mu) {
    vector[10] l = mu * [1,2,3,4,5,6,7,8,9,10]';
    return l[{1,2,3,4,5}];
  }
}
model {
}

Produces a linking problem:

--- Translating Stan model to C++ code ---
bin/stanc  --o=models/test3.hpp models/test3.stan

--- Compiling, linking C++ code ---
g++ -std=c++1y -pthread -Wno-sign-compare     -O3 -I src -I stan/src -I stan/lib/stan_math/ -I stan/lib/stan_math/lib/eigen_3.3.3 -I stan/lib/stan_math/lib/boost_1.69.0 -I stan/lib/stan_math/lib/sundials_4.1.0/include    -DBOOST_RESULT_OF_USE_TR1 -DBOOST_NO_DECLTYPE -DBOOST_DISABLE_ASSERTS -DBOOST_PHOENIX_NO_VARIADIC_EXPRESSION     -c  -x c++ -o models/test3.o models/test3.hpp
g++ -std=c++1y -pthread -Wno-sign-compare     -O3 -I src -I stan/src -I stan/lib/stan_math/ -I stan/lib/stan_math/lib/eigen_3.3.3 -I stan/lib/stan_math/lib/boost_1.69.0 -I stan/lib/stan_math/lib/sundials_4.1.0/include    -DBOOST_RESULT_OF_USE_TR1 -DBOOST_NO_DECLTYPE -DBOOST_DISABLE_ASSERTS -DBOOST_PHOENIX_NO_VARIADIC_EXPRESSION                   src/cmdstan/main.o stan/lib/stan_math/lib/sundials_4.1.0/lib/libsundials_nvecserial.a stan/lib/stan_math/lib/sundials_4.1.0/lib/libsundials_cvodes.a stan/lib/stan_math/lib/sundials_4.1.0/lib/libsundials_idas.a  models/test3.o -o models/test3
src/cmdstan/main.o: In function `cmdstan::command(int, char const**)':
main.cpp:(.text+0x612c): undefined reference to `new_model(stan::io::var_context&, unsigned int, std::ostream*)'
collect2: error: ld returned 1 exit status
make/program:38: recipe for target 'models/test3' failed
1 Like

Awesome, thanks! Will add this to the mother model :D

Hey all, we’re releasing the 2nd release candidate for stanc3! Thanks @andre.pfeuffer - your examples have been fixed and your test functions now live on in the mother model, which is tested automatically on every pull request to the new compiler to guard against regressions :)

We’re hoping people can download the new compiler and try it out against any models they care about, and any pathological examples that work in Stan 2 that they think should work in Stan 3. Trying it with CmdStan can be as simple as:

  1. git clone --recursive https://github.com/stan-dev/cmdstan; cd cmdstan
  2. make -j4 build
  3. Download the stanc3 binary for your OS to the right place:
  • Linux: curl -L https://github.com/stan-dev/stanc3/releases/download/v1.0.0-rc2/linux-stanc -o bin/stanc
  • Mac: curl -L https://github.com/stan-dev/stanc3/releases/download/v1.0.0-rc2/mac-stanc -o bin/stanc
  • Windows: curl -L https://github.com/stan-dev/stanc3/releases/download/v1.0.0-rc2/windows-stanc -o bin\stanc
  1. make <path/to/model.stan>

If you’d like to go the extra mile and help us check that it also gets the same results as your models, if you have them in the same folder as a .data.R file with the same name, you can use the performance-tests-cmdstan repo to compare compilers:

  1. git clone --recursive https://github.com/stan-dev/performance-tests-cmdstan; cd performance-tests-cmdstan
  2. Download the binary as above and remember its location.
  3. bash compare-compilers.sh "<path/to/models/dir> --num_samples=10" <path/to/stanc3/from/step/2>

Thanks all!

5 Likes