Passing pstream argument for higher-order functions

The prototype laplace_marginal_lpdf functions takes in two functions which: (i) return the log likelihood and (ii) return the covariance matrix. The parser parses higher-order function and gives them a pstream argument, which, if my understanding is correct, allows us to use print statements inside the function argument.

Two questions: (i) How is the position of the pstream argument determined? Ideally I want it before the optional tuning parameters. And (ii), if I’m passing two functions, would I need two pstream arguments, or is one sufficient? Currently, the parser generates one pstream argument at the end.

Here’s the function’s signature in C++:

  template <bool propto, typename T0, typename T1, typename T2,
            typename Tx, typename K, typename L>
  stan::return_type_t<T1, T2> laplace_marginal_lpdf
    (const Eigen::VectorXd& y,
     const L& L_f,
     const Eigen::Matrix<T2, Eigen::Dynamic, 1>& eta,
     const std::vector<int>& delta_int_L,
     const K& K_f,
     const Eigen::Matrix<T1, Eigen::Dynamic, 1>& phi,
     const Tx& x,
     const std::vector<double>& delta_K,
     const std::vector<int>& delta_int_K,
     const Eigen::Matrix<T0, Eigen::Dynamic, 1>& theta_0,
     std::ostream* msgs_L = nullptr,
     std::ostream* msgs_K = nullptr,
     double tolerance = 1e-6,
     long int max_num_steps = 100,
     int hessian_block_size = 0,
     int compute_W_root = 1)

Here are the signatures for the parser, in the file Stan_math_signature.ml

add_qualified  (* general implementation without tuning parameters *)
        ("laplace_marginal_lpdf"
        , ReturnType UReal
        , [ (DataOnly, UVector)
          ; (AutoDiffable
            , UFun
                ( [ (AutoDiffable, UVector); (AutoDiffable, UVector)
                  ; (DataOnly, UVector); (DataOnly, UArray UInt) ]
                , ReturnType UReal ) )
          ; (AutoDiffable, UVector); (DataOnly, UArray UInt)
          ; (AutoDiffable
            , UFun
                ( [ (AutoDiffable, UVector); (DataOnly, UMatrix)
                  ; (DataOnly, UArray UReal); (DataOnly, UArray UInt) ]
                , ReturnType UMatrix ) )
          ; (AutoDiffable, UVector); (DataOnly, UMatrix)
          ; (DataOnly, UArray UReal); (DataOnly, UArray UInt)
          ; (AutoDiffable, UVector) ] );

  add_qualified  (* general implementation with tuning parameters *)
    ("laplace_marginal_lpdf"
    , ReturnType UReal
    , [ (DataOnly, UVector)
      ; (AutoDiffable
        , UFun
            ( [ (AutoDiffable, UVector); (AutoDiffable, UVector)
              ; (DataOnly, UVector); (DataOnly, UArray UInt) ]
            , ReturnType UReal ) )
      ; (AutoDiffable, UVector); (DataOnly, UArray UInt)
      ; (AutoDiffable
        , UFun
            ( [ (AutoDiffable, UVector); (DataOnly, UMatrix)
              ; (DataOnly, UArray UReal); (DataOnly, UArray UInt) ]
            , ReturnType UMatrix ) )
      ; (AutoDiffable, UVector); (DataOnly, UMatrix)
      ; (DataOnly, UArray UReal); (DataOnly, UArray UInt)
      ; (AutoDiffable, UVector); (DataOnly, UReal); (DataOnly, UInt)
      ; (DataOnly, UInt); (DataOnly, UInt) ] );

And here is what the function gets translated to:

lp_accum__.add(
          laplace_marginal_lpdf<false>(y, L_f_functor__(), eta_dummy,
            delta_int, K_f_functor__(), phi, x_mat, delta, delta_int, theta0,
            tol, max_num_steps, hessian_block_size, compute_W_root,
            pstream__));

The same argument would be used for both so I would say one is enough.

The position of the pstream__ arg in code-gen is determined here: stanc3/Expression_gen.ml at master · stan-dev/stanc3 · GitHub

In algebra_solver its the 6th argument, in integrate_1d its the 7th argument. You can also put msgs :: msgs :: to generate pstream__, pstream__ but I would rather just change the C++ signature to only use one ostream*

1 Like