Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generic var templates for operators and std::iterator_trait var/fvar specialization #1525

Merged
merged 39 commits into from
Feb 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
8309363
Adds std iterator_traits specialization for fvar and var. The var ope…
SteveBronder Dec 18, 2019
bd9b20c
cleanup the template names
SteveBronder Dec 18, 2019
f8f2e3a
[Jenkins] auto-formatting by clang-format version 5.0.2-svn328729-1~e…
stan-buildbot Dec 18, 2019
8806331
cleanup the unary var templates
SteveBronder Dec 18, 2019
a6b4d81
cleanup the unary var templates
SteveBronder Dec 18, 2019
3868acf
[Jenkins] auto-formatting by clang-format version 5.0.2-svn328729-1~e…
stan-buildbot Dec 18, 2019
5e07ef9
replace var_or_fvar_t with autodiff_t in require_generics tests
SteveBronder Dec 18, 2019
119a7e7
[Jenkins] auto-formatting by clang-format version 6.0.0 (tags/google/…
stan-buildbot Dec 18, 2019
1348dda
remove template from ostream for var
SteveBronder Dec 18, 2019
858e1f2
Merge branch 'cleanup/generic-templates-var' of github.com:stan-dev/m…
SteveBronder Dec 18, 2019
ec6345a
fix order of members in kinsoldata
SteveBronder Dec 18, 2019
4300497
revert beta-binomial changes
SteveBronder Dec 20, 2019
fd35443
Fixup template order for core var impls
SteveBronder Dec 24, 2019
73181b4
Merge commit 'cb961050fd2bb013cc658eb8e3eafaa6bdf1cf38' into HEAD
yashikno Dec 24, 2019
36777ab
[Jenkins] auto-formatting by clang-format version 5.0.0-3~16.04.1 (ta…
stan-buildbot Dec 24, 2019
ad62f4f
Moves cmath var and fvar stuff over to prim and uses initlializer bra…
SteveBronder Dec 30, 2019
fd2a4a8
Merge commit '65aec14f5caea8b9e38a7475afcd4a6681648497' into HEAD
yashikno Dec 30, 2019
930329d
[Jenkins] auto-formatting by clang-format version 5.0.2-svn328729-1~e…
stan-buildbot Dec 30, 2019
6185370
put back the namespace call for exp in gp_periodic_cov and remove sta…
SteveBronder Dec 30, 2019
12ec611
Merge branch 'cleanup/generic-templates-var' of github.com:stan-dev/m…
SteveBronder Dec 30, 2019
88c86e8
merge to develop
SteveBronder Dec 30, 2019
5564039
merge to develop
SteveBronder Dec 31, 2019
a694d1a
Merge branch 'develop' into cleanup/generic-templates-var
SteveBronder Jan 3, 2020
5740cd4
Merge remote-tracking branch 'origin/develop' into cleanup/generic-te…
SteveBronder Jan 5, 2020
4cba532
Merge remote-tracking branch 'origin/develop' into cleanup/generic-te…
SteveBronder Jan 5, 2020
30ee8c9
Remove Var&& arguments for const var& arguments in rev/core
SteveBronder Jan 6, 2020
1a565b6
[Jenkins] auto-formatting by clang-format version 5.0.0-3~16.04.1 (ta…
stan-buildbot Jan 6, 2020
75eaf43
merge to develop
SteveBronder Jan 13, 2020
1342d33
Merge branch 'develop' of https://github.com/stan-dev/math into clean…
Jan 21, 2020
3604151
split cmath.hpp into files w. unit tests
Jan 22, 2020
9eebaa7
fix isnan tests to call right fun
Jan 22, 2020
993ceaa
testing pass by value for var ops instead of by reference
SteveBronder Jan 25, 2020
cd60021
Merge branch 'cleanup/pass-var-by-value', remote-tracking branch 'ori…
SteveBronder Jan 25, 2020
ced2df7
Merge branch 'cleanup/generic-templates-var' of github.com:stan-dev/m…
SteveBronder Jan 25, 2020
8d460ac
Merge commit 'c0d2265f842a1b2df04855fac49d87e9962aa878' into HEAD
yashikno Jan 25, 2020
2795719
[Jenkins] auto-formatting by clang-format version 6.0.0 (tags/google/…
stan-buildbot Jan 25, 2020
99a916b
Merge branch 'develop' of https://github.com/stan-dev/math into clean…
Jan 29, 2020
84f5b26
Merge branch 'develop' of https://github.com/stan-dev/math into clean…
Jan 31, 2020
06ad089
templated var overloads for pow
Jan 31, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions stan/math/fwd/core.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@
#include <stan/math/fwd/core/operator_unary_not.hpp>
#include <stan/math/fwd/core/operator_unary_plus.hpp>
#include <stan/math/fwd/core/std_numeric_limits.hpp>
#include <stan/math/fwd/core/std_iterator_traits.hpp>

#endif
42 changes: 42 additions & 0 deletions stan/math/fwd/core/std_iterator_traits.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#ifndef STAN_MATH_FWD_CORE_STD_ITERATOR_TRAITS_HPP
#define STAN_MATH_FWD_CORE_STD_ITERATOR_TRAITS_HPP

#include <stan/math/fwd/core/fvar.hpp>
#include <stan/math/prim/meta.hpp>
#include <iterator>

namespace std {
/**
* Specialization of iterator traits for Stan math. These all take
* the form of typedefs.
*/
template <typename T>
struct iterator_traits<stan::math::fvar<T>> {
/**
* Iterator category for traits.
*/
typedef random_access_iterator_tag iterator_category;

/**
* Type for difference between pointers.
*/
typedef ptrdiff_t difference_type;

/**
* Type for value of pointer to values.
*/
typedef stan::math::fvar<T> value_type;

/**
* Type of pointer to variables.
*/
typedef stan::math::fvar<T>* pointer;

/**
* Type of reference to variables.
*/
typedef stan::math::fvar<T>& reference;
};
} // namespace std

#endif
6 changes: 6 additions & 0 deletions stan/math/prim/fun.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include <stan/math/prim/fun/columns_dot_self.hpp>
#include <stan/math/prim/fun/common_type.hpp>
#include <stan/math/prim/fun/constants.hpp>
#include <stan/math/prim/fun/copysign.hpp>
#include <stan/math/prim/fun/corr_constrain.hpp>
#include <stan/math/prim/fun/corr_free.hpp>
#include <stan/math/prim/fun/corr_matrix_constrain.hpp>
Expand Down Expand Up @@ -127,6 +128,10 @@
#include <stan/math/prim/fun/inverse.hpp>
#include <stan/math/prim/fun/inverse_softmax.hpp>
#include <stan/math/prim/fun/inverse_spd.hpp>
#include <stan/math/prim/fun/isfinite.hpp>
#include <stan/math/prim/fun/isinf.hpp>
#include <stan/math/prim/fun/isnan.hpp>
#include <stan/math/prim/fun/isnormal.hpp>
#include <stan/math/prim/fun/is_any_nan.hpp>
#include <stan/math/prim/fun/is_inf.hpp>
#include <stan/math/prim/fun/is_nan.hpp>
Expand Down Expand Up @@ -250,6 +255,7 @@
#include <stan/math/prim/fun/sd.hpp>
#include <stan/math/prim/fun/segment.hpp>
#include <stan/math/prim/fun/sign.hpp>
#include <stan/math/prim/fun/signbit.hpp>
#include <stan/math/prim/fun/simplex_constrain.hpp>
#include <stan/math/prim/fun/simplex_free.hpp>
#include <stan/math/prim/fun/sin.hpp>
Expand Down
34 changes: 34 additions & 0 deletions stan/math/prim/fun/copysign.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#ifndef STAN_MATH_PRIM_SCAL_FUN_COPYSIGN_HPP
#define STAN_MATH_PRIM_SCAL_FUN_COPYSIGN_HPP

#include <stan/math/prim/meta.hpp>

namespace stan {
namespace math {

/**
* Return the negation of the first argument if the first and second
* argument have different signs, otherwise return a copy of the first
* argument. For the sake of this function, zero is considered
* positive. ADTypehis function uses negation rather than literally copying
* signs to preserve derivatives.
*
* Overload of `std::copysign` from `cmath` for argument-dependent
* lookup.
*
* @tparam ADType type of first argument
* @tparam U type of second argument
* @param[in] x first complex argument
* @param[in] y second complex argument
* @return copy of second argument, negated if necessary to match sign
* of first argument
*/
template <typename ADType, typename U>
inline ADType copysign(const ADType& x, const U& y) {
// +0 is positive; second condition handles -0
return (x < 0 && y >= 0) || (x >= 0 && y < 0) ? -x : x;
}
} // namespace math
} // namespace stan

#endif
29 changes: 29 additions & 0 deletions stan/math/prim/fun/isfinite.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#ifndef STAN_MATH_PRIM_SCAL_FUN_ISFINITE_HPP
#define STAN_MATH_PRIM_SCAL_FUN_ISFINITE_HPP

#include <stan/math/prim/meta.hpp>

namespace stan {
namespace math {

/**
* Return true if specified argument is finite (not infinite and not
* not-a-number).
*
* Overloads `std::isfinite` from `<cmath>` for argument-dependent
* lookup.
*
* @tparam ADType type of argument
* @param[in] v argument
* @return true if argument is finite
*/
template <typename ADType, require_autodiff_t<ADType>...>
inline bool isfinite(ADType&& v) {
using std::isfinite;
return isfinite(v.val());
}

} // namespace math
} // namespace stan

#endif
29 changes: 29 additions & 0 deletions stan/math/prim/fun/isinf.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#ifndef STAN_MATH_PRIM_SCAL_FUN_ISINF_HPP
#define STAN_MATH_PRIM_SCAL_FUN_ISINF_HPP

#include <stan/math/prim/meta.hpp>

namespace stan {
namespace math {

/**
* Return true if specified argument is infinite (positive or
* negative).
*
* Overloads `std::isinf` from `<cmath>` for argument-dependent
* lookup.
*
* @tparam ADType type of argument
* @param[in] v argument
* @return true if argument is infinite
*/
template <typename ADType, require_autodiff_t<ADType>...>
inline bool isinf(ADType&& v) {
using std::isinf;
return isinf(v.val());
}

} // namespace math
} // namespace stan

#endif
28 changes: 28 additions & 0 deletions stan/math/prim/fun/isnan.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#ifndef STAN_MATH_PRIM_SCAL_FUN_ISNAN_HPP
#define STAN_MATH_PRIM_SCAL_FUN_ISNAN_HPP

#include <stan/math/prim/meta.hpp>

namespace stan {
namespace math {

/**
* Return true if specified argument is not-a-number.
*
* Overloads `std::isnan` from `<cmath>` for argument-dependent
* lookup.
*
* @tparam ADType type of argument
* @param[in] v argument
* @return true if argument is not-a-number
*/
template <typename ADType, require_autodiff_t<ADType>...>
inline bool isnan(ADType&& v) {
using std::isnan;
return isnan(v.val());
}

} // namespace math
} // namespace stan

#endif
29 changes: 29 additions & 0 deletions stan/math/prim/fun/isnormal.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#ifndef STAN_MATH_PRIM_SCAL_FUN_ISNORMAL_HPP
#define STAN_MATH_PRIM_SCAL_FUN_ISNORMAL_HPP

#include <stan/math/prim/meta.hpp>

namespace stan {
namespace math {

/**
* Return true if specified argument is normal. A number is normal if
* it is finite, non-zero and not subnormal.
*
* Overloads `std::isnormal` from `<cmath>` for argument-dependent
* lookup.
*
* @tparam ADType type of argument
* @param[in] v argument
* @return true if argument is normal
*/
template <typename ADType, require_autodiff_t<ADType>...>
inline bool isnormal(ADType&& v) {
using std::isnormal;
return isnormal(v.val());
}

} // namespace math
} // namespace stan

#endif
29 changes: 29 additions & 0 deletions stan/math/prim/fun/signbit.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#ifndef STAN_MATH_PRIM_SCAL_FUN_SIGNBIT_HPP
#define STAN_MATH_PRIM_SCAL_FUN_SIGNBIT_HPP

#include <stan/math/prim/meta.hpp>

namespace stan {
namespace math {

/**
* Return `true` if the specified argument is negative and `false`
* otherwise.
*
* Overloads `std::signbit` from `<cmath>` for argument-dependent
* lookup.
*
* @tparam ADType type of argument
* @param[in] v argument
* @return `true` if the argument is negative
*/
template <typename ADType, require_autodiff_t<ADType>...>
inline bool signbit(ADType&& v) {
using std::signbit;
return signbit(v.val());
}

} // namespace math
} // namespace stan

#endif
16 changes: 7 additions & 9 deletions stan/math/prim/meta/require_generics.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ struct is_double_or_int
* @tparam The type to check
*/
template <typename T>
struct is_var_or_fvar
struct is_autodiff
SteveBronder marked this conversation as resolved.
Show resolved Hide resolved
: bool_constant<math::disjunction<is_var<std::decay_t<T>>,
is_fvar<std::decay_t<T>>>::value> {};

Expand Down Expand Up @@ -529,24 +529,22 @@ using require_any_not_fvar_t
= require_any_not_t<is_fvar<std::decay_t<Types>>...>;

template <typename T>
using require_var_or_fvar_t = require_t<is_var_or_fvar<T>>;
using require_autodiff_t = require_t<is_autodiff<T>>;
Copy link
Contributor

Choose a reason for hiding this comment

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

[comment]
These are all super useful. Thanks for adding.


template <typename T>
using require_not_var_or_fvar_t = require_not_t<is_var_or_fvar<T>>;
using require_not_autodiff_t = require_not_t<is_autodiff<T>>;
Copy link
Contributor

@bob-carpenter bob-carpenter Dec 24, 2019

Choose a reason for hiding this comment

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

I'd strongly prefer

  • removing the require_ prefix because that's implying a use, not a behavior

  • replace _t with _v because it denotes a boolean value, not a type; this follows the behavior of is_arithmetic_v; enable_if_t ends in _t because it denotes a type (void by default), not a value.

For example, that'd be not_autodiff_v<T> for true if T is not an autodiff type, and usage would be, for example enable_if_t<not_autodiff_v<T>, U>.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

removing the require_ prefix because that's implying a use, not a behavior

Can you clarify? I'm not sure i understand how the require part of the name is implying a use over a behaviour. The intent with the require_ in the name is because all those require_*s are trying to emulate a legacy version of C++20 concepts. It's for if you want a universal reference in the function signature for all the weird value types and const combinations. In terms of use/behavior I think my answer is that I think about C++ concepts like compile time contracts (which feels like a behaviour, though idk what that word means in context here)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

replace _t with _v because it denotes a boolean value, not a type; this follows the behavior of is_arithmetic_v; enable_if_t ends in _t because it denotes a type (void by default), not a value.
For example, that'd be not_autodiff_v for true if T is not an autodiff type, and usage would be, for example enable_if_t<not_autodiff_v, U>.

The require_*_t metaprogramming stuff is essentially a convoluted / compact way to write std::enable_if_t<...> i.e. they also return void.

You can think of require_autodiff_t as an alias for enable_if_t<not_autodiff_v<T>, U>.

Also idt we can use C++ compile time constexpr objects with c++1y (anything _v like how std does) since the windows compiler we require compatibility with for Rtools has a bug for those

Copy link
Contributor

Choose a reason for hiding this comment

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

I misunderstood and thought this was a boolean. Now that I see what it's doing, I still think it needs to be renamed. How about enable_if_autodiff_t to enable if it's an autodiff type? That follows the standard library naming conventions more closely than require_autodiff_t.

We can then use disable_if_autodiff_t instead of enable_if_not_autodiff_t.

We can build similar ones for primitives, enable_if_arithmetic_t and disable_if_arithmetic_t.


template <typename... Types>
using require_all_var_or_fvar_t = require_all_t<is_var_or_fvar<Types>...>;
using require_all_autodiff_t = require_all_t<is_autodiff<Types>...>;
Copy link
Contributor

Choose a reason for hiding this comment

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

Should these all have doc or are they so close to the ones without _v that they're obvious? cppreference actually doesn't doc these and they doc everything else meticulously.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I've been throwing this back and forth with myself. I've leaned towards not doc since aliases are inlined in the docs you can see the full definition

http://mc-stan.org/math/d0/dfb/group__require__base__types.html#gac55eae5c1fc2f38a96336b5f0bc94449


template <typename... Types>
using require_any_var_or_fvar_t = require_any_t<is_var_or_fvar<Types>...>;
using require_any_autodiff_t = require_any_t<is_autodiff<Types>...>;

template <typename... Types>
using require_all_not_var_or_fvar_t
= require_all_not_t<is_var_or_fvar<Types>...>;
using require_all_not_autodiff_t = require_all_not_t<is_autodiff<Types>...>;

template <typename... Types>
using require_any_not_var_or_fvar_t
= require_any_not_t<is_var_or_fvar<Types>...>;
using require_any_not_autodiff_t = require_any_not_t<is_autodiff<Types>...>;

template <typename T>
using require_stan_scalar_t = require_t<is_stan_scalar<T>>;
Expand Down
1 change: 1 addition & 0 deletions stan/math/rev/core.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <stan/math/rev/core/chainable_alloc.hpp>
#include <stan/math/rev/core/chainablestack.hpp>
#include <stan/math/rev/core/init_chainablestack.hpp>
#include <stan/math/rev/core/std_iterator_traits.hpp>
#include <stan/math/rev/core/ddv_vari.hpp>
#include <stan/math/rev/core/dv_vari.hpp>
#include <stan/math/rev/core/dvd_vari.hpp>
Expand Down
17 changes: 11 additions & 6 deletions stan/math/rev/core/operator_addition.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef STAN_MATH_REV_CORE_OPERATOR_ADDITION_HPP
#define STAN_MATH_REV_CORE_OPERATOR_ADDITION_HPP

#include <stan/math/prim/meta.hpp>
#include <stan/math/rev/core/var.hpp>
#include <stan/math/rev/core/vv_vari.hpp>
#include <stan/math/rev/core/vd_vari.hpp>
Expand Down Expand Up @@ -77,8 +78,8 @@ class add_vd_vari : public op_vd_vari {
* @param b Second variable operand.
* @return Variable result of adding two variables.
*/
inline var operator+(const var& a, const var& b) {
return var(new internal::add_vv_vari(a.vi_, b.vi_));
inline var operator+(var a, var b) {
return {new internal::add_vv_vari(a.vi_, b.vi_)};
}

/**
Expand All @@ -88,15 +89,17 @@ inline var operator+(const var& a, const var& b) {
*
* \f$\frac{d}{dx} (x + c) = 1\f$.
*
* @tparam Arith An arithmetic type
* @param a First variable operand.
* @param b Second scalar operand.
* @return Result of adding variable and scalar.
*/
inline var operator+(const var& a, double b) {
template <typename Arith, require_arithmetic_t<Arith>...>
inline var operator+(var a, Arith b) {
if (b == 0.0) {
return a;
}
return var(new internal::add_vd_vari(a.vi_, b));
return {new internal::add_vd_vari(a.vi_, b)};
}

/**
Expand All @@ -106,15 +109,17 @@ inline var operator+(const var& a, double b) {
*
* \f$\frac{d}{dy} (c + y) = 1\f$.
*
* @tparam Arith An arithmetic type
* @param a First scalar operand.
* @param b Second variable operand.
* @return Result of adding variable and scalar.
*/
inline var operator+(double a, const var& b) {
template <typename Arith, require_arithmetic_t<Arith>...>
inline var operator+(Arith a, var b) {
if (a == 0.0) {
return b;
}
return var(new internal::add_vd_vari(b.vi_, a)); // by symmetry
return {new internal::add_vd_vari(b.vi_, a)}; // by symmetry
}

} // namespace math
Expand Down
7 changes: 4 additions & 3 deletions stan/math/rev/core/operator_divide_equal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@

#include <stan/math/rev/core/var.hpp>
#include <stan/math/rev/core/operator_division.hpp>
#include <stan/math/prim/meta.hpp>

namespace stan {
namespace math {

inline var& var::operator/=(const var& b) {
inline var& var::operator/=(var b) {
vi_ = new internal::divide_vv_vari(vi_, b.vi_);
return *this;
}

inline var& var::operator/=(double b) {
template <typename Arith, require_arithmetic_t<Arith>...>
inline var& var::operator/=(Arith b) {
if (b == 1.0) {
return *this;
}
Expand Down
Loading