Commit f1f056fc authored by Bob Carpenter's avatar Bob Carpenter Committed by GitHub
Browse files

Merge pull request #547 from stan-dev/cleanup/546-operands-partials

operands_and_partials refactor
parents b5d61bf1 ae81a2e1
stan-petsc ChrisChiasson-feature/issue-123-complex-numbers-with-vars autoformat/build/test-test-format bugfix/1063-std-lgamma bugfix/1152-algebra_solver-lambdas bugfix/issue-1250-lgamma bugfix/issue-1270-add-check-for-meta-includes bugfix/issue-2708-map-rect-fail bugfix/issue-968-value-of-const-ref bugfix/issue-995-fix-bernoulli-glm-test bugfix/issues-935-933-integrate-1d build/config-device-id build/default-cc build/distr-tests build/errors build/errwarns build/precompiled-headers cholesky_gpu_funcs cmake code-cleanup/chain-final code-cleanup/issue-937-flatten develop feature/0565-remove-var_alloc_stack_ feature/0661-automated-style feature/1258-ad-test-core feature/adjoint-ode feature/automatic-autodiff-testing feature/concept-chainable-allocator feature/daniel-windows feature/eigen-aligned-malloc feature/faster-ad-tls feature/faster-ad-tls-v2 feature/faster-ad-tls-v3 feature/faster-ad-tls-v4 feature/faster-ad-tls-v4-windows feature/faster-ad-tls-v6 feature/github-doc-updates-aug-1-2018 feature/intel-tbb-lib feature/issue-1012-binorm-copula-cdf feature/issue-1022-integrate-1d-templating feature/issue-1115-newton_solver feature/issue-123-complex feature/issue-1257-diff_algebra_solver feature/issue-202-vectorize-all-binary feature/issue-38-multi_normal_sufficient feature/issue-45-vectorized-rngs feature/issue-45-vectorized_rngs_continuous feature/issue-45-vectorized_rngs_continuous2 feature/issue-565-vari-dealloc feature/issue-617-make feature/issue-755-laplace feature/issue-838-linseq feature/issue-876-adj-jac feature/issue-876-ordered-constraints feature/issue-888-quadratic_optimizer feature/issue-937-flatten-meta-again feature/issue-937-flatten-meta-the-third feature/issue-937-flatten-meta-third feature/issue-962-bivar-norm feature/issue-989-rev-mat-eig feature/lambertw feature/log_mix_arr feature/map_rect-cpp17 feature/map_rect-fail-windows feature/matrix_sqrt feature/openMP feature/operands_partials_less_copies feature/parallel_for_each feature/python-test-math-dependencies feature/refactor-nested feature/sparse-cholesky generalized_grad_tr_mat gpu_matrix_multiply gpu_performance_tests integrate_1d-improvements internal/no-assert issue-static-init-order kcl master mpi_errors new-static-poc new_complex_var null parallel-ad-tape-3 perf/operands_and_partials_deux perf/runtime_matrix_check_flags perf/static-stack perf/threaded-ad2 release/v2.17.1 release/v2.18.0 release/v2.18.1 release/v2.19.0 release/v2.19.1 release/v2.20.0 revert seantest/faster-ad-tls-v3 stancon/syclik status-quo-multiple-tu syclik/forward-mode v2.20.0 v2.19.1 v2.19.0 v2.18.1 v2.18.0 v2.17.1 v2.17.0 v2.16.0
No related merge requests found
Showing with 257 additions and 683 deletions
+257 -683
......@@ -46,4 +46,6 @@
#include <stan/math/fwd/mat/functor/gradient.hpp>
#include <stan/math/fwd/mat/functor/jacobian.hpp>
#include <stan/math/fwd/mat/meta/operands_and_partials.hpp>
#endif
#ifndef STAN_MATH_FWD_MAT_META_OPERANDS_AND_PARTIALS_HPP
#define STAN_MATH_FWD_MAT_META_OPERANDS_AND_PARTIALS_HPP
#include <stan/math/fwd/mat/fun/typedefs.hpp>
#include <stan/math/fwd/scal/meta/operands_and_partials.hpp>
#include <stan/math/prim/scal/meta/broadcast_array.hpp>
#include <vector>
namespace stan {
namespace math {
namespace internal {
// Vectorized Univariate
template <typename Dx>
class ops_partials_edge<Dx, std::vector<fvar<Dx> > > {
public:
typedef std::vector<fvar<Dx> > Op;
typedef Eigen::Matrix<Dx, -1, 1> partials_t;
partials_t partials_; // For univariate use-cases
broadcast_array<partials_t> partials_vec_; // For multivariate
explicit ops_partials_edge(const Op& ops)
: partials_(partials_t::Zero(ops.size())),
partials_vec_(partials_), operands_(ops) {}
private:
template<typename, typename, typename, typename, typename>
friend class stan::math::operands_and_partials;
const Op& operands_;
Dx dx() {
Dx derivative(0);
for (size_t i = 0; i < this->operands_.size(); ++i) {
derivative += this->partials_[i] * this->operands_[i].d_;
}
return derivative;
}
};
template <typename Dx, int R, int C>
class ops_partials_edge<Dx, Eigen::Matrix<fvar<Dx>, R, C> > {
public:
typedef Eigen::Matrix<Dx, R, C> partials_t;
typedef Eigen::Matrix<fvar<Dx>, R, C> Op;
partials_t partials_; // For univariate use-cases
broadcast_array<partials_t> partials_vec_; // For multivariate
explicit ops_partials_edge(const Op& ops)
: partials_(partials_t::Zero(ops.rows(), ops.cols())),
partials_vec_(partials_), operands_(ops) {}
private:
template<typename, typename, typename, typename, typename>
friend class stan::math::operands_and_partials;
const Op& operands_;
Dx dx() {
Dx derivative(0);
for (int i = 0; i < this->operands_.size(); ++i) {
derivative += this->partials_(i) * this->operands_(i).d_;
}
return derivative;
}
};
// Multivariate; vectors of eigen types
template <typename Dx, int R, int C>
class ops_partials_edge
<Dx, std::vector<Eigen::Matrix<fvar<Dx>, R, C> > > {
public:
typedef std::vector<Eigen::Matrix<fvar<Dx>, R, C> > Op;
typedef Eigen::Matrix<Dx, -1, -1> partial_t;
std::vector<partial_t> partials_vec_;
explicit ops_partials_edge(const Op& ops)
: partials_vec_(ops.size()), operands_(ops) {
for (size_t i = 0; i < ops.size(); ++i) {
partials_vec_[i] = partial_t::Zero(ops[i].rows(), ops[i].cols());
}
}
private:
template<typename, typename, typename, typename, typename>
friend class stan::math::operands_and_partials;
const Op& operands_;
Dx dx() {
Dx derivative(0);
for (size_t i = 0; i < this->operands_.size(); ++i) {
for (int j = 0; j < this->operands_[i].size(); ++j) {
derivative
+= this->partials_vec_[i](j) * this->operands_[i](j).d_;
}
}
return derivative;
}
};
} // namespace internal
} // namespace math
} // namespace stan
#endif
......@@ -5,7 +5,7 @@
#include <stan/math/fwd/scal/meta/ad_promotable.hpp>
#include <stan/math/fwd/scal/meta/is_fvar.hpp>
#include <stan/math/fwd/scal/meta/partials_type.hpp>
#include <stan/math/fwd/scal/meta/OperandsAndPartials.hpp>
#include <stan/math/fwd/scal/meta/operands_and_partials.hpp>
#include <stan/math/prim/scal.hpp>
......
#ifndef STAN_MATH_FWD_SCAL_META_OPERANDSANDPARTIALS_HPP
#define STAN_MATH_FWD_SCAL_META_OPERANDSANDPARTIALS_HPP
#include <stan/math/prim/scal/meta/is_constant_struct.hpp>
#include <stan/math/prim/scal/meta/length.hpp>
#include <stan/math/prim/scal/meta/OperandsAndPartials.hpp>
#include <stan/math/fwd/core.hpp>
namespace stan {
namespace math {
namespace {
template <typename T_derivative,
typename T,
typename T_partials,
bool is_vec = is_vector<T>::value,
bool is_const = is_constant_struct<T>::value>
struct increment_derivative {
inline T_derivative operator()(const T& x,
const T_partials& d_dx) {
return 0;
}
};
template <typename T_derivative,
typename T,
typename T_partials>
struct increment_derivative<T_derivative, T, T_partials, false, false> {
inline T_derivative operator()(const T& x,
const T_partials& d_dx) {
return d_dx[0] * x.d_;
}
};
template <typename T_derivative,
typename T,
typename T_partials>
struct increment_derivative<T_derivative, T, T_partials, true, false> {
inline T_derivative operator()(const T& x,
const T_partials& d_dx) {
T_derivative derivative(0);
for (size_t n = 0; n < length(x); n++)
derivative += d_dx[n] * x[n].d_;
return derivative;
}
};
template <typename T,
typename T1, typename D1, typename T2, typename D2,
typename T3, typename D3, typename T4, typename D4,
typename T5, typename D5, typename T6, typename D6>
fvar<T> partials_to_fvar(T& logp,
const T1& x1, D1& d_x1,
const T2& x2, D2& d_x2,
const T3& x3, D3& d_x3,
const T4& x4, D4& d_x4,
const T5& x5, D5& d_x5,
const T6& x6, D6& d_x6) {
T deriv = 0;
if (!is_constant_struct<T1>::value)
deriv += increment_derivative<T, T1, D1>()(x1, d_x1);
if (!is_constant_struct<T2>::value)
deriv += increment_derivative<T, T2, D2>()(x2, d_x2);
if (!is_constant_struct<T3>::value)
deriv += increment_derivative<T, T3, D3>()(x3, d_x3);
if (!is_constant_struct<T4>::value)
deriv += increment_derivative<T, T4, D4>()(x4, d_x4);
if (!is_constant_struct<T5>::value)
deriv += increment_derivative<T, T5, D5>()(x5, d_x5);
if (!is_constant_struct<T6>::value)
deriv += increment_derivative<T, T6, D6>()(x6, d_x6);
return fvar<T>(logp, deriv);
}
}
/**
* This class builds partial derivatives with respect to a set of
* operands. There are two reason for the generality of this
* class. The first is to handle vector and scalar arguments
* without needing to write additional code. The second is to use
* this class for writing probability distributions that handle
* primitives, reverse mode, and forward mode variables
* seamlessly.
*
* This is the partial template specialization for when the return
* type is fvar<T>.
*
* @tparam T1 First set of operands.
* @tparam T2 Second set of operands.
* @tparam T3 Third set of operands.
* @tparam T4 Fourth set of operands.
* @tparam T5 Fifth set of operands.
* @tparam T6 Sixth set of operands.
* @tparam T_return_type Return type of the expression. This defaults
* to a template metaprogram that calculates the scalar promotion of
* T1 -- T6.
*/
template<typename T1, typename T2, typename T3,
typename T4, typename T5, typename T6,
typename T_partials_return>
struct OperandsAndPartials<T1, T2, T3, T4, T5, T6,
fvar<T_partials_return> > {
typedef fvar<T_partials_return> T_return_type;
const T1& x1_;
const T2& x2_;
const T3& x3_;
const T4& x4_;
const T5& x5_;
const T6& x6_;
size_t n_partials;
T_partials_return* all_partials;
VectorView<T_partials_return,
is_vector<T1>::value,
is_constant_struct<T1>::value> d_x1;
VectorView<T_partials_return,
is_vector<T2>::value,
is_constant_struct<T2>::value> d_x2;
VectorView<T_partials_return,
is_vector<T3>::value,
is_constant_struct<T3>::value> d_x3;
VectorView<T_partials_return,
is_vector<T4>::value,
is_constant_struct<T4>::value> d_x4;
VectorView<T_partials_return,
is_vector<T5>::value,
is_constant_struct<T5>::value> d_x5;
VectorView<T_partials_return,
is_vector<T6>::value,
is_constant_struct<T6>::value> d_x6;
OperandsAndPartials(const T1& x1 = 0, const T2& x2 = 0, const T3& x3 = 0,
const T4& x4 = 0, const T5& x5 = 0, const T6& x6 = 0)
: x1_(x1), x2_(x2), x3_(x3), x4_(x4), x5_(x5), x6_(x6),
n_partials(!is_constant_struct<T1>::value * length(x1) +
!is_constant_struct<T2>::value * length(x2) +
!is_constant_struct<T3>::value * length(x3) +
!is_constant_struct<T4>::value * length(x4) +
!is_constant_struct<T5>::value * length(x5) +
!is_constant_struct<T6>::value * length(x6)),
all_partials(new T_partials_return[n_partials]),
d_x1(all_partials),
d_x2(all_partials
+ (!is_constant_struct<T1>::value) * length(x1)),
d_x3(all_partials
+ (!is_constant_struct<T1>::value) * length(x1)
+ (!is_constant_struct<T2>::value) * length(x2)),
d_x4(all_partials
+ (!is_constant_struct<T1>::value) * length(x1)
+ (!is_constant_struct<T2>::value) * length(x2)
+ (!is_constant_struct<T3>::value) * length(x3)),
d_x5(all_partials
+ (!is_constant_struct<T1>::value) * length(x1)
+ (!is_constant_struct<T2>::value) * length(x2)
+ (!is_constant_struct<T3>::value) * length(x3)
+ (!is_constant_struct<T4>::value) * length(x4)),
d_x6(all_partials
+ (!is_constant_struct<T1>::value) * length(x1)
+ (!is_constant_struct<T2>::value) * length(x2)
+ (!is_constant_struct<T3>::value) * length(x3)
+ (!is_constant_struct<T4>::value) * length(x4)
+ (!is_constant_struct<T5>::value) * length(x5)) {
std::fill(all_partials, all_partials + n_partials, 0);
}
T_return_type
value(T_partials_return value) {
return partials_to_fvar(value,
x1_, d_x1, x2_, d_x2,
x3_, d_x3, x4_, d_x4,
x5_, d_x4, x6_, d_x5);
}
~OperandsAndPartials() {
delete[] all_partials;
}
};
}
}
#endif
#ifndef STAN_MATH_FWD_SCAL_META_OPERANDS_AND_PARTIALS_HPP
#define STAN_MATH_FWD_SCAL_META_OPERANDS_AND_PARTIALS_HPP
#include <stan/math/prim/scal/meta/broadcast_array.hpp>
#include <stan/math/prim/scal/meta/operands_and_partials.hpp>
#include <stan/math/fwd/core/fvar.hpp>
namespace stan {
namespace math {
namespace internal {
template <typename Dx>
class ops_partials_edge<Dx, fvar<Dx> > {
public:
typedef fvar<Dx> Op;
Dx partial_;
broadcast_array<Dx> partials_;
explicit ops_partials_edge(const Op& op)
: partial_(0), partials_(partial_), operand_(op) {}
private:
template<typename, typename, typename, typename, typename>
friend class stan::math::operands_and_partials;
const Op& operand_;
Dx dx() {
return this->partials_[0] * this->operand_.d_;
}
};
} // namespace internal
/**
* This class builds partial derivatives with respect to a set of
* operands. There are two reason for the generality of this
* class. The first is to handle vector and scalar arguments
* without needing to write additional code. The second is to use
* this class for writing probability distributions that handle
* primitives, reverse mode, and forward mode variables
* seamlessly.
*
* Conceptually, this class is used when we want to manually calculate
* the derivative of a function and store this manual result on the
* autodiff stack in a sort of "compressed" form. Think of it like an
* easy-to-use interface to rev/core/precomputed_gradients.
*
* This class now supports multivariate use-cases as well by
* exposing edge#_.partials_vec
*
* This is the specialization for when the return type is fvar,
* which should be for forward mode and all higher-order cases.
*
* @tparam Op1 type of the first operand
* @tparam Op2 type of the second operand
* @tparam Op3 type of the third operand
* @tparam Op4 type of the fourth operand
* @tparam T_return_type return type of the expression. This defaults
* to a template metaprogram that calculates the scalar promotion of
* Op1 -- Op4
*/
template <typename Op1, typename Op2, typename Op3, typename Op4,
typename Dx>
class operands_and_partials<Op1, Op2, Op3, Op4, fvar<Dx> > {
public:
internal::ops_partials_edge<Dx, Op1> edge1_;
internal::ops_partials_edge<Dx, Op2> edge2_;
internal::ops_partials_edge<Dx, Op3> edge3_;
internal::ops_partials_edge<Dx, Op4> edge4_;
typedef fvar<Dx> T_return_type;
explicit operands_and_partials(const Op1& o1)
: edge1_(o1) { }
operands_and_partials(const Op1& o1, const Op2& o2)
: edge1_(o1), edge2_(o2) { }
operands_and_partials(const Op1& o1, const Op2& o2, const Op3& o3)
: edge1_(o1), edge2_(o2), edge3_(o3) { }
operands_and_partials(const Op1& o1, const Op2& o2, const Op3& o3,
const Op4& o4)
: edge1_(o1), edge2_(o2), edge3_(o3), edge4_(o4) { }
/**
* Build the node to be stored on the autodiff graph.
* This should contain both the value and the tangent.
*
* For scalars, we don't calculate any tangents.
* For reverse mode, we end up returning a type of var that will calculate
* the appropriate adjoint using the stored operands and partials.
* Forward mode just calculates the tangent on the spot and returns it in
* a vanilla fvar.
*
* @param value the return value of the function we are compressing
* @return the value with its derivative
*/
T_return_type build(Dx value) {
Dx deriv = edge1_.dx() + edge2_.dx() + edge3_.dx() + edge4_.dx();
return T_return_type(value, deriv);
}
};
}
}
#endif
......@@ -8,12 +8,12 @@
#include <stan/math/fwd/core.hpp>
#include <stan/math/fwd/scal/meta/is_fvar.hpp>
#include <stan/math/fwd/scal/meta/partials_type.hpp>
#include <stan/math/fwd/scal/meta/OperandsAndPartials.hpp>
#include <stan/math/fwd/scal/meta/operands_and_partials.hpp>
#include <stan/math/rev/core.hpp>
#include <stan/math/rev/scal/meta/is_var.hpp>
#include <stan/math/rev/scal/meta/partials_type.hpp>
#include <stan/math/rev/scal/meta/OperandsAndPartials.hpp>
#include <stan/math/rev/scal/meta/operands_and_partials.hpp>
#include <stan/math/prim/scal.hpp>
#include <stan/math/fwd/scal.hpp>
......
#ifndef STAN_MATH_PRIM_ARR_HPP
#define STAN_MATH_PRIM_ARR_HPP
#include <stan/math/prim/arr/meta/container_view.hpp>
#include <stan/math/prim/arr/meta/get.hpp>
#include <stan/math/prim/arr/meta/index_type.hpp>
#include <stan/math/prim/arr/meta/is_constant_struct.hpp>
#include <stan/math/prim/arr/meta/is_vector.hpp>
#include <stan/math/prim/arr/meta/length.hpp>
#include <stan/math/prim/arr/meta/scalar_type.hpp>
#include <stan/math/prim/arr/meta/value_type.hpp>
#include <stan/math/prim/arr/meta/VectorBuilderHelper.hpp>
#include <stan/math/prim/arr/meta/VectorView.hpp>
#include <stan/math/prim/arr/err/check_matching_sizes.hpp>
#include <stan/math/prim/arr/err/check_nonzero_size.hpp>
......
#ifndef STAN_MATH_ARR_SCAL_META_VECTORVIEW_HPP
#define STAN_MATH_ARR_SCAL_META_VECTORVIEW_HPP
#include <stan/math/prim/scal/meta/VectorView.hpp>
#include <vector>
namespace stan {
template <typename T>
class VectorView<std::vector<T>, true, false> {
public:
typedef typename scalar_type<T>::type scalar_t;
template <typename X>
explicit VectorView(X& x) : x_(&x[0]) { }
scalar_t& operator[](int i) {
return x_[i];
}
private:
scalar_t* x_;
};
template <typename T>
class VectorView<const std::vector<T>, true, false> {
public:
typedef typename boost::add_const<typename scalar_type<T>::type>::type
scalar_t;
template <typename X>
explicit VectorView(X& x) : x_(&x[0]) { }
scalar_t& operator[](int i) const {
return x_[i];
}
private:
scalar_t* x_;
};
}
#endif
#ifndef STAN_MATH_PRIM_ARR_META_CONTAINER_VIEW_HPP
#define STAN_MATH_PRIM_ARR_META_CONTAINER_VIEW_HPP
#include <stan/math/prim/scal/meta/container_view.hpp>
#include <vector>
namespace stan {
namespace math {
/**
* Template specialization for scalar view of
* array y with scalar type T2 with proper indexing
* inferred from input vector x of scalar type T1
*
* @tparam T1 scalar type of input vector
* @tparam T2 scalar type returned by view.
*/
template <typename T1, typename T2>
class container_view<std::vector<T1>, T2> {
public:
/**
* Constructor
*
* @param x input vector
* @param y underlying array
*/
container_view(const std::vector<T1>& x, T2* y)
: y_(y) { }
/**
* operator[](int i) returns reference to scalar
* view indexed at i
*
* @param i index of scalar element
*/
T2& operator[](int i) {
return y_[i];
}
private:
T2* y_;
};
}
}
#endif
#ifndef STAN_MATH_PRIM_ARR_META_SCALAR_TYPE_HPP
#define STAN_MATH_PRIM_ARR_META_SCALAR_TYPE_HPP
#include <stan/math/prim/scal/meta/scalar_type.hpp>
#include <vector>
namespace stan {
template <typename T>
struct scalar_type<std::vector<T> > {
typedef typename scalar_type<T>::type type;
};
template <typename T>
struct scalar_type<const std::vector<T> > {
typedef typename scalar_type<T>::type type;
};
template <typename T>
struct scalar_type<std::vector<T>& > {
typedef typename scalar_type<T>::type type;
};
template <typename T>
struct scalar_type<const std::vector<T>& > {
typedef typename scalar_type<T>::type type;
};
}
#endif
......@@ -19,7 +19,7 @@ namespace stan {
* Type of value stored in a standard vector with type
* <code>T</code> entries.
*/
typedef typename std::vector<T>::value_type type;
typedef T type;
};
}
......
......@@ -6,7 +6,6 @@
#include <stan/math/prim/arr/meta/is_vector.hpp>
#include <stan/math/prim/arr/meta/length.hpp>
#include <stan/math/prim/mat/meta/container_view.hpp>
#include <stan/math/prim/mat/meta/get.hpp>
#include <stan/math/prim/mat/meta/index_type.hpp>
#include <stan/math/prim/mat/meta/is_constant_struct.hpp>
......@@ -18,7 +17,6 @@
#include <stan/math/prim/mat/meta/scalar_type.hpp>
#include <stan/math/prim/mat/meta/value_type.hpp>
#include <stan/math/prim/mat/meta/vector_seq_view.hpp>
#include <stan/math/prim/mat/meta/VectorView.hpp>
#include <stan/math/prim/mat/err/check_cholesky_factor.hpp>
#include <stan/math/prim/mat/err/check_cholesky_factor_corr.hpp>
......
#ifndef STAN_MATH_MAT_SCAL_META_VECTORVIEW_HPP
#define STAN_MATH_MAT_SCAL_META_VECTORVIEW_HPP
#include <stan/math/prim/mat/fun/Eigen.hpp>
#include <stan/math/prim/mat/meta/scalar_type.hpp>
#include <stan/math/prim/scal/meta/VectorView.hpp>
#include <boost/type_traits.hpp>
namespace stan {
template <typename T, int R, int C>
class VectorView<Eigen::Matrix<T, R, C>, true, false> {
public:
typedef typename scalar_type<T>::type scalar_t;
template <typename X>
explicit VectorView(X& x) : x_(x.data()) { }
scalar_t& operator[](int i) {
return x_[i];
}
private:
scalar_t* x_;
};
template <typename T, int R, int C>
class VectorView<const Eigen::Matrix<T, R, C>, true, false> {
public:
typedef typename boost::add_const<typename scalar_type<T>::type>::type
scalar_t;
template <typename X>
explicit VectorView(X& x) : x_(x.data()) { }
scalar_t& operator[](int i) const {
return x_[i];
}
private:
scalar_t* x_;
};
}
#endif
#ifndef STAN_MATH_PRIM_MAT_META_CONTAINER_VIEW_HPP
#define STAN_MATH_PRIM_MAT_META_CONTAINER_VIEW_HPP
#include <stan/math/prim/scal/meta/container_view.hpp>
#include <stan/math/prim/mat/fun/Eigen.hpp>
#include <vector>
namespace stan {
namespace math {
/**
* Template specialization for Eigen::Map view of
* array with scalar type T2 with size inferred from
* input Eigen::Matrix
*
* @tparam T1 scalar type of input matrix
* @tparam T2 scalar type of view.
* @tparam R rows of input matrix and view
* @tparam C columns of input matrix and view
*/
template <typename T1, typename T2, int R, int C>
class container_view<Eigen::Matrix<T1, R, C>, Eigen::Matrix<T2, R, C> > {
public:
/**
* Initialize Map dimensions with input matrix
* dimensions
*
* @param x input matrix
* @param y underlying array
*/
container_view(const Eigen::Matrix<T1, R, C>& x, T2* y)
: y_(y, x.rows(), x.cols()) { }
/**
* operator[](int i) returns Eigen::Map y
*
* @param i index
*/
Eigen::Map<Eigen::Matrix<T2, R, C> >& operator[](int i) {
return y_;
}
private:
Eigen::Map<Eigen::Matrix<T2, R, C> > y_;
};
/**
* Template specialization for scalar view of
* array y with scalar type T2
*
* @tparam T1 scalar type of input matrix
* @tparam T2 scalar type returned by view.
* @tparam R rows of input matrix and view
* @tparam C columns of input matrix and view
*/
template <typename T1, typename T2, int R, int C>
class container_view<Eigen::Matrix<T1, R, C>, T2> {
public:
/**
* Constructor
*
* @param x input matrix
* @param y underlying array
*/
container_view(const Eigen::Matrix<T1, R, C>& x, T2* y)
: y_(y) { }
/**
* operator[](int i) returns reference to scalar
* of type T2 at appropriate index i in array y
*/
T2& operator[](int i) {
return y_[i];
}
private:
T2* y_;
};
/**
* Template specialization for matrix view of
* array y with scalar type T2 with shape
* equal to x
*
* @tparam T1 scalar type of input vector of matrices
* @tparam T2 scalar type of matrix view
* @tparam R rows of input matrix and view
* @tparam C columns of input matrix and view
*/
template <typename T1, typename T2, int R, int C>
class container_view<std::vector<Eigen::Matrix<T1, R, C> >,
Eigen::Matrix<T2, R, C> > {
public:
/**
* Constructor assumes all matrix elements in
* std::vector are of same dimension
*
* Initializes y_view as 1x1 matrix because no
* nullary constructor for Eigen::Map
*
* @param x input matrix
* @param y underlying array
*/
container_view(const std::vector<Eigen::Matrix<T1, R, C> >& x, T2* y)
: y_view(y, 1, 1), y_(y) {
if (x.size() > 0) {
rows = x[0].rows();
cols = x[0].cols();
} else {
rows = 0;
cols = 0;
}
}
/**
* operator[](int i) returns matrix view
* of scalartype T2 at appropriate index i in array y
*/
Eigen::Map<Eigen::Matrix<T2, R, C> >& operator[](int i) {
int offset = i * rows * cols;
new (&y_view) Eigen::Map<Eigen::Matrix<T2, R, C> >
(y_ + offset, rows, cols);
return y_view;
}
private:
Eigen::Map<Eigen::Matrix<T2, R, C> > y_view;
T2* y_;
int rows;
int cols;
};
}
}
#endif
......@@ -2,16 +2,33 @@
#define STAN_MATH_PRIM_MAT_META_SCALAR_TYPE_HPP
#include <stan/math/prim/mat/fun/Eigen.hpp>
#include <stan/math/prim/mat/meta/is_vector.hpp>
#include <stan/math/prim/mat/meta/value_type.hpp>
#include <stan/math/prim/scal/meta/scalar_type.hpp>
#include <stan/math/prim/arr/meta/scalar_type.hpp>
namespace stan {
template <typename T>
struct scalar_type<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> > {
template <typename T, int R, int C>
struct scalar_type<Eigen::Matrix<T, R, C> > {
typedef typename scalar_type<T>::type type;
};
template <typename T, int R, int C>
struct scalar_type<const Eigen::Matrix<T, R, C> > {
typedef typename scalar_type<T>::type type;
};
template <typename T, int R, int C>
struct scalar_type<Eigen::Matrix<T, R, C>& > {
typedef typename scalar_type<T>::type type;
};
template <typename T, int R, int C>
struct scalar_type<const Eigen::Matrix<T, R, C>& > {
typedef typename scalar_type<T>::type type;
};
template <typename T>
struct scalar_type<Eigen::Block<T> > {
typedef typename scalar_type<T>::type type;
};
}
#endif
#ifndef STAN_MATH_PRIM_MAT_META_VALUE_TYPE_HPP
#define STAN_MATH_PRIM_MAT_META_VALUE_TYPE_HPP
#include <stan/math/prim/scal/meta/value_type.hpp>
#include <stan/math/prim/arr/meta/value_type.hpp>
#include <Eigen/Core>
namespace stan {
......@@ -17,7 +17,7 @@ namespace stan {
*/
template <typename T, int R, int C>
struct value_type<Eigen::Matrix<T, R, C> > {
typedef typename Eigen::Matrix<T, R, C>::Scalar type;
typedef T type;
};
}
......
......@@ -5,7 +5,6 @@
#include <stan/math/prim/scal/meta/ad_promotable.hpp>
#include <stan/math/prim/scal/meta/child_type.hpp>
#include <stan/math/prim/scal/meta/container_view.hpp>
#include <stan/math/prim/scal/meta/contains_fvar.hpp>
#include <stan/math/prim/scal/meta/contains_nonconstant_struct.hpp>
#include <stan/math/prim/scal/meta/contains_vector.hpp>
......@@ -25,7 +24,7 @@
#include <stan/math/prim/scal/meta/likely.hpp>
#include <stan/math/prim/scal/meta/max_size.hpp>
#include <stan/math/prim/scal/meta/max_size_mvt.hpp>
#include <stan/math/prim/scal/meta/OperandsAndPartials.hpp>
#include <stan/math/prim/scal/meta/operands_and_partials.hpp>
#include <stan/math/prim/scal/meta/partials_return_type.hpp>
#include <stan/math/prim/scal/meta/partials_type.hpp>
#include <stan/math/prim/scal/meta/return_type.hpp>
......@@ -35,7 +34,6 @@
#include <stan/math/prim/scal/meta/size_of.hpp>
#include <stan/math/prim/scal/meta/value_type.hpp>
#include <stan/math/prim/scal/meta/VectorBuilder.hpp>
#include <stan/math/prim/scal/meta/VectorView.hpp>
#include <stan/math/prim/scal/err/check_2F1_converges.hpp>
#include <stan/math/prim/scal/err/check_3F2_converges.hpp>
......
......@@ -11,7 +11,7 @@
namespace stan {
namespace math {
namespace detail {
namespace internal {
// implemented using structs because there is no partial specialization
// for templated functions
......@@ -93,7 +93,7 @@ namespace stan {
const T_y& y,
const T_low& low,
const T_high& high) {
detail::bounded<T_y, T_low, T_high, is_vector_like<T_y>::value>
internal::bounded<T_y, T_low, T_high, is_vector_like<T_y>::value>
::check(function, name, y, low, high);
}
......
#ifndef STAN_MATH_PRIM_SCAL_META_OPERANDSANDPARTIALS_HPP
#define STAN_MATH_PRIM_SCAL_META_OPERANDSANDPARTIALS_HPP
#include <stan/math/prim/scal/meta/return_type.hpp>
#include <stan/math/prim/scal/meta/VectorView.hpp>
namespace stan {
namespace math {
/**
* This class builds partial derivatives with respect to a set of
* operands. There are two reason for the generality of this
* class. The first is to handle vector and scalar arguments
* without needing to write additional code. The second is to use
* this class for writing probability distributions that handle
* primitives, reverse mode, and forward mode variables
* seamlessly.
*
* The default template class handles the case where the arguments
* are primitive. There are template specializations for reverse
* mode and forward mode.
*
* @tparam T1 First set of operands.
* @tparam T2 Second set of operands.
* @tparam T3 Third set of operands.
* @tparam T4 Fourth set of operands.
* @tparam T5 Fifth set of operands.
* @tparam T6 Sixth set of operands.
* @tparam T_return_type Return type of the expression. This defaults
* to a template metaprogram that calculates the scalar promotion of
* T1 -- T6.
*/
template<typename T1 = double, typename T2 = double, typename T3 = double,
typename T4 = double, typename T5 = double, typename T6 = double,
typename T_return_type
= typename stan::return_type<T1, T2, T3, T4, T5, T6>::type>
struct OperandsAndPartials {
VectorView<T_return_type, false, true> d_x1;
VectorView<T_return_type, false, true> d_x2;
VectorView<T_return_type, false, true> d_x3;
VectorView<T_return_type, false, true> d_x4;
VectorView<T_return_type, false, true> d_x5;
VectorView<T_return_type, false, true> d_x6;
/**
* Constructor.
*
* @param x1 first set of operands
* @param x2 second set of operands
* @param x3 third set of operands
* @param x4 fourth set of operands
* @param x5 fifth set of operands
* @param x6 sixth set of operands
*/
OperandsAndPartials(const T1& x1 = 0, const T2& x2 = 0,
const T3& x3 = 0, const T4& x4 = 0,
const T5& x5 = 0, const T6& x6 = 0) { }
/**
* Returns a T_return_type with the value specified with
* the partial derivatves.
*
* @param[in] value Value of the variable
* @returns a variable with the appropriate value
*/
T_return_type
value(double value) {
return value;
}
};
}
}
#endif
#ifndef STAN_MATH_PRIM_SCAL_META_VECTORVIEW_HPP
#define STAN_MATH_PRIM_SCAL_META_VECTORVIEW_HPP
#include <stan/math/prim/scal/meta/scalar_type.hpp>
#include <stan/math/prim/scal/meta/is_vector_like.hpp>
#include <boost/type_traits.hpp>
#include <stdexcept>
namespace stan {
/**
* VectorView is a template expression that is constructed with a
* container or scalar, which it then allows to be used as an array
* using <code>operator[]</code>.
*
* For a scalar value, any index returns the reference or pointer
* used to construct the view.
*
* For a container, the index returns a reference to the position in
* the underlying container used to construct the view. WARNING:
* There is no bounds checking for container indices and they will
* segfault if accessed beyond their boundaries.
*
* The first use is to read arguments to prob functions as vectors,
* even if scalars, so they can be read by common code (and scalars
* automatically broadcast up to behave like vectors) : VectorView
* of immutable const array of double* (no allocation).
*
* The second use is to build up derivatives into common storage :
* VectorView of mutable shared array (no allocation because
* allocated on auto-diff arena memory).
*
* Because it deals with references to its inputs, it is up to the
* client of VectorView to ensure that the container being wrapped
* is not modified while the VectorView is in use in such a way as
* to disrupt the indexing. Similarly, because it deals with
* references, it cannot be constructed with a literal or expression.
*
* @tparam T Type of scalar or container being wrapped.
* @tparam is_array True if underlying type T can be indexed with
* operator[].
* @tparam throw_if_accessed True if the behavior is to throw an
* exception whenever <code>operator[]</code> is called.
*/
template <typename T,
bool is_array = stan::is_vector_like<T>::value,
bool throw_if_accessed = false>
class VectorView {
public:
typedef typename
boost::conditional<boost::is_const<T>::value,
typename boost::add_const<
typename scalar_type<T>::type>::type,
typename scalar_type<T>::type>::type scalar_t;
template <typename X>
explicit VectorView(X x) {
throw std::logic_error("VectorView: the default template "
"specialization not implemented");
}
scalar_t& operator[](int i) {
throw std::logic_error("VectorView: the default template "
"specialization not implemented");
}
scalar_t& operator[](int i) const {
throw std::logic_error("VectorView: the default template "
"specialization not implemented");
}
};
template <typename T, bool is_array>
class VectorView<T, is_array, true> {
public:
typedef typename
boost::conditional<boost::is_const<T>::value,
typename boost::add_const<
typename scalar_type<T>::type>::type,
typename scalar_type<T>::type>::type scalar_t;
VectorView() { }
template <typename X>
explicit VectorView(X x) { }
scalar_t& operator[](int i) {
throw std::logic_error("VectorView: this cannot be accessed");
}
scalar_t& operator[](int i) const {
throw std::logic_error("VectorView: this cannot be accessed");
}
};
// this covers non-vectors: double
template <typename T>
class VectorView<T, false, false> {
public:
typedef typename
boost::conditional<boost::is_const<T>::value,
typename boost::add_const<
typename scalar_type<T>::type>::type,
typename scalar_type<T>::type>::type scalar_t;
explicit VectorView(scalar_t& x) : x_(&x) { }
explicit VectorView(scalar_t* x) : x_(x) { }
scalar_t& operator[](int i) {
return *x_;
}
scalar_t& operator[](int i) const {
return *x_;
}
private:
scalar_t* x_;
};
// this covers raw memory: double*
template <typename T>
class VectorView<T, true, false> {
public:
typedef typename
boost::conditional<boost::is_const<T>::value,
typename boost::add_const<
typename scalar_type<T>::type>::type,
typename scalar_type<T>::type>::type scalar_t;
explicit VectorView(scalar_t* x) : x_(x) { }
scalar_t& operator[](int i) {
return x_[i];
}
scalar_t& operator[](int i) const {
return x_[i];
}
private:
scalar_t* x_;
};
}
#endif
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment