From c00158fd0a50d83faf33def59f0a5b542ced49c7 Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Sun, 1 Mar 2020 12:19:42 -0500 Subject: [PATCH 01/63] exp, copysign, complex test extensions --- stan/math/fwd/fun/exp.hpp | 6 +++ stan/math/prim/fun/copysign.hpp | 22 +++++++++ stan/math/prim/fun/exp.hpp | 39 +++++++++++++++ stan/math/rev/fun/exp.hpp | 5 ++ test/unit/math/mix/fun/copysign_test.cpp | 44 +++++++++++++---- test/unit/math/mix/fun/exp_test.cpp | 6 ++- test/unit/math/test_ad.hpp | 61 ++++++++++++++++++++++++ 7 files changed, 174 insertions(+), 9 deletions(-) diff --git a/stan/math/fwd/fun/exp.hpp b/stan/math/fwd/fun/exp.hpp index c15b8a2637b..6aaf2e02134 100644 --- a/stan/math/fwd/fun/exp.hpp +++ b/stan/math/fwd/fun/exp.hpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace stan { namespace math { @@ -13,6 +14,11 @@ inline fvar exp(const fvar& x) { return fvar(exp(x.val_), x.d_ * exp(x.val_)); } +// template +// inline std::complex> exp(const std::complex>& z) { +// return complex_exp(z); +// } + } // namespace math } // namespace stan #endif diff --git a/stan/math/prim/fun/copysign.hpp b/stan/math/prim/fun/copysign.hpp index bccf23bd1cc..e89ba9dc952 100644 --- a/stan/math/prim/fun/copysign.hpp +++ b/stan/math/prim/fun/copysign.hpp @@ -28,6 +28,28 @@ 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; } + +/** + * Return the complex number composed of the real and complex parts + * with signs copied from the real and complex parts of the first + * arguments to the real and complex parts of the second. + * + * This is an overload of the standard libary `copysign` for complex + * numbers that will be used with argument-dependent lookup. + * + * @tparam T value type of first argument + * @tparam U value type of second argument + * @param[in] x first complex argument + * @param[in] y second complex argument + * @return copy of second argument, with components negated if + * necessary to match sign of first argument + */ +template +inline std::complex copysign(const std::complex& y, + const std::complex& x) { + return {copysign(y.real(), x.real()), copysign(y.imag(), x.imag())}; +} + } // namespace math } // namespace stan diff --git a/stan/math/prim/fun/exp.hpp b/stan/math/prim/fun/exp.hpp index d1ac2eaa717..c5d6c9eab5f 100644 --- a/stan/math/prim/fun/exp.hpp +++ b/stan/math/prim/fun/exp.hpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace stan { namespace math { @@ -17,6 +18,44 @@ namespace math { */ inline double exp(int x) { return std::exp(x); } +/** + * Return the natural (base e) complex exponentiation of the specified + * complex argument. + * + * @tparam V value type (must be Stan autodiff type) + * @param z complex number + * @return natural exponentiation of specified complex number + * @see documentation for `std::complex` for boundary condition and + * branch cut details + */ +template > +inline std::complex exp(const std::complex& z) { + if (is_inf(z.real()) && z.real() > 0) { + if (is_nan(z.imag()) || z.imag() == 0) { + // (+inf, nan), (+inf, 0) + return z; + } else if (is_inf(z.imag()) && z.imag() > 0) { + // (+inf, +inf) + return {z.real(), std::numeric_limits::quiet_NaN()}; + } else if (is_inf(z.imag()) && z.imag() < 0) { + // (+inf, -inf) + return {std::numeric_limits::quiet_NaN(), + std::numeric_limits::quiet_NaN()}; + } + } + if (is_inf(z.real()) && z.real() < 0 + && (is_nan(z.imag()) || is_inf(z.imag()))) { + // (-inf, nan), (-inf, -inf), (-inf, inf) + return {0, 0}; + } + if (is_nan(z.real()) && z.imag() == -0.0) { + // (nan, -0) + return z; + } + V exp_re = exp(z.real()); + return {exp_re * cos(z.imag()), exp_re * sin(z.imag())}; +} + /** * Structure to wrap exp() so that it can be * vectorized. diff --git a/stan/math/rev/fun/exp.hpp b/stan/math/rev/fun/exp.hpp index 0136194f894..0431446c269 100644 --- a/stan/math/rev/fun/exp.hpp +++ b/stan/math/rev/fun/exp.hpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace stan { namespace math { @@ -40,6 +41,10 @@ class exp_vari : public op_v_vari { */ inline var exp(const var& a) { return var(new internal::exp_vari(a.vi_)); } +// inline std::complex exp(const std::complex& z) { +// return complex_exp(z); +// } + } // namespace math } // namespace stan #endif diff --git a/test/unit/math/mix/fun/copysign_test.cpp b/test/unit/math/mix/fun/copysign_test.cpp index 67cd1685393..811084746a5 100644 --- a/test/unit/math/mix/fun/copysign_test.cpp +++ b/test/unit/math/mix/fun/copysign_test.cpp @@ -1,8 +1,14 @@ #include #include +#include #include #include +template +void expect_eq_signbit(const U& u, const V& v) { + EXPECT_EQ(signbit(u), signbit(v)); +} + template void expect_copysign() { using stan::math::copysign; @@ -10,15 +16,37 @@ void expect_copysign() { using std::copysign; using std::numeric_limits; using std::signbit; - T inf = numeric_limits::infinity(); - T nan = std::numeric_limits::quiet_NaN(); - std::vector ys{inf, -inf, -1, 0, 1}; // inf, -inf, -1.0, 0.0, 1.0 }; - for (const T& x : ys) { - for (const T& y : ys) { - EXPECT_EQ(signbit(y), signbit(copysign(T(x), y))); - EXPECT_EQ(signbit(y), signbit(copysign(x, T(y)))); - EXPECT_EQ(signbit(y), signbit(copysign(T(x), T(y)))); + double inf = numeric_limits::infinity(); + std::vector ys{inf, -inf, -1, 0, 1}; + + // real + for (double x : ys) { + for (double y : ys) { + expect_eq_signbit(y, copysign(T(x), y)); + expect_eq_signbit(y, copysign(x, T(y))); + expect_eq_signbit(y, copysign(T(x), T(y))); + } + } + // complex + for (double re1 : ys) { + for (double im1 : ys) { + auto x_d = std::complex(re1, im1); + auto x_t = std::complex(re1, im1); + for (double re2 : ys) { + for (double im2 : ys) { + auto y_d = std::complex(re2, im2); + auto y_t = std::complex(re2, im2); + expect_eq_signbit(re2, copysign(x_d, y_d).real()); + expect_eq_signbit(re2, copysign(x_d, y_t).real()); + expect_eq_signbit(re2, copysign(x_t, y_d).real()); + expect_eq_signbit(re2, copysign(x_t, y_t).real()); + expect_eq_signbit(im2, copysign(x_d, y_d).imag()); + expect_eq_signbit(im2, copysign(x_d, y_t).imag()); + expect_eq_signbit(im2, copysign(x_t, y_d).imag()); + expect_eq_signbit(im2, copysign(x_t, y_t).imag()); + } + } } } } diff --git a/test/unit/math/mix/fun/exp_test.cpp b/test/unit/math/mix/fun/exp_test.cpp index ce8ea90d6c1..1a75ed232e8 100644 --- a/test/unit/math/mix/fun/exp_test.cpp +++ b/test/unit/math/mix/fun/exp_test.cpp @@ -1,8 +1,12 @@ #include TEST(mathMixMatFun, exp) { - auto f = [](const auto& x1) { return stan::math::exp(x1); }; + auto f = [](const auto& x) { + using stan::math::exp; + return exp(x); + }; stan::test::expect_common_unary_vectorized(f); stan::test::expect_unary_vectorized(f, -15.2, -10, -0.5, 0.5, 1, 1.0, 1.3, 5, 10); + stan::test::expect_complex_common(f); } diff --git a/test/unit/math/test_ad.hpp b/test/unit/math/test_ad.hpp index ed1f1b15485..12d3cf9d235 100644 --- a/test/unit/math/test_ad.hpp +++ b/test/unit/math/test_ad.hpp @@ -1721,6 +1721,67 @@ auto ldlt_factor(const Eigen::Matrix& x) { return ldlt_x; } +/** + * Return the + */ +std::vector common_complex_parts() { + double inf = std::numeric_limits::infinity(); + double nan = std::numeric_limits::quiet_NaN(); + return {-4, -2.5, -1.5, -0.3, -0.0, 0.0, 1.3, 2.1, 3.9}; +} + +std::vector> common_complex() { + std::vector> zs; + for (double re : common_complex_parts()) + for (double im : common_complex_parts()) + zs.emplace_back(re, im); + return zs; +} + +template +void expect_complex_common(const F& f) { + auto zs = common_complex(); + for (auto z : zs) { + expect_ad(f, z); + } +} + +template +void expect_complex_common_binary(const F& f) { + auto zs = common_complex(); + for (auto z1 : zs) { + for (auto z2 : zs) { + test_ad(f, z1, z2); + } + } +} + +// template +// void expect_reduction(const F& f) { +// cvar_t x(1, 2); +// var_t y = f(x); + +// cdouble_t xd(1, 2); +// double yd = f(xd); +// EXPECT_FLOAT_EQ(yd, y.val()); +// } + +// std::vector common_complex_non_neg_parts() { +// double inf = std::numeric_limits::infinity(); +// double nan = std::numeric_limits::quiet_NaN(); +// double pos_zero = 0.0; +// return {0.0, 1.3, 2.1}; +// } + +// template +// std::vector to_array(const std::complex& a) { +// return {a.real(), a.imag()}; +// } +// template +// std::complex from_array(const std::vector& a) { +// return {a[0], a[1]}; +// } + } // namespace test } // namespace stan #endif From f715f51773620807110fca76f0b4bd7ad704740f Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Sun, 1 Mar 2020 17:04:16 -0500 Subject: [PATCH 02/63] i_times and related --- stan/math/prim/fun.hpp | 1 + stan/math/prim/fun/copysign.hpp | 1 + stan/math/prim/fun/i_times.hpp | 55 +++++++++++++++++++++++++ test/unit/math/mix/fun/i_times_test.cpp | 16 +++++++ 4 files changed, 73 insertions(+) create mode 100644 stan/math/prim/fun/i_times.hpp create mode 100644 test/unit/math/mix/fun/i_times_test.cpp diff --git a/stan/math/prim/fun.hpp b/stan/math/prim/fun.hpp index 72d6a26d557..ccffa08c6ce 100644 --- a/stan/math/prim/fun.hpp +++ b/stan/math/prim/fun.hpp @@ -115,6 +115,7 @@ #include #include #include +#include #include #include #include diff --git a/stan/math/prim/fun/copysign.hpp b/stan/math/prim/fun/copysign.hpp index e89ba9dc952..3d19bf8d2a3 100644 --- a/stan/math/prim/fun/copysign.hpp +++ b/stan/math/prim/fun/copysign.hpp @@ -2,6 +2,7 @@ #define STAN_MATH_PRIM_SCAL_FUN_COPYSIGN_HPP #include +#include namespace stan { namespace math { diff --git a/stan/math/prim/fun/i_times.hpp b/stan/math/prim/fun/i_times.hpp new file mode 100644 index 00000000000..002f8420edf --- /dev/null +++ b/stan/math/prim/fun/i_times.hpp @@ -0,0 +1,55 @@ +#ifndef STAN_MATH_PRIM_SCAL_FUN_I_TIMES_HPP +#define STAN_MATH_PRIM_SCAL_FUN_I_TIMES_HPP + +#include + +namespace stan { +namespace math { + +/** + * Return the specified complex number multiplied by `i`. + * + * This compound function is more efficient than mulitplying by a + * constant `i` because it involves only a single arithmetic negation. + * + * @tparam value type of complex argument + * @param[in] z complex argument + * @return argument multipled by `i` + */ +template +inline std::complex i_times(const std::complex& z) { + return {-z.imag(), z.real()}; +} + +/** + * Return the specified complex number multiplied by `-i`. + * + * This compound function is more efficient than mulitplying by the + * constant `-i` because it involves only a single arithmetic + * negation. + * + * @tparam value type of complex argument + * @param[in] z complex argument + * @return argument multipled by `-i` + */ +template +inline std::complex neg_i_times(const std::complex& z) { + return {z.imag(), -z.real()}; +} + +/** + * Return the complex negation of the specified complex argument. + * + * @tparam V value type of complex argument + * @param[in] z argument + * @return negation of argument + */ +template +inline std::complex complex_negate(const std::complex& z) { + return {-z.real(), -z.imag()}; +} + +} // namespace math +} // namespace stan + +#endif diff --git a/test/unit/math/mix/fun/i_times_test.cpp b/test/unit/math/mix/fun/i_times_test.cpp new file mode 100644 index 00000000000..5234906194d --- /dev/null +++ b/test/unit/math/mix/fun/i_times_test.cpp @@ -0,0 +1,16 @@ +#include + +TEST(matPrimFun, iTimes) { + auto f = [](const auto& x) { return stan::math::i_times(x); }; + stan::test::expect_complex_common(f); +} + +TEST(matPrimFun, negITimes) { + auto f = [](const auto& x) { return stan::math::neg_i_times(x); }; + stan::test::expect_complex_common(f); +} + +TEST(matPrimFun, complexNegate) { + auto f = [](const auto& x) { return stan::math::complex_negate(x); }; + stan::test::expect_complex_common(f); +} From d64babede792da76b683675a1fedbff70cc0419c Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Sun, 1 Mar 2020 19:16:26 -0500 Subject: [PATCH 03/63] complex binary operator+ and operator- --- stan/math/fwd/core/std_complex.hpp | 8 +- stan/math/prim/core.hpp | 2 + stan/math/prim/core/complex_base.hpp | 2 +- stan/math/prim/core/operator_addition.hpp | 76 +++++++++++++++++++ stan/math/prim/core/operator_subtraction.hpp | 76 +++++++++++++++++++ stan/math/rev/core/std_complex.hpp | 7 +- stan/math/rev/core/var.hpp | 64 ---------------- .../math/mix/core/operator_addition_test.cpp | 3 + .../mix/core/operator_subtraction_test.cpp | 1 + test/unit/math/test_ad.hpp | 2 +- 10 files changed, 171 insertions(+), 70 deletions(-) create mode 100644 stan/math/prim/core/operator_addition.hpp create mode 100644 stan/math/prim/core/operator_subtraction.hpp diff --git a/stan/math/fwd/core/std_complex.hpp b/stan/math/fwd/core/std_complex.hpp index b7b7263df88..e52b65f0546 100644 --- a/stan/math/fwd/core/std_complex.hpp +++ b/stan/math/fwd/core/std_complex.hpp @@ -32,8 +32,12 @@ class complex> * @tparam Scalar real type (must be assignable to `value_type`) * @param[in] re real part */ - template > - complex(U&& re) : base_t(re) {} // NOLINT(runtime/explicit) + template // , typename = stan::require_stan_scalar_t> + complex(const U& re) : base_t(re) {} // NOLINT(runtime/explicit) + + template + complex(const std::complex& z) // NOLINT(runtime/explicit) + : base_t(z.real(), z.imag()) {} /** * Construct a complex number from the specified real and imaginary diff --git a/stan/math/prim/core.hpp b/stan/math/prim/core.hpp index 680c7b0139f..ec899aa2629 100644 --- a/stan/math/prim/core.hpp +++ b/stan/math/prim/core.hpp @@ -2,5 +2,7 @@ #define STAN_MATH_PRIM_CORE_HPP #include +#include +#include #endif diff --git a/stan/math/prim/core/complex_base.hpp b/stan/math/prim/core/complex_base.hpp index 4d21c88b585..222a93009ef 100644 --- a/stan/math/prim/core/complex_base.hpp +++ b/stan/math/prim/core/complex_base.hpp @@ -39,7 +39,7 @@ class complex_base { * @tparam U real type (assignable to `value_type`) * @param[in] re real part */ - template > + template // , typename = require_stan_scalar_t> complex_base(const U& re) : re_(re) {} // NOLINT(runtime/explicit) /** diff --git a/stan/math/prim/core/operator_addition.hpp b/stan/math/prim/core/operator_addition.hpp new file mode 100644 index 00000000000..fc7f210b518 --- /dev/null +++ b/stan/math/prim/core/operator_addition.hpp @@ -0,0 +1,76 @@ +#ifndef STAN_MATH_PRIM_CORE_OPERATOR_ADDITION_HPP +#define STAN_MATH_PRIM_CORE_OPERATOR_ADDITION_HPP + +#include +#include +#include + +namespace stan { +namespace math { + +namespace internal { +/** + * Return the sum of the specified arguments. At least one of the + * arguments must be a complex number. + * + * @tparam U type of first argument + * @tparam V type of second argument + * @param[in] lhs first argument + * @param[in] rhs second argument + * @return sum of the arguments + */ +template +inline complex_return_t complex_add(const U& lhs, const V& rhs) { + complex_return_t y(lhs); + y += rhs; + return y; +} +} // namespace internal + +/** + * Return the sum of the arguments. + * + * @tparam U value type of first argument + * @tparam V value type of second argument + * @param x first argument + * @param y second argument + * @return sum of the arguments + */ +template +inline complex_return_t operator+(const std::complex& x, + const std::complex& y) { + return internal::complex_add(x, y); +} + +/** + * Return the sum of the arguments. + * + * @tparam U value type of first argument + * @tparam V type of second argument + * @param x first argument + * @param y second argument + * @return sum of the arguments + */ +template +inline complex_return_t operator+(const std::complex& x, const V& y) { + return internal::complex_add(x, y); +} + +/** + * Return the sum of the arguments. + * + * @tparam U type of first argument + * @tparam V value type of second argument + * @param x first argument + * @param y second argument + * @return sum of the arguments + */ +template +inline complex_return_t operator+(const U& x, const std::complex& y) { + return internal::complex_add(x, y); +} + +} // namespace math +} // namespace stan + +#endif diff --git a/stan/math/prim/core/operator_subtraction.hpp b/stan/math/prim/core/operator_subtraction.hpp new file mode 100644 index 00000000000..da6f8fa7076 --- /dev/null +++ b/stan/math/prim/core/operator_subtraction.hpp @@ -0,0 +1,76 @@ +#ifndef STAN_MATH_PRIM_CORE_OPERATOR_SUBTRACTION_HPP +#define STAN_MATH_PRIM_CORE_OPERATOR_SUBTRACTION_HPP + +#include +#include +#include + +namespace stan { +namespace math { + +namespace internal { +/** + * Return the difference between specified arguments. At least one of + * the arguments must be a complex number. + * + * @tparam U type of first argument + * @tparam V type of second argument + * @param[in] lhs first argument + * @param[in] rhs second argument + * @return sum of the arguments + */ +template +inline complex_return_t complex_subtract(const U& lhs, const V& rhs) { + complex_return_t y(lhs); + y -= rhs; + return y; +} +} // namespace internal + +/** + * Return the difference of the arguments. + * + * @tparam U value type of first argument + * @tparam V value type of second argument + * @param x first argument + * @param y second argument + * @return difference of the arguments + */ +template +inline complex_return_t operator-(const std::complex& x, + const std::complex& y) { + return internal::complex_subtract(x, y); +} + +/** + * Return the difference of the arguments. + * + * @tparam U value type of first argument + * @tparam V type of second argument + * @param x first argument + * @param y second argument + * @return difference of the arguments + */ +template +inline complex_return_t operator-(const std::complex& x, const V& y) { + return internal::complex_subtract(x, y); +} + +/** + * Return the difference of the arguments. + * + * @tparam U type of first argument + * @tparam V value type of second argument + * @param x first argument + * @param y second argument + * @return difference of the arguments + */ +template +inline complex_return_t operator-(const U& x, const std::complex& y) { + return internal::complex_subtract(x, y); +} + +} // namespace math +} // namespace stan + +#endif diff --git a/stan/math/rev/core/std_complex.hpp b/stan/math/rev/core/std_complex.hpp index d2f76450c5f..b3d67b9643d 100644 --- a/stan/math/rev/core/std_complex.hpp +++ b/stan/math/rev/core/std_complex.hpp @@ -42,8 +42,11 @@ class complex * @tparam U type of real part (assignable to `value_type`) * @param[in] re real part */ - template > - complex(U&& re) : base_t(re) {} // NOLINT(runtime/explicit) + template // , typename = stan::require_stan_scalar_t> + complex(const U& re) : base_t(re) {} // NOLINT(runtime/explicit) + + template + complex(const std::complex& z) : base_t(z.real(), z.imag()) {} /** * Set the real and imaginary components of this complex number to diff --git a/stan/math/rev/core/var.hpp b/stan/math/rev/core/var.hpp index f00d42dfa73..18b499d44c0 100644 --- a/stan/math/rev/core/var.hpp +++ b/stan/math/rev/core/var.hpp @@ -186,71 +186,7 @@ class var { var(unsigned long x) : vi_(new vari(static_cast(x), false)) {} // NOLINT - /** - * Construct a variable from the specified arithmetic argument - * by constructing a new vari with the argument - * cast to double, and a zero adjoint. Only works - * if the imaginary part is zero. - * - * @param x Value of the variable. - */ - explicit var(const std::complex& x) { - if (imag(x) == 0) { - vi_ = new vari(real(x), false); - } else { - std::stringstream ss; - ss << "Imaginary part of std::complex used to construct var" - << " must be zero. Found real part = " << real(x) << " and " - << " found imaginary part = " << imag(x) << std::endl; - std::string msg = ss.str(); - throw std::invalid_argument(msg); - } - } - - /** - * Construct a variable from the specified arithmetic argument - * by constructing a new vari with the argument - * cast to double, and a zero adjoint. Only works - * if the imaginary part is zero. - * - * @param x Value of the variable. - */ - explicit var(const std::complex& x) { - if (imag(x) == 0) { - vi_ = new vari(static_cast(real(x)), false); - } else { - std::stringstream ss; - ss << "Imaginary part of std::complex used to construct var" - << " must be zero. Found real part = " << real(x) << " and " - << " found imaginary part = " << imag(x) << std::endl; - std::string msg = ss.str(); - throw std::invalid_argument(msg); - } - } - - /** - * Construct a variable from the specified arithmetic argument - * by constructing a new vari with the argument - * cast to double, and a zero adjoint. Only works - * if the imaginary part is zero. - * - * @param x Value of the variable. - */ - explicit var(const std::complex& x) { - if (imag(x) == 0) { - vi_ = new vari(static_cast(real(x)), false); - } else { - std::stringstream ss; - ss << "Imaginary part of std::complex used to construct var" - << " must be zero. Found real part = " << real(x) << " and " - << " found imaginary part = " << imag(x) << std::endl; - std::string msg = ss.str(); - throw std::invalid_argument(msg); - } - } - #ifdef _WIN64 - // these two ctors are for Win64 to enable 64-bit signed // and unsigned integers, because long and unsigned long // are still 32-bit diff --git a/test/unit/math/mix/core/operator_addition_test.cpp b/test/unit/math/mix/core/operator_addition_test.cpp index 5fce58a166d..62bb8d0f189 100644 --- a/test/unit/math/mix/core/operator_addition_test.cpp +++ b/test/unit/math/mix/core/operator_addition_test.cpp @@ -1,7 +1,10 @@ +#include +#include #include TEST(mathMixCore, operatorAddition) { auto f = [](const auto& x1, const auto& x2) { return x1 + x2; }; bool disable_lhs_int = true; stan::test::expect_common_binary(f, disable_lhs_int); + stan::test::expect_complex_common_binary(f); } diff --git a/test/unit/math/mix/core/operator_subtraction_test.cpp b/test/unit/math/mix/core/operator_subtraction_test.cpp index c657571210b..0cb0efd11cb 100644 --- a/test/unit/math/mix/core/operator_subtraction_test.cpp +++ b/test/unit/math/mix/core/operator_subtraction_test.cpp @@ -4,4 +4,5 @@ TEST(mathMixCore, operatorSubtraction) { auto f = [](const auto& x1, const auto& x2) { return x1 - x2; }; bool disable_lhs_int = true; stan::test::expect_common_binary(f, disable_lhs_int); + stan::test::expect_complex_common_binary(f); } diff --git a/test/unit/math/test_ad.hpp b/test/unit/math/test_ad.hpp index 12d3cf9d235..96a8dbbc062 100644 --- a/test/unit/math/test_ad.hpp +++ b/test/unit/math/test_ad.hpp @@ -1751,7 +1751,7 @@ void expect_complex_common_binary(const F& f) { auto zs = common_complex(); for (auto z1 : zs) { for (auto z2 : zs) { - test_ad(f, z1, z2); + expect_ad(f, z1, z2); } } } From 4b07ef76054566dd75999e568f0236895f147e08 Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Sun, 1 Mar 2020 19:38:15 -0500 Subject: [PATCH 04/63] complex operator/ and operator* --- stan/math/prim/core.hpp | 2 + stan/math/prim/core/operator_division.hpp | 76 +++++++++++++++++++ .../prim/core/operator_multiplication.hpp | 76 +++++++++++++++++++ .../math/mix/core/operator_division_test.cpp | 13 ++++ .../mix/core/operator_multiplication_test.cpp | 1 + 5 files changed, 168 insertions(+) create mode 100644 stan/math/prim/core/operator_division.hpp create mode 100644 stan/math/prim/core/operator_multiplication.hpp diff --git a/stan/math/prim/core.hpp b/stan/math/prim/core.hpp index ec899aa2629..f42e6ad127a 100644 --- a/stan/math/prim/core.hpp +++ b/stan/math/prim/core.hpp @@ -3,6 +3,8 @@ #include #include +#include +#include #include #endif diff --git a/stan/math/prim/core/operator_division.hpp b/stan/math/prim/core/operator_division.hpp new file mode 100644 index 00000000000..5f5a81c22f5 --- /dev/null +++ b/stan/math/prim/core/operator_division.hpp @@ -0,0 +1,76 @@ +#ifndef STAN_MATH_PRIM_CORE_OPERATOR_DIVISION_HPP +#define STAN_MATH_PRIM_CORE_OPERATOR_DIVISION_HPP + +#include +#include +#include + +namespace stan { +namespace math { + +namespace internal { +/** + * Return the quotient of the specified arguments. At least one of the + * arguments must be a complex number. + * + * @tparam U type of first argumentx + * @tparam V type of second argument + * @param[in] lhs first argument + * @param[in] rhs second argument + * @return quotient of the arguments + */ +template +inline complex_return_t complex_divide(const U& lhs, const V& rhs) { + complex_return_t y(lhs); + y /= rhs; + return y; +} +} // namespace internal + +/** + * Return the quotient of the arguments. + * + * @tparam U value type of first argument + * @tparam V value type of second argument + * @param x first argument + * @param y second argument + * @return quotient of the arguments + */ +template +inline complex_return_t operator/(const std::complex& x, + const std::complex& y) { + return internal::complex_divide(x, y); +} + +/** + * Return the quotient of the arguments. + * + * @tparam U value type of first argument + * @tparam V type of second argument + * @param x first argument + * @param y second argument + * @return quotient of the arguments + */ +template +inline complex_return_t operator/(const std::complex& x, const V& y) { + return internal::complex_divide(x, y); +} + +/** + * Return the quotient of the arguments. + * + * @tparam U type of first argument + * @tparam V value type of second argument + * @param x first argument + * @param y second argument + * @return quotient of the arguments + */ +template +inline complex_return_t operator/(const U& x, const std::complex& y) { + return internal::complex_divide(x, y); +} + +} // namespace math +} // namespace stan + +#endif diff --git a/stan/math/prim/core/operator_multiplication.hpp b/stan/math/prim/core/operator_multiplication.hpp new file mode 100644 index 00000000000..9bb7d0a32e2 --- /dev/null +++ b/stan/math/prim/core/operator_multiplication.hpp @@ -0,0 +1,76 @@ +#ifndef STAN_MATH_PRIM_CORE_OPERATOR_MULTIPLICATION_HPP +#define STAN_MATH_PRIM_CORE_OPERATOR_MULTIPLICATION_HPP + +#include +#include +#include + +namespace stan { +namespace math { + +namespace internal { +/** + * Return the product of the specified arguments. At least one of the + * arguments must be a complex number. + * + * @tparam U type of first argumentx + * @tparam V type of second argument + * @param[in] lhs first argument + * @param[in] rhs second argument + * @return product of the arguments + */ +template +inline complex_return_t complex_multiply(const U& lhs, const V& rhs) { + complex_return_t y(lhs); + y *= rhs; + return y; +} +} // namespace internal + +/** + * Return the product of the arguments. + * + * @tparam U value type of first argument + * @tparam V value type of second argument + * @param x first argument + * @param y second argument + * @return product of the arguments + */ +template +inline complex_return_t operator*(const std::complex& x, + const std::complex& y) { + return internal::complex_multiply(x, y); +} + +/** + * Return the product of the arguments. + * + * @tparam U value type of first argument + * @tparam V type of second argument + * @param x first argument + * @param y second argument + * @return product of the arguments + */ +template +inline complex_return_t operator*(const std::complex& x, const V& y) { + return internal::complex_multiply(x, y); +} + +/** + * Return the product of the arguments. + * + * @tparam U type of first argument + * @tparam V value type of second argument + * @param x first argument + * @param y second argument + * @return product of the arguments + */ +template +inline complex_return_t operator*(const U& x, const std::complex& y) { + return internal::complex_multiply(x, y); +} + +} // namespace math +} // namespace stan + +#endif diff --git a/test/unit/math/mix/core/operator_division_test.cpp b/test/unit/math/mix/core/operator_division_test.cpp index d61ec16afba..9193b24a7a8 100644 --- a/test/unit/math/mix/core/operator_division_test.cpp +++ b/test/unit/math/mix/core/operator_division_test.cpp @@ -4,4 +4,17 @@ TEST(mathMixCore, operatorDivision) { auto f = [](const auto& x1, const auto& x2) { return x1 / x2; }; bool disable_lhs_int = true; stan::test::expect_common_binary(f, disable_lhs_int); + + std::vector common_finite = {-2.9, -1, -0.0, 0.0, 1, 1.39}; + std::vector common_finite_nz = {-3.1, -1, 1, 2.7}; + for (auto re1 : common_finite) { + for (auto im1 : common_finite_nz) { + for (auto re2 : common_finite) { + for (auto im2 : common_finite_nz) { + stan::test::expect_ad(f, std::complex(re1, im1), + std::complex(re2, im2)); + } + } + } + } } diff --git a/test/unit/math/mix/core/operator_multiplication_test.cpp b/test/unit/math/mix/core/operator_multiplication_test.cpp index c752957c5fc..32b553f30d2 100644 --- a/test/unit/math/mix/core/operator_multiplication_test.cpp +++ b/test/unit/math/mix/core/operator_multiplication_test.cpp @@ -4,4 +4,5 @@ TEST(mathMixCore, operatorMultiplication) { auto f = [](const auto& x1, const auto& x2) { return x1 * x2; }; bool disable_lhs_int = true; stan::test::expect_common_binary(f, disable_lhs_int); + stan::test::expect_complex_common_binary(f); } From a4ee58ad659ec0b4a68ff0d630da982422855036 Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Sun, 1 Mar 2020 19:53:24 -0500 Subject: [PATCH 05/63] complex unary operator+ and operator- --- stan/math/prim/core.hpp | 2 ++ stan/math/prim/core/operator_addition.hpp | 2 -- stan/math/prim/core/operator_division.hpp | 2 -- stan/math/prim/core/operator_minus.hpp | 25 +++++++++++++++++++ .../prim/core/operator_multiplication.hpp | 2 -- stan/math/prim/core/operator_plus.hpp | 25 +++++++++++++++++++ stan/math/prim/core/operator_subtraction.hpp | 2 -- .../mix/core/operator_unary_minus_test.cpp | 1 + .../mix/core/operator_unary_plus_test.cpp | 1 + 9 files changed, 54 insertions(+), 8 deletions(-) create mode 100644 stan/math/prim/core/operator_minus.hpp create mode 100644 stan/math/prim/core/operator_plus.hpp diff --git a/stan/math/prim/core.hpp b/stan/math/prim/core.hpp index f42e6ad127a..1c2366a9146 100644 --- a/stan/math/prim/core.hpp +++ b/stan/math/prim/core.hpp @@ -4,7 +4,9 @@ #include #include #include +#include #include +#include #include #endif diff --git a/stan/math/prim/core/operator_addition.hpp b/stan/math/prim/core/operator_addition.hpp index fc7f210b518..34799f8b936 100644 --- a/stan/math/prim/core/operator_addition.hpp +++ b/stan/math/prim/core/operator_addition.hpp @@ -1,8 +1,6 @@ #ifndef STAN_MATH_PRIM_CORE_OPERATOR_ADDITION_HPP #define STAN_MATH_PRIM_CORE_OPERATOR_ADDITION_HPP -#include -#include #include namespace stan { diff --git a/stan/math/prim/core/operator_division.hpp b/stan/math/prim/core/operator_division.hpp index 5f5a81c22f5..07aa89ca577 100644 --- a/stan/math/prim/core/operator_division.hpp +++ b/stan/math/prim/core/operator_division.hpp @@ -1,8 +1,6 @@ #ifndef STAN_MATH_PRIM_CORE_OPERATOR_DIVISION_HPP #define STAN_MATH_PRIM_CORE_OPERATOR_DIVISION_HPP -#include -#include #include namespace stan { diff --git a/stan/math/prim/core/operator_minus.hpp b/stan/math/prim/core/operator_minus.hpp new file mode 100644 index 00000000000..e1b238aff5c --- /dev/null +++ b/stan/math/prim/core/operator_minus.hpp @@ -0,0 +1,25 @@ +#ifndef STAN_MATH_PRIM_CORE_OPERATOR_MINUS_HPP +#define STAN_MATH_PRIM_CORE_OPERATOR_MINUS_HPP + +#include +#include + +namespace stan { +namespace math { + +/** + * Return the negation of the argument. + * + * @tparam U value type argument + * @param x argument + * @return negation of the argument + */ +template > +inline std::complex operator-(const std::complex& x) { + return {-x.real(), -x.imag()}; +} + +} // namespace math +} // namespace stan + +#endif diff --git a/stan/math/prim/core/operator_multiplication.hpp b/stan/math/prim/core/operator_multiplication.hpp index 9bb7d0a32e2..523fa7e2f62 100644 --- a/stan/math/prim/core/operator_multiplication.hpp +++ b/stan/math/prim/core/operator_multiplication.hpp @@ -1,8 +1,6 @@ #ifndef STAN_MATH_PRIM_CORE_OPERATOR_MULTIPLICATION_HPP #define STAN_MATH_PRIM_CORE_OPERATOR_MULTIPLICATION_HPP -#include -#include #include namespace stan { diff --git a/stan/math/prim/core/operator_plus.hpp b/stan/math/prim/core/operator_plus.hpp new file mode 100644 index 00000000000..cee306e56b5 --- /dev/null +++ b/stan/math/prim/core/operator_plus.hpp @@ -0,0 +1,25 @@ +#ifndef STAN_MATH_PRIM_CORE_OPERATOR_PLUS_HPP +#define STAN_MATH_PRIM_CORE_OPERATOR_PLUS_HPP + +#include +#include + +namespace stan { +namespace math { + +/** + * Return the argument. + * + * @tparam U value type argument + * @param x argument + * @return argument + */ +template > +inline std::complex operator+(const std::complex& x) { + return x; +} + +} // namespace math +} // namespace stan + +#endif diff --git a/stan/math/prim/core/operator_subtraction.hpp b/stan/math/prim/core/operator_subtraction.hpp index da6f8fa7076..4c4cc938308 100644 --- a/stan/math/prim/core/operator_subtraction.hpp +++ b/stan/math/prim/core/operator_subtraction.hpp @@ -1,8 +1,6 @@ #ifndef STAN_MATH_PRIM_CORE_OPERATOR_SUBTRACTION_HPP #define STAN_MATH_PRIM_CORE_OPERATOR_SUBTRACTION_HPP -#include -#include #include namespace stan { diff --git a/test/unit/math/mix/core/operator_unary_minus_test.cpp b/test/unit/math/mix/core/operator_unary_minus_test.cpp index 80e5b242d74..6e650963f74 100644 --- a/test/unit/math/mix/core/operator_unary_minus_test.cpp +++ b/test/unit/math/mix/core/operator_unary_minus_test.cpp @@ -3,4 +3,5 @@ TEST(mathMixCore, operatorUnaryMinus) { auto f = [](const auto& x1) { return -x1; }; stan::test::expect_common_unary(f); + stan::test::expect_complex_common(f); } diff --git a/test/unit/math/mix/core/operator_unary_plus_test.cpp b/test/unit/math/mix/core/operator_unary_plus_test.cpp index a61674f3f5b..450fa549da7 100644 --- a/test/unit/math/mix/core/operator_unary_plus_test.cpp +++ b/test/unit/math/mix/core/operator_unary_plus_test.cpp @@ -3,4 +3,5 @@ TEST(mathMixCore, operatorUnaryPlus) { auto f = [](const auto& x1) { return +x1; }; stan::test::expect_common_unary(f); + stan::test::expect_complex_common(f); } From e010c0c7ebbef30f67c05347af4092746727f4ab Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Sun, 1 Mar 2020 20:47:21 -0500 Subject: [PATCH 06/63] complex operator== and operator!= --- stan/math/prim/core.hpp | 2 + stan/math/prim/core/operator_equal_equal.hpp | 59 ++++++++++++++++++ stan/math/prim/core/operator_not_equal.hpp | 60 +++++++++++++++++++ .../math/mix/core/operator_equal_test.cpp | 1 + .../math/mix/core/operator_not_equal_test.cpp | 1 + test/unit/math/test_ad.hpp | 43 ++++++++++++- 6 files changed, 163 insertions(+), 3 deletions(-) create mode 100644 stan/math/prim/core/operator_equal_equal.hpp create mode 100644 stan/math/prim/core/operator_not_equal.hpp diff --git a/stan/math/prim/core.hpp b/stan/math/prim/core.hpp index 1c2366a9146..3a96e419fd6 100644 --- a/stan/math/prim/core.hpp +++ b/stan/math/prim/core.hpp @@ -4,8 +4,10 @@ #include #include #include +#include #include #include +#include #include #include diff --git a/stan/math/prim/core/operator_equal_equal.hpp b/stan/math/prim/core/operator_equal_equal.hpp new file mode 100644 index 00000000000..17334283674 --- /dev/null +++ b/stan/math/prim/core/operator_equal_equal.hpp @@ -0,0 +1,59 @@ +#ifndef STAN_MATH_PRIM_CORE_OPERATOR_EQUAL_EQUAL_HPP +#define STAN_MATH_PRIM_CORE_OPERATOR_EQUAL_EQUAL_HPP + +#include +#include + +namespace stan { +namespace math { + +/** + * Return `true` if the complex numbers have equal imaginary and + * complex parts. + * + * @tparam U value type of first argument + * @tparam V value type of second argument + * @param x first argument + * @param y second argument + * @return `true` if the arguments are equal + */ +template > +inline bool operator==(const std::complex& x, const std::complex& y) { + return x.real() == y.real() && x.imag() == y.imag(); +} + +/** + * Return `true` if the first argument's real part is equal to the + * second argument and the first argument's imaginary part is zero. + * + * @tparam U value type of first argument + * @tparam V type of second argument + * @param x first argument + * @param y second argument + * @return `true` if the arguments are equal + */ +template > +inline bool operator==(const std::complex& x, const V& y) { + return x.real() == y && x.imag() == 0; +} + +/** + * Return `true` if the first argument is equal to the real part of + * the second argument and the imaginary part of the second argument + * is zero. + * + * @tparam U type of first argument + * @tparam V value type of second argument + * @param x first argument + * @param y second argument + * @return `true` if the arguments are equal + */ +template > +inline bool operator==(const U& x, const std::complex& y) { + return x == y.real() && 0 == y.imag(); +} + +} // namespace math +} // namespace stan + +#endif diff --git a/stan/math/prim/core/operator_not_equal.hpp b/stan/math/prim/core/operator_not_equal.hpp new file mode 100644 index 00000000000..a3dc733ed51 --- /dev/null +++ b/stan/math/prim/core/operator_not_equal.hpp @@ -0,0 +1,60 @@ +#ifndef STAN_MATH_PRIM_CORE_OPERATOR_NOT_EQUAL_HPP +#define STAN_MATH_PRIM_CORE_OPERATOR_NOT_EQUAL_HPP + +#include +#include + +namespace stan { +namespace math { + +/** + * Return `true` if the complex numbers have unequal imaginary or + * complex parts. + * + * @tparam U value type of first argument + * @tparam V value type of second argument + * @param x first argument + * @param y second argument + * @return `true` if the arguments are equal + */ +template > +inline bool operator!=(const std::complex& x, const std::complex& y) { + return !(x.real() == y.real() && x.imag() == y.imag()); +} + +/** + * Return `true` if the first argument's real part is unequal to the + * second argument or the first argument's imaginary part is unequal + * to zero. + * + * @tparam U value type of first argument + * @tparam V type of second argument + * @param x first argument + * @param y second argument + * @return `true` if the arguments are equal + */ +template > +inline bool operator!=(const std::complex& x, const V& y) { + return !(x.real() == y && x.imag() == 0); +} + +/** + * Return `true` if the first argument is unequal to the real part of + * the second argument or the imaginary part of the second argument + * is nonzero. + * + * @tparam U type of first argument + * @tparam V value type of second argument + * @param x first argument + * @param y second argument + * @return `true` if the arguments are not equal + */ +template > +inline bool operator!=(const U& x, const std::complex& y) { + return !(x == y.real() && 0 == y.imag()); +} + +} // namespace math +} // namespace stan + +#endif diff --git a/test/unit/math/mix/core/operator_equal_test.cpp b/test/unit/math/mix/core/operator_equal_test.cpp index 9c425a468e9..d3ebdace1b7 100644 --- a/test/unit/math/mix/core/operator_equal_test.cpp +++ b/test/unit/math/mix/core/operator_equal_test.cpp @@ -3,4 +3,5 @@ TEST(mathMixCore, operatorEqual) { auto f = [](const auto& x1, const auto& x2) { return x1 == x2; }; stan::test::expect_common_comparison(f); + stan::test::expect_complex_common_comparison(f); } diff --git a/test/unit/math/mix/core/operator_not_equal_test.cpp b/test/unit/math/mix/core/operator_not_equal_test.cpp index 37b998fba20..0289a031f7c 100644 --- a/test/unit/math/mix/core/operator_not_equal_test.cpp +++ b/test/unit/math/mix/core/operator_not_equal_test.cpp @@ -3,4 +3,5 @@ TEST(mathMixCore, operatorNotEqual) { auto f = [](const auto& x1, const auto& x2) { return x1 != x2; }; stan::test::expect_common_comparison(f); + stan::test::expect_complex_common_comparison(f); } diff --git a/test/unit/math/test_ad.hpp b/test/unit/math/test_ad.hpp index 96a8dbbc062..174336d0d94 100644 --- a/test/unit/math/test_ad.hpp +++ b/test/unit/math/test_ad.hpp @@ -1721,9 +1721,6 @@ auto ldlt_factor(const Eigen::Matrix& x) { return ldlt_x; } -/** - * Return the - */ std::vector common_complex_parts() { double inf = std::numeric_limits::infinity(); double nan = std::numeric_limits::quiet_NaN(); @@ -1756,6 +1753,46 @@ void expect_complex_common_binary(const F& f) { } } +template +void expect_complex_compare(const F& f, const std::complex& z1, + const std::complex& z2) { + using c_t = std::complex; + EXPECT_EQ(f(z1, z2), f(c_t(z1), z2)); + EXPECT_EQ(f(z1, z2), f(z1, c_t(z2))); + EXPECT_EQ(f(z1, z2), f(c_t(z1), c_t(z2))); + + EXPECT_EQ(f(z1.real(), z2), f(T(z1.real()), z2)); + EXPECT_EQ(f(z1.real(), z2), f(z1.real(), c_t(z2))); + EXPECT_EQ(f(z1.real(), z2), f(T(z1.real()), c_t(z2))); + + EXPECT_EQ(f(z1, z2.real()), f(c_t(z1), z2.real())); + EXPECT_EQ(f(z1, z2.real()), f(z1, T(z2.real()))); + EXPECT_EQ(f(z1, z2.real()), f(c_t(z1), T(z2.real()))); +} + +template +void expect_complex_comparison(const F& f, const std::complex& z1, + const std::complex& z2) { + using stan::math::fvar; + using stan::math::var; + using std::complex; + expect_complex_compare(f, z1, z2); + expect_complex_compare(f, z1, z2); + // expect_complex_compare>>(f, z1, z2); + // expect_complex_compare>>>(f, z1, z2); + // expect_complex_compare>>(f, z1, z2); + // expect_complex_compare>>>(f, z1, z2); +} + +template +void expect_complex_common_comparison(const F& f) { + for (auto z1 : common_complex()) { + for (auto z2 : common_complex()) { + expect_complex_comparison(f, z1, z2); + } + } +} + // template // void expect_reduction(const F& f) { // cvar_t x(1, 2); From 46e822ab091b8a9afe1f7be31dd4655b7ad78c7e Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Tue, 3 Mar 2020 20:41:13 -0500 Subject: [PATCH 07/63] complex imag and real functions --- stan/math/prim/fun/imag.hpp | 25 +++++++++++++++++++++++++ stan/math/prim/fun/real.hpp | 25 +++++++++++++++++++++++++ test/unit/math/mix/fun/imag_test.cpp | 6 ++++++ test/unit/math/mix/fun/real_test.cpp | 6 ++++++ 4 files changed, 62 insertions(+) create mode 100644 stan/math/prim/fun/imag.hpp create mode 100644 stan/math/prim/fun/real.hpp create mode 100644 test/unit/math/mix/fun/imag_test.cpp create mode 100644 test/unit/math/mix/fun/real_test.cpp diff --git a/stan/math/prim/fun/imag.hpp b/stan/math/prim/fun/imag.hpp new file mode 100644 index 00000000000..b5b89e6fe27 --- /dev/null +++ b/stan/math/prim/fun/imag.hpp @@ -0,0 +1,25 @@ +#ifndef STAN_MATH_PRIM_FUN_IMAG_HPP +#define STAN_MATH_PRIM_FUN_IMAG_HPP + +#include +#include + +namespace stan { +namespace math { + +/** + * Return the real part of the complex argument. + * + * @tparam T value type of argument + * @param[in] z argument + * @return real part of argument + */ +template > +T imag(const std::complex& z) { + return z.imag(); +} + +} // namespace math +} // namespace stan + +#endif diff --git a/stan/math/prim/fun/real.hpp b/stan/math/prim/fun/real.hpp new file mode 100644 index 00000000000..a14c0d404d0 --- /dev/null +++ b/stan/math/prim/fun/real.hpp @@ -0,0 +1,25 @@ +#ifndef STAN_MATH_PRIM_FUN_REAL_HPP +#define STAN_MATH_PRIM_FUN_REAL_HPP + +#include +#include + +namespace stan { +namespace math { + +/** + * Return the real part of the complex argument. + * + * @tparam T value type of argument + * @param[in] z argument + * @return real part of argument + */ +template > +T real(const std::complex& z) { + return z.real(); +} + +} // namespace math +} // namespace stan + +#endif diff --git a/test/unit/math/mix/fun/imag_test.cpp b/test/unit/math/mix/fun/imag_test.cpp new file mode 100644 index 00000000000..195cb6f5c65 --- /dev/null +++ b/test/unit/math/mix/fun/imag_test.cpp @@ -0,0 +1,6 @@ +#include + +TEST(mathMixMatFun, imag) { + auto f = [](const auto& z) { return imag(z); }; + stan::test::expect_complex_common(f); +} diff --git a/test/unit/math/mix/fun/real_test.cpp b/test/unit/math/mix/fun/real_test.cpp new file mode 100644 index 00000000000..94be5b39e52 --- /dev/null +++ b/test/unit/math/mix/fun/real_test.cpp @@ -0,0 +1,6 @@ +#include + +TEST(mathMixMatFun, real) { + auto f = [](const auto& z) { return real(z); }; + stan::test::expect_complex_common(f); +} From 3148153524490e4a5366487c701ccce77f97de81 Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Tue, 3 Mar 2020 20:41:28 -0500 Subject: [PATCH 08/63] asinh, but won't pass until log etc in --- stan/math/fwd/fun/asinh.hpp | 6 ++++++ stan/math/prim/fun.hpp | 2 ++ stan/math/prim/fun/asinh.hpp | 19 +++++++++++++++++++ stan/math/prim/fun/value_of_rec.hpp | 13 +++++++++++++ stan/math/rev/fun/asinh.hpp | 5 +++++ test/unit/math/mix/fun/asinh_test.cpp | 24 +++++++++++++++++++++--- 6 files changed, 66 insertions(+), 3 deletions(-) diff --git a/stan/math/fwd/fun/asinh.hpp b/stan/math/fwd/fun/asinh.hpp index 7a4b0df5693..b820ba73827 100644 --- a/stan/math/fwd/fun/asinh.hpp +++ b/stan/math/fwd/fun/asinh.hpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace stan { namespace math { @@ -16,6 +17,11 @@ inline fvar asinh(const fvar& x) { return fvar(asinh(x.val_), x.d_ / sqrt(square(x.val_) + 1)); } +template +inline std::complex> asinh(const std::complex>& z) { + return internal::complex_asinh(z); +} + } // namespace math } // namespace stan #endif diff --git a/stan/math/prim/fun.hpp b/stan/math/prim/fun.hpp index ccffa08c6ce..ea508fec5dc 100644 --- a/stan/math/prim/fun.hpp +++ b/stan/math/prim/fun.hpp @@ -117,6 +117,7 @@ #include #include #include +#include #include #include #include @@ -243,6 +244,7 @@ #include #include #include +#include #include #include #include diff --git a/stan/math/prim/fun/asinh.hpp b/stan/math/prim/fun/asinh.hpp index 83e301b0ca2..ff725ea8ba5 100644 --- a/stan/math/prim/fun/asinh.hpp +++ b/stan/math/prim/fun/asinh.hpp @@ -2,7 +2,10 @@ #define STAN_MATH_PRIM_FUN_ASINH_HPP #include +#include +#include #include +#include namespace stan { namespace math { @@ -52,6 +55,22 @@ inline auto asinh(const T& x) { return apply_scalar_unary::apply(x); } +namespace internal { +/** + * Return the hyperbolic arc sine of the complex argument. + * + * @tparam V value type of argument + * @param[in] z argument + * @return hyperbolic arc sine of the argument + */ +template +inline std::complex complex_asinh(const std::complex& z) { + std::complex y_d = asinh(value_of_rec(z)); + auto y = log(z + sqrt(1 + z * z)); + return copysign(y, y_d); +} +} // namespace internal + } // namespace math } // namespace stan diff --git a/stan/math/prim/fun/value_of_rec.hpp b/stan/math/prim/fun/value_of_rec.hpp index c6f4fd1ab9c..8f6ee17deb6 100644 --- a/stan/math/prim/fun/value_of_rec.hpp +++ b/stan/math/prim/fun/value_of_rec.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -42,6 +43,18 @@ inline double value_of_rec(const T x) { */ inline double value_of_rec(double x) { return x; } +/** + * Recursively apply value-of to the parts of the argument. + * + * @tparam T value type of argument + * @param[in] x argument + * @return real complex value of argument + */ +template +inline std::complex value_of_rec(const std::complex& x) { + return {value_of_rec(x.real()), value_of_rec(x.imag())}; +} + /** * Convert a std::vector of type T to a std::vector of doubles. * diff --git a/stan/math/rev/fun/asinh.hpp b/stan/math/rev/fun/asinh.hpp index bbcfbb9f78a..d16abf9c4e7 100644 --- a/stan/math/rev/fun/asinh.hpp +++ b/stan/math/rev/fun/asinh.hpp @@ -5,6 +5,7 @@ #include #include #include +#include namespace stan { namespace math { @@ -56,6 +57,10 @@ inline var asinh(const var& a) { return var(new internal::asinh_vari(asinh(a.val()), a.vi_)); } +inline std::complex asinh(const std::complex& z) { + return internal::complex_asinh(z); +} + } // namespace math } // namespace stan #endif diff --git a/test/unit/math/mix/fun/asinh_test.cpp b/test/unit/math/mix/fun/asinh_test.cpp index 9e4c518bdff..231c5ea5138 100644 --- a/test/unit/math/mix/fun/asinh_test.cpp +++ b/test/unit/math/mix/fun/asinh_test.cpp @@ -1,7 +1,25 @@ #include -TEST(mathMixMatFun, asinh) { +TEST(mathMixFun, asinh) { auto f = [](const auto& x1) { return stan::math::asinh(x1); }; - stan::test::expect_common_unary_vectorized(f); - stan::test::expect_unary_vectorized(f, -2.6, -1.2, -0.2, 0.5, 2, -1.2); + // stan::test::expect_common_unary_vectorized(f); + // stan::test::expect_unary_vectorized(f, -2.6, -1.2, -0.2, 0.5, 2, -1.2); + // stan::test::expect_complex_common(f); +} + +TEST(mathMixFun, asinhComplex) { + auto f = [](const auto& z) { return asinh(z); }; + stan::test::ad_tolerances tols; + tols.hessian_hessian_ = 1e-2; + tols.hessian_fvar_hessian_ = 1e-2; + // for (double re : std::vector{-1.1, 2.9}) { + // for (double im : std::vector{-1.1, 2.9}) { + // stan::test::expect_ad(tols, f, std::complex{re, im}); + // } + // } + // stan::test::expect_ad(tols, f, std::complex{1.1, -1.3}); + // stan::test::expect_ad(tols, f, std::complex{-1.1, -1.3}); + stan::test::expect_ad(tols, f, std::complex{0.1, 0.1}); + + stan::test::expect_complex_common(f); } From 472641cf24276b7403f7cac2472b117b798880c3 Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Tue, 3 Mar 2020 21:35:55 -0500 Subject: [PATCH 09/63] complex abs --- stan/math/fwd/fun/abs.hpp | 15 ++++++++++++++- stan/math/fwd/fun/asinh.hpp | 8 ++++---- stan/math/prim/fun/abs.hpp | 15 +++++++++++++++ stan/math/prim/fun/asinh.hpp | 30 ++++++++++++++--------------- stan/math/prim/fun/imag.hpp | 4 ++-- stan/math/rev/fun/abs.hpp | 12 ++++++++++++ stan/math/rev/fun/asinh.hpp | 6 +++--- test/unit/math/mix/fun/abs_test.cpp | 15 ++++++++++++++- test/unit/math/test_ad.hpp | 10 ++++------ 9 files changed, 83 insertions(+), 32 deletions(-) diff --git a/stan/math/fwd/fun/abs.hpp b/stan/math/fwd/fun/abs.hpp index f52c49482da..ffd21791ff0 100644 --- a/stan/math/fwd/fun/abs.hpp +++ b/stan/math/fwd/fun/abs.hpp @@ -3,9 +3,10 @@ #include #include -#include #include +#include #include +#include namespace stan { namespace math { @@ -23,6 +24,18 @@ inline fvar abs(const fvar& x) { } } +/** + * Return the absolute value of the complex argument. + * + * @tparam T value type of argument + * @param[in] z argument + * @return absolute value of the argument + */ +template +inline std::complex> abs(const std::complex>& z) { + return internal::complex_abs(z); +} + } // namespace math } // namespace stan #endif diff --git a/stan/math/fwd/fun/asinh.hpp b/stan/math/fwd/fun/asinh.hpp index b820ba73827..6d90484d8d7 100644 --- a/stan/math/fwd/fun/asinh.hpp +++ b/stan/math/fwd/fun/asinh.hpp @@ -17,10 +17,10 @@ inline fvar asinh(const fvar& x) { return fvar(asinh(x.val_), x.d_ / sqrt(square(x.val_) + 1)); } -template -inline std::complex> asinh(const std::complex>& z) { - return internal::complex_asinh(z); -} +// template +// inline std::complex> asinh(const std::complex>& z) { +// return internal::complex_asinh(z); +// } } // namespace math } // namespace stan diff --git a/stan/math/prim/fun/abs.hpp b/stan/math/prim/fun/abs.hpp index cdf0a52dcd6..4a4d76350c4 100644 --- a/stan/math/prim/fun/abs.hpp +++ b/stan/math/prim/fun/abs.hpp @@ -2,6 +2,7 @@ #define STAN_MATH_PRIM_FUN_ABS_HPP #include +#include #include namespace stan { @@ -18,6 +19,20 @@ namespace math { */ inline double abs(double x) { return std::fabs(x); } +namespace internal { +/** + * Return the absolute value of the complex argument. + * + * @tparam V value type of argument + * @param[in] z argument + * @return absolute value of the argument + */ +template +inline V complex_abs(const std::complex& z) { + return hypot(z.real(), z.imag()); +} +} // namespace internal + } // namespace math } // namespace stan diff --git a/stan/math/prim/fun/asinh.hpp b/stan/math/prim/fun/asinh.hpp index ff725ea8ba5..c195a61f86a 100644 --- a/stan/math/prim/fun/asinh.hpp +++ b/stan/math/prim/fun/asinh.hpp @@ -55,21 +55,21 @@ inline auto asinh(const T& x) { return apply_scalar_unary::apply(x); } -namespace internal { -/** - * Return the hyperbolic arc sine of the complex argument. - * - * @tparam V value type of argument - * @param[in] z argument - * @return hyperbolic arc sine of the argument - */ -template -inline std::complex complex_asinh(const std::complex& z) { - std::complex y_d = asinh(value_of_rec(z)); - auto y = log(z + sqrt(1 + z * z)); - return copysign(y, y_d); -} -} // namespace internal +// namespace internal { +// /** +// * Return the hyperbolic arc sine of the complex argument. +// * +// * @tparam V value type of argument +// * @param[in] z argument +// * @return hyperbolic arc sine of the argument +// */ +// template +// inline std::complex complex_asinh(const std::complex& z) { +// std::complex y_d = asinh(value_of_rec(z)); +// auto y = log(z + sqrt(1 + z * z)); +// return copysign(y, y_d); +// } +// } // namespace internal } // namespace math } // namespace stan diff --git a/stan/math/prim/fun/imag.hpp b/stan/math/prim/fun/imag.hpp index b5b89e6fe27..f6aed7b3778 100644 --- a/stan/math/prim/fun/imag.hpp +++ b/stan/math/prim/fun/imag.hpp @@ -8,11 +8,11 @@ namespace stan { namespace math { /** - * Return the real part of the complex argument. + * Return the imaginary part of the complex argument. * * @tparam T value type of argument * @param[in] z argument - * @return real part of argument + * @return imaginary part of argument */ template > T imag(const std::complex& z) { diff --git a/stan/math/rev/fun/abs.hpp b/stan/math/rev/fun/abs.hpp index 9aad50f2865..74cb0ddf81d 100644 --- a/stan/math/rev/fun/abs.hpp +++ b/stan/math/rev/fun/abs.hpp @@ -1,8 +1,10 @@ #ifndef STAN_MATH_REV_FUN_ABS_HPP #define STAN_MATH_REV_FUN_ABS_HPP +#include #include #include +#include namespace stan { namespace math { @@ -35,6 +37,16 @@ namespace math { */ inline var abs(const var& a) { return fabs(a); } +/** + * Return the absolute value of the complex argument. + * + * @param[in] z argument + * @return absolute value of the argument + */ +inline std::complex abs(const std::complex& z) { + return internal::complex_abs(z); +} + } // namespace math } // namespace stan #endif diff --git a/stan/math/rev/fun/asinh.hpp b/stan/math/rev/fun/asinh.hpp index d16abf9c4e7..2ad76b5418e 100644 --- a/stan/math/rev/fun/asinh.hpp +++ b/stan/math/rev/fun/asinh.hpp @@ -57,9 +57,9 @@ inline var asinh(const var& a) { return var(new internal::asinh_vari(asinh(a.val()), a.vi_)); } -inline std::complex asinh(const std::complex& z) { - return internal::complex_asinh(z); -} +// inline std::complex asinh(const std::complex& z) { +// return internal::complex_asinh(z); +// } } // namespace math } // namespace stan diff --git a/test/unit/math/mix/fun/abs_test.cpp b/test/unit/math/mix/fun/abs_test.cpp index 19d43f75b00..13aff75221a 100644 --- a/test/unit/math/mix/fun/abs_test.cpp +++ b/test/unit/math/mix/fun/abs_test.cpp @@ -1,7 +1,8 @@ +#include #include TEST(mixScalFun, abs) { - auto f = [](const auto& x) { return stan::math::abs(x); }; + auto f = [](const auto& x) { return abs(x); }; stan::test::expect_common_nonzero_unary(f); stan::test::expect_value(f, 0); stan::test::expect_value(f, 0.0); @@ -15,4 +16,16 @@ TEST(mixScalFun, abs) { stan::test::expect_ad(f, 0.68); stan::test::expect_ad(f, 2.0); stan::test::expect_ad(f, 4.0); + + // not differentiable at zero + for (double re : + std::vector{-4, -2.5, -1.5, -0.3, -0.0, 0.0, 1.3, 2.1, 3.9}) { + for (double im : + std::vector{-4, -2.5, -1.5, -0.3, -0.0, 0.0, 1.3, 2.1, 3.9}) { + if ((re == 0.0 || re == -0.0) && (im == 0.0 || im == -0.0)) { + continue; + } + stan::test::expect_ad(f, std::complex(re, im)); + } + } } diff --git a/test/unit/math/test_ad.hpp b/test/unit/math/test_ad.hpp index 174336d0d94..d8b1d6bde4a 100644 --- a/test/unit/math/test_ad.hpp +++ b/test/unit/math/test_ad.hpp @@ -1722,8 +1722,6 @@ auto ldlt_factor(const Eigen::Matrix& x) { } std::vector common_complex_parts() { - double inf = std::numeric_limits::infinity(); - double nan = std::numeric_limits::quiet_NaN(); return {-4, -2.5, -1.5, -0.3, -0.0, 0.0, 1.3, 2.1, 3.9}; } @@ -1778,10 +1776,10 @@ void expect_complex_comparison(const F& f, const std::complex& z1, using std::complex; expect_complex_compare(f, z1, z2); expect_complex_compare(f, z1, z2); - // expect_complex_compare>>(f, z1, z2); - // expect_complex_compare>>>(f, z1, z2); - // expect_complex_compare>>(f, z1, z2); - // expect_complex_compare>>>(f, z1, z2); + expect_complex_compare>>(f, z1, z2); + expect_complex_compare>>>(f, z1, z2); + expect_complex_compare>>(f, z1, z2); + expect_complex_compare>>>(f, z1, z2); } template From 159ac3170da29afd194570d24ab5a71d6fa03d5d Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Tue, 3 Mar 2020 22:49:17 -0500 Subject: [PATCH 10/63] complex arg function --- stan/math/fwd/fun.hpp | 1 + stan/math/fwd/fun/arg.hpp | 27 +++++++++++++++++++++++++++ stan/math/prim/fun.hpp | 1 + stan/math/prim/fun/arg.hpp | 26 ++++++++++++++++++++++++++ stan/math/rev/fun.hpp | 1 + stan/math/rev/fun/arg.hpp | 23 +++++++++++++++++++++++ test/unit/math/mix/fun/abs_test.cpp | 3 ++- test/unit/math/mix/fun/arg_test.cpp | 15 +++++++++++++++ 8 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 stan/math/fwd/fun/arg.hpp create mode 100644 stan/math/prim/fun/arg.hpp create mode 100644 stan/math/rev/fun/arg.hpp create mode 100644 test/unit/math/mix/fun/arg_test.cpp diff --git a/stan/math/fwd/fun.hpp b/stan/math/fwd/fun.hpp index a717293aa07..2e6516ad59d 100644 --- a/stan/math/fwd/fun.hpp +++ b/stan/math/fwd/fun.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include diff --git a/stan/math/fwd/fun/arg.hpp b/stan/math/fwd/fun/arg.hpp new file mode 100644 index 00000000000..a2fbbf9195c --- /dev/null +++ b/stan/math/fwd/fun/arg.hpp @@ -0,0 +1,27 @@ +#ifndef STAN_MATH_FWD_FUN_ARG_HPP +#define STAN_MATH_FWD_FUN_ARG_HPP + +#include +#include +#include +#include + +namespace stan { +namespace math { + +/** + * Return the phase angle of the complex argument. + * + * @tparam T value type of autodiff variable + * @param[in] z argument + * @return phase angle of the argument + */ +template +inline fvar arg(const std::complex>& z) { + return internal::complex_arg(z); +} + +} // namespace math +} // namespace stan + +#endif diff --git a/stan/math/prim/fun.hpp b/stan/math/prim/fun.hpp index ea508fec5dc..565df7ec2af 100644 --- a/stan/math/prim/fun.hpp +++ b/stan/math/prim/fun.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/stan/math/prim/fun/arg.hpp b/stan/math/prim/fun/arg.hpp new file mode 100644 index 00000000000..e8d5029c904 --- /dev/null +++ b/stan/math/prim/fun/arg.hpp @@ -0,0 +1,26 @@ +#ifndef STAN_MATH_PRIM_FUN_ARG_HPP +#define STAN_MATH_PRIM_FUN_ARG_HPP + +#include +#include + +namespace stan { +namespace math { +namespace internal { +/** + * Return the phase angle of the complex argument. + * + * @tparam V value type of argument + * @param[in] z argument + * @return phase angle of the argument + */ +template +inline V complex_arg(const std::complex& z) { + using std::atan2; + return atan2(z.imag(), z.real()); +} +} // namespace internal +} // namespace math +} // namespace stan + +#endif diff --git a/stan/math/rev/fun.hpp b/stan/math/rev/fun.hpp index 1deb92f9738..8053a537a6b 100644 --- a/stan/math/rev/fun.hpp +++ b/stan/math/rev/fun.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/stan/math/rev/fun/arg.hpp b/stan/math/rev/fun/arg.hpp new file mode 100644 index 00000000000..81bd4c27417 --- /dev/null +++ b/stan/math/rev/fun/arg.hpp @@ -0,0 +1,23 @@ +#ifndef STAN_MATH_REV_FUN_ARG_HPP +#define STAN_MATH_REV_FUN_ARG_HPP + +#include +#include +#include +#include + +namespace stan { +namespace math { + +/** + * Return the phase angle of the complex argument. + * + * @param[in] z argument + * @return phase angle of the argument + */ +inline var arg(const std::complex& z) { return internal::complex_arg(z); } + +} // namespace math +} // namespace stan + +#endif diff --git a/test/unit/math/mix/fun/abs_test.cpp b/test/unit/math/mix/fun/abs_test.cpp index 13aff75221a..7316a5e0af6 100644 --- a/test/unit/math/mix/fun/abs_test.cpp +++ b/test/unit/math/mix/fun/abs_test.cpp @@ -1,5 +1,6 @@ -#include #include +#include +#include TEST(mixScalFun, abs) { auto f = [](const auto& x) { return abs(x); }; diff --git a/test/unit/math/mix/fun/arg_test.cpp b/test/unit/math/mix/fun/arg_test.cpp new file mode 100644 index 00000000000..9fe7b6dbd79 --- /dev/null +++ b/test/unit/math/mix/fun/arg_test.cpp @@ -0,0 +1,15 @@ +#include +#include +#include + +TEST(mixScalFun, arg) { + auto f = [](const auto& x) { return arg(x); }; + + // undefined with 0 in denominator + stan::test::expect_ad(f, std::complex(0.9, 0.8)); + for (double im : std::vector{-1.3, 2.3}) { + for (double re : std::vector{-3.6, -0.0, 0.0, 0.5}) { + stan::test::expect_ad(f, std::complex(re, im)); + } + } +} From 15de8023b7589b7141c5b1a6ca24e6ecb37b1677 Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Thu, 5 Mar 2020 11:24:37 -0500 Subject: [PATCH 11/63] complex norm and arg --- stan/math/fwd/fun.hpp | 1 + stan/math/fwd/fun/arg.hpp | 1 - stan/math/fwd/fun/norm.hpp | 26 ++++++++++++++++++++++++++ stan/math/prim/fun.hpp | 1 + stan/math/prim/fun/norm.hpp | 25 +++++++++++++++++++++++++ stan/math/rev/fun.hpp | 1 + stan/math/rev/fun/arg.hpp | 3 +-- stan/math/rev/fun/norm.hpp | 22 ++++++++++++++++++++++ test/unit/math/mix/fun/norm_test.cpp | 8 ++++++++ 9 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 stan/math/fwd/fun/norm.hpp create mode 100644 stan/math/prim/fun/norm.hpp create mode 100644 stan/math/rev/fun/norm.hpp create mode 100644 test/unit/math/mix/fun/norm_test.cpp diff --git a/stan/math/fwd/fun.hpp b/stan/math/fwd/fun.hpp index 5af652333d0..7c05a5fc2bb 100644 --- a/stan/math/fwd/fun.hpp +++ b/stan/math/fwd/fun.hpp @@ -83,6 +83,7 @@ #include #include #include +#include #include #include #include diff --git a/stan/math/fwd/fun/arg.hpp b/stan/math/fwd/fun/arg.hpp index a2fbbf9195c..89e3ae192ba 100644 --- a/stan/math/fwd/fun/arg.hpp +++ b/stan/math/fwd/fun/arg.hpp @@ -3,7 +3,6 @@ #include #include -#include #include namespace stan { diff --git a/stan/math/fwd/fun/norm.hpp b/stan/math/fwd/fun/norm.hpp new file mode 100644 index 00000000000..1de3e640223 --- /dev/null +++ b/stan/math/fwd/fun/norm.hpp @@ -0,0 +1,26 @@ +#ifndef STAN_MATH_FWD_FUN_NORM_HPP +#define STAN_MATH_FWD_FUN_NORM_HPP + +#include +#include +#include + +namespace stan { +namespace math { + +/** + * Return the squared magnitude of the complex argument. + * + * @tparam T value type of autodiff variable + * @param[in] z argument + * @return phase squared magnitude of the argument + */ +template +inline fvar norm(const std::complex>& z) { + return internal::complex_norm(z); +} + +} // namespace math +} // namespace stan + +#endif diff --git a/stan/math/prim/fun.hpp b/stan/math/prim/fun.hpp index 565df7ec2af..fd53d75756b 100644 --- a/stan/math/prim/fun.hpp +++ b/stan/math/prim/fun.hpp @@ -207,6 +207,7 @@ #include #include #include +#include #include #include #include diff --git a/stan/math/prim/fun/norm.hpp b/stan/math/prim/fun/norm.hpp new file mode 100644 index 00000000000..89fe76552f6 --- /dev/null +++ b/stan/math/prim/fun/norm.hpp @@ -0,0 +1,25 @@ +#ifndef STAN_MATH_PRIM_FUN_NORM_HPP +#define STAN_MATH_PRIM_FUN_NORM_HPP + +#include +#include + +namespace stan { +namespace math { +namespace internal { +/** + * Return the squared magnitude of the complex argument. + * + * @tparam V value type of argument + * @param[in] z argument + * @return squared magnitude of the argument + */ +template +inline V complex_norm(const std::complex& z) { + return square(z.real()) + square(z.imag()); +} +} // namespace internal +} // namespace math +} // namespace stan + +#endif diff --git a/stan/math/rev/fun.hpp b/stan/math/rev/fun.hpp index 8053a537a6b..8bafbfcf2ad 100644 --- a/stan/math/rev/fun.hpp +++ b/stan/math/rev/fun.hpp @@ -105,6 +105,7 @@ #include #include #include +#include #include #include #include diff --git a/stan/math/rev/fun/arg.hpp b/stan/math/rev/fun/arg.hpp index 81bd4c27417..e286ed34174 100644 --- a/stan/math/rev/fun/arg.hpp +++ b/stan/math/rev/fun/arg.hpp @@ -2,8 +2,7 @@ #define STAN_MATH_REV_FUN_ARG_HPP #include -#include -#include +#include #include namespace stan { diff --git a/stan/math/rev/fun/norm.hpp b/stan/math/rev/fun/norm.hpp new file mode 100644 index 00000000000..39ec4a7f9d7 --- /dev/null +++ b/stan/math/rev/fun/norm.hpp @@ -0,0 +1,22 @@ +#ifndef STAN_MATH_REV_FUN_NORM_HPP +#define STAN_MATH_REV_FUN_NORM_HPP + +#include +#include +#include + +namespace stan { +namespace math { + +/** + * Return the squared magnitude of the complex argument. + * + * @param[in] z argument + * @return squared magnitude of the argument + */ +inline var norm(const std::complex& z) { return internal::complex_norm(z); } + +} // namespace math +} // namespace stan + +#endif diff --git a/test/unit/math/mix/fun/norm_test.cpp b/test/unit/math/mix/fun/norm_test.cpp new file mode 100644 index 00000000000..306b52a01b8 --- /dev/null +++ b/test/unit/math/mix/fun/norm_test.cpp @@ -0,0 +1,8 @@ +#include +#include +#include + +TEST(mixScalFun, arg) { + auto f = [](const auto& x) { return norm(x); }; + stan::test::expect_complex_common(f); +} From 313f8c9f6af552be1ba531ab72f6fd1e3d2d5fbe Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Thu, 5 Mar 2020 11:36:04 -0500 Subject: [PATCH 12/63] complex conj --- stan/math/fwd/fun.hpp | 1 + stan/math/fwd/fun/conj.hpp | 26 ++++++++++++++++++++++++++ stan/math/prim/fun.hpp | 1 + stan/math/prim/fun/conj.hpp | 24 ++++++++++++++++++++++++ stan/math/rev/fun.hpp | 1 + stan/math/rev/fun/conj.hpp | 24 ++++++++++++++++++++++++ test/unit/math/mix/fun/conj_test.cpp | 8 ++++++++ test/unit/math/mix/fun/norm_test.cpp | 2 +- 8 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 stan/math/fwd/fun/conj.hpp create mode 100644 stan/math/prim/fun/conj.hpp create mode 100644 stan/math/rev/fun/conj.hpp create mode 100644 test/unit/math/mix/fun/conj_test.cpp diff --git a/stan/math/fwd/fun.hpp b/stan/math/fwd/fun.hpp index 7c05a5fc2bb..9074f716824 100644 --- a/stan/math/fwd/fun.hpp +++ b/stan/math/fwd/fun.hpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/stan/math/fwd/fun/conj.hpp b/stan/math/fwd/fun/conj.hpp new file mode 100644 index 00000000000..706d97d2678 --- /dev/null +++ b/stan/math/fwd/fun/conj.hpp @@ -0,0 +1,26 @@ +#ifndef STAN_MATH_FWD_FUN_CONJ_HPP +#define STAN_MATH_FWD_FUN_CONJ_HPP + +#include +#include +#include + +namespace stan { +namespace math { + +/** + * Return the phase angle of the complex argument. + * + * @tparam T value type of autodiff variable + * @param[in] z argument + * @return phase angle of the argument + */ +template +inline std::complex> conj(const std::complex>& z) { + return internal::complex_conj(z); +} + +} // namespace math +} // namespace stan + +#endif diff --git a/stan/math/prim/fun.hpp b/stan/math/prim/fun.hpp index fd53d75756b..f17a187ba15 100644 --- a/stan/math/prim/fun.hpp +++ b/stan/math/prim/fun.hpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include diff --git a/stan/math/prim/fun/conj.hpp b/stan/math/prim/fun/conj.hpp new file mode 100644 index 00000000000..a356cd0a9ee --- /dev/null +++ b/stan/math/prim/fun/conj.hpp @@ -0,0 +1,24 @@ +#ifndef STAN_MATH_PRIM_FUN_CONJ_HPP +#define STAN_MATH_PRIM_FUN_CONJ_HPP + +#include + +namespace stan { +namespace math { +namespace internal { +/** + * Return the complex conjugate the complex argument. + * + * @tparam V value type of argument + * @param[in] z argument + * @return complex conjugate of the argument + */ +template +inline std::complex complex_conj(const std::complex& z) { + return {z.real(), -z.imag()}; +} +} // namespace internal +} // namespace math +} // namespace stan + +#endif diff --git a/stan/math/rev/fun.hpp b/stan/math/rev/fun.hpp index 8bafbfcf2ad..81197b8cf46 100644 --- a/stan/math/rev/fun.hpp +++ b/stan/math/rev/fun.hpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include diff --git a/stan/math/rev/fun/conj.hpp b/stan/math/rev/fun/conj.hpp new file mode 100644 index 00000000000..2537f17c8e8 --- /dev/null +++ b/stan/math/rev/fun/conj.hpp @@ -0,0 +1,24 @@ +#ifndef STAN_MATH_REV_FUN_CONJ_HPP +#define STAN_MATH_REV_FUN_CONJ_HPP + +#include +#include +#include + +namespace stan { +namespace math { + +/** + * Return the complex conjugate of the complex argument. + * + * @param[in] z argument + * @return complex conjugate of the argument + */ +inline std::complex conj(const std::complex& z) { + return internal::complex_conj(z); +} + +} // namespace math +} // namespace stan + +#endif diff --git a/test/unit/math/mix/fun/conj_test.cpp b/test/unit/math/mix/fun/conj_test.cpp new file mode 100644 index 00000000000..877ced049c2 --- /dev/null +++ b/test/unit/math/mix/fun/conj_test.cpp @@ -0,0 +1,8 @@ +#include +#include +#include + +TEST(mixScalFun, conj) { + auto f = [](const auto& x) { return conj(x); }; + stan::test::expect_complex_common(f); +} diff --git a/test/unit/math/mix/fun/norm_test.cpp b/test/unit/math/mix/fun/norm_test.cpp index 306b52a01b8..9fec91afb6d 100644 --- a/test/unit/math/mix/fun/norm_test.cpp +++ b/test/unit/math/mix/fun/norm_test.cpp @@ -2,7 +2,7 @@ #include #include -TEST(mixScalFun, arg) { +TEST(mixScalFun, norm) { auto f = [](const auto& x) { return norm(x); }; stan::test::expect_complex_common(f); } From b2ff01ab9d2bda4d8bad886cfba0de354a025412 Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Thu, 5 Mar 2020 11:45:49 -0500 Subject: [PATCH 13/63] complex proj --- stan/math/fwd/fun.hpp | 1 + stan/math/fwd/fun/proj.hpp | 27 +++++++++++++++++++++++++++ stan/math/prim/fun.hpp | 1 + stan/math/prim/fun/proj.hpp | 28 ++++++++++++++++++++++++++++ stan/math/rev/fun.hpp | 1 + stan/math/rev/fun/proj.hpp | 25 +++++++++++++++++++++++++ test/unit/math/mix/fun/proj_test.cpp | 8 ++++++++ 7 files changed, 91 insertions(+) create mode 100644 stan/math/fwd/fun/proj.hpp create mode 100644 stan/math/prim/fun/proj.hpp create mode 100644 stan/math/rev/fun/proj.hpp create mode 100644 test/unit/math/mix/fun/proj_test.cpp diff --git a/stan/math/fwd/fun.hpp b/stan/math/fwd/fun.hpp index 9074f716824..194dccd688a 100644 --- a/stan/math/fwd/fun.hpp +++ b/stan/math/fwd/fun.hpp @@ -90,6 +90,7 @@ #include #include #include +#include #include #include #include diff --git a/stan/math/fwd/fun/proj.hpp b/stan/math/fwd/fun/proj.hpp new file mode 100644 index 00000000000..931d2dc4b72 --- /dev/null +++ b/stan/math/fwd/fun/proj.hpp @@ -0,0 +1,27 @@ +#ifndef STAN_MATH_FWD_FUN_PROJ_HPP +#define STAN_MATH_FWD_FUN_PROJ_HPP + +#include +#include +#include + +namespace stan { +namespace math { + +/** + * Return the projection of the complex argument onto the Riemann + * sphere. + * + * @tparam T value type of autodiff variable + * @param[in] z argument + * @return projection of the argument onto the Riemann sphere + */ +template +inline std::complex> proj(const std::complex>& z) { + return internal::complex_proj(z); +} + +} // namespace math +} // namespace stan + +#endif diff --git a/stan/math/prim/fun.hpp b/stan/math/prim/fun.hpp index f17a187ba15..6824193a663 100644 --- a/stan/math/prim/fun.hpp +++ b/stan/math/prim/fun.hpp @@ -233,6 +233,7 @@ #include #include #include +#include #include #include #include diff --git a/stan/math/prim/fun/proj.hpp b/stan/math/prim/fun/proj.hpp new file mode 100644 index 00000000000..3f1c99a396c --- /dev/null +++ b/stan/math/prim/fun/proj.hpp @@ -0,0 +1,28 @@ +#ifndef STAN_MATH_PRIM_FUN_PROJ_HPP +#define STAN_MATH_PRIM_FUN_PROJ_HPP + +#include + +namespace stan { +namespace math { +namespace internal { +/** + * Return the projection of the complex argument onto the Riemann + * sphere. + * + * @tparam V value type of argument + * @param[in] z argument + * @return projection of the argument onto the Riemann sphere + */ +template +inline std::complex complex_proj(const std::complex& z) { + if (is_inf(z.real()) || is_inf(z.imag())) { + return {std::numeric_limits::infinity(), z.imag() < 0 ? -0.0 : 0.0}; + } + return z; +} +} // namespace internal +} // namespace math +} // namespace stan + +#endif diff --git a/stan/math/rev/fun.hpp b/stan/math/rev/fun.hpp index 81197b8cf46..96e3e285dd8 100644 --- a/stan/math/rev/fun.hpp +++ b/stan/math/rev/fun.hpp @@ -112,6 +112,7 @@ #include #include #include +#include #include #include #include diff --git a/stan/math/rev/fun/proj.hpp b/stan/math/rev/fun/proj.hpp new file mode 100644 index 00000000000..e5797703e16 --- /dev/null +++ b/stan/math/rev/fun/proj.hpp @@ -0,0 +1,25 @@ +#ifndef STAN_MATH_REV_FUN_PROJ_HPP +#define STAN_MATH_REV_FUN_PROJ_HPP + +#include +#include +#include + +namespace stan { +namespace math { + +/** + * Return the projection of the complex argument onto the Riemann + * sphere. + * + * @param[in] z argument + * @return projection of the argument onto the Riemann sphere + */ +inline std::complex proj(const std::complex& z) { + return internal::complex_proj(z); +} + +} // namespace math +} // namespace stan + +#endif diff --git a/test/unit/math/mix/fun/proj_test.cpp b/test/unit/math/mix/fun/proj_test.cpp new file mode 100644 index 00000000000..ea0006cbc7c --- /dev/null +++ b/test/unit/math/mix/fun/proj_test.cpp @@ -0,0 +1,8 @@ +#include +#include +#include + +TEST(mixScalFun, proj) { + auto f = [](const auto& x) { return proj(x); }; + stan::test::expect_complex_common(f); +} From 7298cd62fac37770fe85778284a1b1759c6c525e Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Thu, 5 Mar 2020 13:04:33 -0500 Subject: [PATCH 14/63] complex exp --- stan/math/fwd/fun.hpp | 1 + stan/math/fwd/fun/exp.hpp | 15 ++++++-- stan/math/prim/fun.hpp | 1 + stan/math/prim/fun/exp.hpp | 76 +++++++++++++++++++------------------ stan/math/prim/fun/proj.hpp | 2 + stan/math/rev/fun.hpp | 1 + stan/math/rev/fun/exp.hpp | 11 ++++-- 7 files changed, 63 insertions(+), 44 deletions(-) diff --git a/stan/math/fwd/fun.hpp b/stan/math/fwd/fun.hpp index 194dccd688a..0d1cf962857 100644 --- a/stan/math/fwd/fun.hpp +++ b/stan/math/fwd/fun.hpp @@ -88,6 +88,7 @@ #include #include #include +#include #include #include #include diff --git a/stan/math/fwd/fun/exp.hpp b/stan/math/fwd/fun/exp.hpp index 6aaf2e02134..440667b7e0e 100644 --- a/stan/math/fwd/fun/exp.hpp +++ b/stan/math/fwd/fun/exp.hpp @@ -14,10 +14,17 @@ inline fvar exp(const fvar& x) { return fvar(exp(x.val_), x.d_ * exp(x.val_)); } -// template -// inline std::complex> exp(const std::complex>& z) { -// return complex_exp(z); -// } +/** + * Return the natural exponentiation (base e) of the specified complex number. + * + * @tparam T value type of autodiff variable + * @param z complex argument + * @return exponentiation of argument + */ +template +inline std::complex> exp(const std::complex>& z) { + return internal::complex_exp(z); +} } // namespace math } // namespace stan diff --git a/stan/math/prim/fun.hpp b/stan/math/prim/fun.hpp index 6824193a663..10cddafe0ba 100644 --- a/stan/math/prim/fun.hpp +++ b/stan/math/prim/fun.hpp @@ -225,6 +225,7 @@ #include #include #include +#include #include #include #include diff --git a/stan/math/prim/fun/exp.hpp b/stan/math/prim/fun/exp.hpp index c5d6c9eab5f..157278ee034 100644 --- a/stan/math/prim/fun/exp.hpp +++ b/stan/math/prim/fun/exp.hpp @@ -18,43 +18,6 @@ namespace math { */ inline double exp(int x) { return std::exp(x); } -/** - * Return the natural (base e) complex exponentiation of the specified - * complex argument. - * - * @tparam V value type (must be Stan autodiff type) - * @param z complex number - * @return natural exponentiation of specified complex number - * @see documentation for `std::complex` for boundary condition and - * branch cut details - */ -template > -inline std::complex exp(const std::complex& z) { - if (is_inf(z.real()) && z.real() > 0) { - if (is_nan(z.imag()) || z.imag() == 0) { - // (+inf, nan), (+inf, 0) - return z; - } else if (is_inf(z.imag()) && z.imag() > 0) { - // (+inf, +inf) - return {z.real(), std::numeric_limits::quiet_NaN()}; - } else if (is_inf(z.imag()) && z.imag() < 0) { - // (+inf, -inf) - return {std::numeric_limits::quiet_NaN(), - std::numeric_limits::quiet_NaN()}; - } - } - if (is_inf(z.real()) && z.real() < 0 - && (is_nan(z.imag()) || is_inf(z.imag()))) { - // (-inf, nan), (-inf, -inf), (-inf, inf) - return {0, 0}; - } - if (is_nan(z.real()) && z.imag() == -0.0) { - // (nan, -0) - return z; - } - V exp_re = exp(z.real()); - return {exp_re * cos(z.imag()), exp_re * sin(z.imag())}; -} /** * Structure to wrap exp() so that it can be @@ -101,6 +64,45 @@ inline auto exp(const Eigen::MatrixBase& x) { return x.derived().array().exp().matrix().eval(); } +namespace internal { +/** + * Return the natural (base e) complex exponentiation of the specified + * complex argument. + * + * @tparam V value type (must be Stan autodiff type) + * @param z complex number + * @return natural exponentiation of specified complex number + * @see documentation for `std::complex` for boundary condition and + * branch cut details + */ +template +inline std::complex complex_exp(const std::complex& z) { + if (is_inf(z.real()) && z.real() > 0) { + if (is_nan(z.imag()) || z.imag() == 0) { + // (+inf, nan), (+inf, 0) + return z; + } else if (is_inf(z.imag()) && z.imag() > 0) { + // (+inf, +inf) + return {z.real(), std::numeric_limits::quiet_NaN()}; + } else if (is_inf(z.imag()) && z.imag() < 0) { + // (+inf, -inf) + return {std::numeric_limits::quiet_NaN(), + std::numeric_limits::quiet_NaN()}; + } + } + if (is_inf(z.real()) && z.real() < 0 + && (is_nan(z.imag()) || is_inf(z.imag()))) { + // (-inf, nan), (-inf, -inf), (-inf, inf) + return {0, 0}; + } + if (is_nan(z.real()) && z.imag() == -0.0) { + // (nan, -0) + return z; + } + V exp_re = exp(z.real()); + return {exp_re * cos(z.imag()), exp_re * sin(z.imag())}; +} +} // namespace internal } // namespace math } // namespace stan diff --git a/stan/math/prim/fun/proj.hpp b/stan/math/prim/fun/proj.hpp index 3f1c99a396c..a8cb7439a95 100644 --- a/stan/math/prim/fun/proj.hpp +++ b/stan/math/prim/fun/proj.hpp @@ -1,7 +1,9 @@ #ifndef STAN_MATH_PRIM_FUN_PROJ_HPP #define STAN_MATH_PRIM_FUN_PROJ_HPP +#include #include +#include namespace stan { namespace math { diff --git a/stan/math/rev/fun.hpp b/stan/math/rev/fun.hpp index 96e3e285dd8..de947a3ac92 100644 --- a/stan/math/rev/fun.hpp +++ b/stan/math/rev/fun.hpp @@ -109,6 +109,7 @@ #include #include #include +#include #include #include #include diff --git a/stan/math/rev/fun/exp.hpp b/stan/math/rev/fun/exp.hpp index 0431446c269..7cc70f42036 100644 --- a/stan/math/rev/fun/exp.hpp +++ b/stan/math/rev/fun/exp.hpp @@ -41,9 +41,14 @@ class exp_vari : public op_v_vari { */ inline var exp(const var& a) { return var(new internal::exp_vari(a.vi_)); } -// inline std::complex exp(const std::complex& z) { -// return complex_exp(z); -// } +/** + * Return the exponentiation (base e) of the specified complex number. + * @param z argument + * @return exponentiation of argument + */ +inline std::complex exp(const std::complex& z) { + return internal::complex_exp(z); +} } // namespace math } // namespace stan From aa4c2cd9809d10f0cf1cd68b202dbbabb6748b87 Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Thu, 5 Mar 2020 13:21:42 -0500 Subject: [PATCH 15/63] complex sqrt --- stan/math/fwd/fun/sqrt.hpp | 15 +++++++++++++++ stan/math/prim/fun/sqrt.hpp | 17 +++++++++++++++++ stan/math/rev/fun/sqrt.hpp | 12 ++++++++++++ test/unit/math/mix/fun/sqrt_test.cpp | 13 ++++++++++++- 4 files changed, 56 insertions(+), 1 deletion(-) diff --git a/stan/math/fwd/fun/sqrt.hpp b/stan/math/fwd/fun/sqrt.hpp index 92b712cf6f6..43126e01f58 100644 --- a/stan/math/fwd/fun/sqrt.hpp +++ b/stan/math/fwd/fun/sqrt.hpp @@ -4,7 +4,9 @@ #include #include #include +#include #include +#include namespace stan { namespace math { @@ -14,6 +16,19 @@ inline fvar sqrt(const fvar& x) { using std::sqrt; return fvar(sqrt(x.val_), 0.5 * x.d_ * inv_sqrt(x.val_)); } + +/** + * Return the square root of the complex argument. + * + * @tparam T autodiff value type + * @param[in] z argument + * @return square root of the argument + */ +template +inline std::complex> sqrt(const std::complex>& z) { + return internal::complex_sqrt(z); +} + } // namespace math } // namespace stan #endif diff --git a/stan/math/prim/fun/sqrt.hpp b/stan/math/prim/fun/sqrt.hpp index 2b397a586d4..a000a57a6f8 100644 --- a/stan/math/prim/fun/sqrt.hpp +++ b/stan/math/prim/fun/sqrt.hpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace stan { namespace math { @@ -57,6 +58,22 @@ inline auto sqrt(const Eigen::MatrixBase& x) { return x.derived().array().sqrt().matrix().eval(); } +namespace internal { +/** + * Return the square root of the complex argument. + * + * @tparam V value type of argument + * @param[in] z argument + * @return square root of the argument + */ +template +inline std::complex complex_sqrt(const std::complex& z) { + auto m = sqrt(hypot(z.real(), z.imag())); + auto at = 0.5 * atan2(z.imag(), z.real()); + return {m * cos(at), m * sin(at)}; +} +} // namespace internal + } // namespace math } // namespace stan diff --git a/stan/math/rev/fun/sqrt.hpp b/stan/math/rev/fun/sqrt.hpp index 7b8bddc627e..4d343f38a8c 100644 --- a/stan/math/rev/fun/sqrt.hpp +++ b/stan/math/rev/fun/sqrt.hpp @@ -1,9 +1,11 @@ #ifndef STAN_MATH_REV_FUN_SQRT_HPP #define STAN_MATH_REV_FUN_SQRT_HPP +#include #include #include #include +#include namespace stan { namespace math { @@ -46,6 +48,16 @@ class sqrt_vari : public op_v_vari { */ inline var sqrt(const var& a) { return var(new internal::sqrt_vari(a.vi_)); } +/** + * Return the square root of the complex argument. + * + * @param[in] z argument + * @return square root of the argument + */ +inline std::complex sqrt(const std::complex& z) { + return internal::complex_sqrt(z); +} + } // namespace math } // namespace stan #endif diff --git a/test/unit/math/mix/fun/sqrt_test.cpp b/test/unit/math/mix/fun/sqrt_test.cpp index 251042259f8..8949819613b 100644 --- a/test/unit/math/mix/fun/sqrt_test.cpp +++ b/test/unit/math/mix/fun/sqrt_test.cpp @@ -1,7 +1,18 @@ #include TEST(mathMixMatFun, sqrt) { - auto f = [](const auto& x1) { return stan::math::sqrt(x1); }; + auto f = [](const auto& x1) { + using stan::math::sqrt; + return sqrt(x1); + }; stan::test::expect_common_nonzero_unary_vectorized(f); stan::test::expect_unary_vectorized(f, -6, -5.2, 1.3, 7, 10.7, 36, 1e6); + + // undefined with 0 in denominator + stan::test::expect_ad(f, std::complex(0.9, 0.8)); + for (double im : std::vector{-1.3, 2.3}) { + for (double re : std::vector{-3.6, -0.0, 0.0, 0.5}) { + stan::test::expect_ad(f, std::complex(re, im)); + } + } } From a17575e0340d5c55989227a11c44d1f6137d6f8c Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Thu, 5 Mar 2020 13:49:16 -0500 Subject: [PATCH 16/63] complex log --- stan/math/fwd/fun/log.hpp | 13 +++++++++++++ stan/math/fwd/fun/sqrt.hpp | 2 ++ stan/math/prim/fun/log.hpp | 26 ++++++++++++++++++++++++++ stan/math/rev/fun/log.hpp | 12 ++++++++++++ test/unit/math/mix/fun/log_test.cpp | 22 ++++++++++++++++++++-- 5 files changed, 73 insertions(+), 2 deletions(-) diff --git a/stan/math/fwd/fun/log.hpp b/stan/math/fwd/fun/log.hpp index f1d5d1d96c7..b1c8f6e7003 100644 --- a/stan/math/fwd/fun/log.hpp +++ b/stan/math/fwd/fun/log.hpp @@ -18,6 +18,19 @@ inline fvar log(const fvar& x) { return fvar(log(x.val_), x.d_ / x.val_); } } + +/** + * Return the natural logarithm (base e) of the specified complex argument. + * + * @tparam T autodiff value type + * @param z complex argument + * @return natural logarithm of argument + */ +template +inline std::complex> log(const std::complex>& z) { + return internal::complex_log(z); +} + } // namespace math } // namespace stan #endif diff --git a/stan/math/fwd/fun/sqrt.hpp b/stan/math/fwd/fun/sqrt.hpp index 43126e01f58..e72bcea4a2f 100644 --- a/stan/math/fwd/fun/sqrt.hpp +++ b/stan/math/fwd/fun/sqrt.hpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include #include diff --git a/stan/math/prim/fun/log.hpp b/stan/math/prim/fun/log.hpp index e29f05bc96a..131ec5d7e16 100644 --- a/stan/math/prim/fun/log.hpp +++ b/stan/math/prim/fun/log.hpp @@ -3,7 +3,11 @@ #include #include +#include +#include #include +#include +#include namespace stan { namespace math { @@ -62,6 +66,28 @@ inline auto log(const Eigen::MatrixBase& x) { return x.derived().array().log().matrix().eval(); } +namespace internal { +/** + * Return the natural logarithm of the complex argument. + * + * @tparam V value type of argument + * @param[in] z argument + * @return natural logarithm of the argument + */ +template +inline std::complex complex_log(const std::complex& z) { + static const double inf = std::numeric_limits::infinity(); + static const double nan = std::numeric_limits::quiet_NaN(); + if ((is_nan(z.real()) && is_inf(z.imag())) + || (is_inf(z.real()) && is_nan(z.imag()))) { + return {inf, nan}; + } + V r = sqrt(norm(z)); + V theta = arg(z); + return {log(r), theta}; +} +} // namespace internal + } // namespace math } // namespace stan #endif diff --git a/stan/math/rev/fun/log.hpp b/stan/math/rev/fun/log.hpp index 2ab780ab289..0a69f864519 100644 --- a/stan/math/rev/fun/log.hpp +++ b/stan/math/rev/fun/log.hpp @@ -1,6 +1,7 @@ #ifndef STAN_MATH_REV_FUN_LOG_HPP #define STAN_MATH_REV_FUN_LOG_HPP +#include #include #include #include @@ -46,6 +47,17 @@ class log_vari : public op_v_vari { */ inline var log(const var& a) { return var(new internal::log_vari(a.vi_)); } +/** + * Return the natural logarithm (base e) of the specified complex argument. + * + * @param z complex argument + * @return natural logarithm of argument + */ +inline std::complex log(const std::complex& z) { + return internal::complex_log(z); +} + + } // namespace math } // namespace stan #endif diff --git a/test/unit/math/mix/fun/log_test.cpp b/test/unit/math/mix/fun/log_test.cpp index 6dcd7314132..41a4de6aae8 100644 --- a/test/unit/math/mix/fun/log_test.cpp +++ b/test/unit/math/mix/fun/log_test.cpp @@ -1,8 +1,26 @@ #include TEST(mathMixMatFun, log) { - auto f = [](const auto& x1) { return stan::math::log(x1); }; + auto f = [](const auto& x1) { + using stan::math::log; + return log(x1); + }; stan::test::expect_common_unary_vectorized(f); stan::test::expect_unary_vectorized(f, -0.2, 1e-3, 1, 1.3, 3, 3.7, 10, 10.2, - 1e6); + 1e6); + + // non-zero real and imaginary components + for (auto re : std::vector{ -2.7, 1, 2.3 }) { + for (auto im : std::vector{ -1.5, 1.2 }) { + stan::test::expect_ad(f, std::complex{re, im}); + } + } + // zero tests which lead to finite vals + stan::test::expect_ad(f, std::complex{0, 2.1}); + stan::test::expect_ad(f, std::complex{0, -2.1}); + stan::test::expect_ad(f, std::complex{2.1, 0}); + stan::test::expect_ad(f, std::complex{-0.0, 2.1}); + stan::test::expect_ad(f, std::complex{-0.0, -2.1}); + stan::test::expect_ad(f, std::complex{2.1, -0.0}); + // (negative real and zero imaginary illegal) } From 3118b03796fb2feeb9ad8aa1575713ad8dcaaba2 Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Thu, 5 Mar 2020 13:56:33 -0500 Subject: [PATCH 17/63] complex log10 --- stan/math/fwd/fun/log10.hpp | 14 ++++++++++++++ stan/math/prim/fun/log10.hpp | 17 +++++++++++++++++ stan/math/rev/fun/log10.hpp | 13 +++++++++++++ test/unit/math/mix/fun/log10_test.cpp | 20 +++++++++++++++++++- 4 files changed, 63 insertions(+), 1 deletion(-) diff --git a/stan/math/fwd/fun/log10.hpp b/stan/math/fwd/fun/log10.hpp index 189f55e9a29..f418eeb4b37 100644 --- a/stan/math/fwd/fun/log10.hpp +++ b/stan/math/fwd/fun/log10.hpp @@ -4,7 +4,9 @@ #include #include #include +#include #include +#include namespace stan { namespace math { @@ -20,6 +22,18 @@ inline fvar log10(const fvar& x) { } } +/** + * Return the base 10 logarithm of the specified complex number. + * + * @tparam T autodiff value type + * @param z complex argument + * @return base 10 log of argument + */ +template +inline std::complex> log10(const std::complex>& z) { + return internal::complex_log10(z); +} + } // namespace math } // namespace stan #endif diff --git a/stan/math/prim/fun/log10.hpp b/stan/math/prim/fun/log10.hpp index 9a257e78dfb..f69eaf390a5 100644 --- a/stan/math/prim/fun/log10.hpp +++ b/stan/math/prim/fun/log10.hpp @@ -3,7 +3,9 @@ #include #include +#include #include +#include namespace stan { namespace math { @@ -48,6 +50,21 @@ inline auto log10(const Eigen::MatrixBase& x) { return x.derived().array().log10().matrix().eval(); } +namespace internal { +/** + * Return the base 10 logarithm of the complex argument. + * + * @tparam V value type of argument + * @param[in] z argument + * @return base 10 logarithm of the argument + */ +template +inline std::complex complex_log10(const std::complex& z) { + static const double inv_log_10 = 1 / std::log(10); + return log(z) * inv_log_10; +} +} // namespace internal + } // namespace math } // namespace stan diff --git a/stan/math/rev/fun/log10.hpp b/stan/math/rev/fun/log10.hpp index e5d246f6908..1cf15d9bae8 100644 --- a/stan/math/rev/fun/log10.hpp +++ b/stan/math/rev/fun/log10.hpp @@ -4,7 +4,9 @@ #include #include #include +#include #include +#include namespace stan { namespace math { @@ -50,6 +52,17 @@ class log10_vari : public op_v_vari { */ inline var log10(const var& a) { return var(new internal::log10_vari(a.vi_)); } +/** + * Return the base 10 logarithm of the specified complex number. + * + * @param z complex argument + * @return base 10 log of argument + */ +inline std::complex log10(const std::complex& z) { + return internal::complex_log10(z); +} + + } // namespace math } // namespace stan #endif diff --git a/test/unit/math/mix/fun/log10_test.cpp b/test/unit/math/mix/fun/log10_test.cpp index 8b66bddfde4..85bb4653c4e 100644 --- a/test/unit/math/mix/fun/log10_test.cpp +++ b/test/unit/math/mix/fun/log10_test.cpp @@ -1,8 +1,26 @@ #include TEST(mathMixMatFun, log10) { - auto f = [](const auto& x1) { return stan::math::log10(x1); }; + auto f = [](const auto& x1) { + using stan::math::log10; + return log10(x1); + }; stan::test::expect_common_unary_vectorized(f); stan::test::expect_unary_vectorized(f, -0.2, 1e-3, 1, 1.3, 3, 3.7, 10, 10.2, 1e6); + + // non-zero real and imaginary components + for (auto re : std::vector{ -2.7, 1, 2.3 }) { + for (auto im : std::vector{ -1.5, 1.2 }) { + stan::test::expect_ad(f, std::complex{re, im}); + } + } + // zero tests which lead to finite vals + stan::test::expect_ad(f, std::complex{0, 2.1}); + stan::test::expect_ad(f, std::complex{0, -2.1}); + stan::test::expect_ad(f, std::complex{2.1, 0}); + stan::test::expect_ad(f, std::complex{-0.0, 2.1}); + stan::test::expect_ad(f, std::complex{-0.0, -2.1}); + stan::test::expect_ad(f, std::complex{2.1, -0.0}); + // (negative real and zero imaginary illegal) } From 619598416ea0bfff6807b866d294397bd1da9a89 Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Thu, 5 Mar 2020 15:58:37 -0500 Subject: [PATCH 18/63] complex pow --- stan/math/fwd/fun/pow.hpp | 154 ++++++++++++++++++++++++++-- stan/math/prim/fun.hpp | 1 + stan/math/prim/fun/exp.hpp | 1 + stan/math/prim/fun/pow.hpp | 30 ++++++ stan/math/rev/fun/pow.hpp | 145 ++++++++++++++++++++++++-- test/unit/math/mix/fun/pow_test.cpp | 36 +++++++ 6 files changed, 351 insertions(+), 16 deletions(-) create mode 100644 stan/math/prim/fun/pow.hpp diff --git a/stan/math/fwd/fun/pow.hpp b/stan/math/fwd/fun/pow.hpp index 71ecb438d0e..dc5ebe0622f 100644 --- a/stan/math/fwd/fun/pow.hpp +++ b/stan/math/fwd/fun/pow.hpp @@ -8,6 +8,8 @@ #include #include #include +#include +#include namespace stan { namespace math { @@ -21,19 +23,18 @@ inline fvar pow(const fvar& x1, const fvar& x2) { * pow_x1_x2); } -template -inline fvar pow(double x1, const fvar& x2) { +template > +inline fvar pow(U x1, const fvar& x2) { using std::log; using std::pow; T u = pow(x1, x2.val_); return fvar(u, x2.d_ * log(x1) * u); } -template -inline fvar pow(const fvar& x1, double x2) { +template > +inline fvar pow(const fvar& x1, U x2) { using std::pow; using std::sqrt; - if (x2 == -2) { return inv_square(x1); } @@ -52,9 +53,150 @@ inline fvar pow(const fvar& x1, double x2) { if (x2 == 2.0) { return square(x1); } - return fvar(pow(x1.val_, x2), x1.d_ * x2 * pow(x1.val_, x2 - 1)); } + +// must uniquely match all pairs of: +// { complex>, complex, fvar, T } +// with at least one fvar and at least one complex, where T is arithmetic: +// 1) complex>, complex> +// 2) complex>, complex +// 3) complex>, fvar +// 4) complex>, T +// 5) complex, complex> +// 6) complex, fvar +// 7) fvar, complex> +// 8) fvar, complex +// 9) T, complex> + +/** + * Return the first argument raised to the power of the second argument. + * + * @param x first argument + * @param y second argument + * @return first argument to the power of the second argument + */ +template +inline std::complex> pow(const std::complex>& x, + const std::complex>& y) { + return internal::complex_pow(x, y); +} + +/** + * Return the first argument raised to the power of the second argument. + * + * @tparam V autodiff value type + * @tparam T arithmetic type + * @param x first argument + * @param y second argument + * @return first argument to the power of the second argument + */ +template > +inline std::complex> pow(const std::complex>& x, + const std::complex& y) { + return internal::complex_pow(x, y); +} + +/** + * Return the first argument raised to the power of the second argument. + * + * @tparam V autodiff value type + * @param x first argument + * @param y second argument + * @return first argument to the power of the second argument + */ +template +inline std::complex> pow(const std::complex>& x, + const fvar& y) { + return internal::complex_pow(x, y); +} + +/** + * Return the first argument raised to the power of the second argument. + * + * @tparam V autodiff value type + * @tparam T arithmetic type + * @param x first argument + * @param y second argument + * @return first argument to the power of the second argument + */ +template > +inline std::complex> pow(const std::complex>& x, + const T& y) { + return internal::complex_pow(x, y); +} + +/** + * Return the first argument raised to the power of the second argument. + * + * @tparam V autodiff value type + * @tparam T arithmetic type + * @param x first argument + * @param y second argument + * @return first argument to the power of the second argument + */ +template > +inline std::complex> pow(const std::complex& x, + const std::complex>& y) { + return internal::complex_pow(x, y); +} + +/** + * Return the first argument raised to the power of the second argument. + * + * @tparam V autodiff value type + * @tparam T arithmetic type + * @param x first argument + * @param y second argument + * @return first argument to the power of the second argument + */ +template > +inline std::complex> pow(const std::complex& x, const fvar& y) { + return internal::complex_pow(x, y); +} + +/** + * Return the first argument raised to the power of the second argument. + * + * @tparam V autodiff value type + * @param x first argument + * @param y second argument + * @return first argument to the power of the second argument + */ +template +inline std::complex> pow(const fvar& x, + const std::complex>& y) { + return internal::complex_pow(x, y); +} + +/** + * Return the first argument raised to the power of the second argument. + * + * @tparam V autodiff value type + * @tparam T arithmetic type + * @param x first argument + * @param y second argument + * @return first argument to the power of the second argument + */ +template > +inline std::complex> pow(const fvar& x, const std::complex& y) { + return internal::complex_pow(x, y); +} + +/** + * Return the first argument raised to the power of the second argument. + * + * @tparam V autodiff value type + * @tparam T real type (`fvar` or arithmetic) + * @param x first argument + * @param y second argument + * @return first argument to the power of the second argument + */ +template > +inline std::complex> pow(T x, const std::complex>& y) { + return internal::complex_pow(x, y); +} + } // namespace math } // namespace stan #endif diff --git a/stan/math/prim/fun.hpp b/stan/math/prim/fun.hpp index 10cddafe0ba..49d1f1efed3 100644 --- a/stan/math/prim/fun.hpp +++ b/stan/math/prim/fun.hpp @@ -230,6 +230,7 @@ #include #include #include +#include #include #include #include diff --git a/stan/math/prim/fun/exp.hpp b/stan/math/prim/fun/exp.hpp index 157278ee034..cc7c1c3b1c9 100644 --- a/stan/math/prim/fun/exp.hpp +++ b/stan/math/prim/fun/exp.hpp @@ -5,6 +5,7 @@ #include #include #include +#include namespace stan { namespace math { diff --git a/stan/math/prim/fun/pow.hpp b/stan/math/prim/fun/pow.hpp new file mode 100644 index 00000000000..ffbcce780d2 --- /dev/null +++ b/stan/math/prim/fun/pow.hpp @@ -0,0 +1,30 @@ +#ifndef STAN_MATH_PRIM_FUN_POW_HPP +#define STAN_MATH_PRIM_FUN_POW_HPP + +#include +#include +#include +#include + +namespace stan { +namespace math { +namespace internal { + +/** + * Return the first argument raised to the power of the second + * argument. At least one of the arguments must be a complex number. + * + * @tparam U type of first argument + * @tparam V type of second argument + * @param[in] lhs first argument + * @param[in] rhs second argument + * @return first argument raised to the power of the second argument + */ +template +inline complex_return_t complex_pow(const U& x, const V& y) { + return exp(y * log(x)); +} +} // namespace internal +} // namespace math +} // namespace stan +#endif diff --git a/stan/math/rev/fun/pow.hpp b/stan/math/rev/fun/pow.hpp index 1b401abda32..6c51a3a62da 100644 --- a/stan/math/rev/fun/pow.hpp +++ b/stan/math/rev/fun/pow.hpp @@ -10,7 +10,10 @@ #include #include #include +#include #include +#include +#include namespace stan { namespace math { @@ -120,15 +123,13 @@ inline var pow(const var& base, const var& exponent) { * The template parameters are coded as they are so that arithmetic * types will not be promoted into the `var` slots. * - * @tparam Var var type - * @tparam Arith arithmetic type + * @tparam T arithmetic type * @param base Base variable. * @param exponent Exponent scalar. * @return Base raised to the exponent. */ -template ..., - require_arithmetic_t...> -inline var pow(const Var& base, Arith exponent) { +template > +inline var pow(const var& base, T exponent) { if (exponent == 0.5) { return sqrt(base); } @@ -161,19 +162,143 @@ inline var pow(const Var& base, Arith exponent) { * The template parameters are coded as they are so that arithmetic * types will not be promoted into the `var` slots. * - * @tparam Var var type - * @tparam Arith arithmetic type + * @tparam T arithmetic type * * @param base Base scalar. * @param exponent Exponent variable. * @return Base raised to the exponent. */ -template ..., - require_var_t> -inline var pow(Arith base, const Var& exponent) { +template > +inline var pow(T base, const var& exponent) { return {new internal::pow_dv_vari(base, exponent.vi_)}; } +// must uniquely match all pairs of { complex, complex, var, T } +// with at least one var and at least one complex, where T is arithmetic: +// 1) complex, complex +// 2) complex, complex +// 3) complex, var +// 4) complex, T +// 5) complex, complex +// 6) complex, var +// 7) var, complex +// 8) var, complex +// 9) T, complex + +/** + * Return the first argument raised to the power of the second argument. + * + * @param x first argument + * @param y second argument + * @return first argument to the power of the second argument + */ +inline std::complex pow(const std::complex& x, + const std::complex& y) { + return internal::complex_pow(x, y); +} + +/** + * Return the first argument raised to the power of the second argument. + * + * @tparam T arithmetic type + * @param x first argument + * @param y second argument + * @return first argument to the power of the second argument + */ +template > +inline std::complex pow(const std::complex& x, + const std::complex y) { + return internal::complex_pow(x, y); +} + +/** + * Return the first argument raised to the power of the second argument. + * + * @param x first argument + * @param y second argument + * @return first argument to the power of the second argument + */ +inline std::complex pow(const std::complex& x, const var& y) { + return internal::complex_pow(x, y); +} + +/** + * Return the first argument raised to the power of the second argument. + * + * @tparam T arithmetic type + * @param x first argument + * @param y second argument + * @return first argument to the power of the second argument + */ +template > +inline std::complex pow(const std::complex& x, T y) { + return internal::complex_pow(x, y); +} + +/** + * Return the first argument raised to the power of the second argument. + * + * @tparam T arithmetic type + * @param x first argument + * @param y second argument + * @return first argument to the power of the second argument + */ +template > +inline std::complex pow(std::complex x, const std::complex& y) { + return internal::complex_pow(x, y); +} + +/** + * Return the first argument raised to the power of the second argument. + * + * @tparam T arithmetic type + * @param x first argument + * @param y second argument + * @return first argument to the power of the second argument + */ +template > +inline std::complex pow(std::complex x, const var& y) { + return internal::complex_pow(x, y); +} + +/** + * Return the first argument raised to the power of the second argument. + * + * @param x first argument + * @param y second argument + * @return first argument to the power of the second argument + */ +inline std::complex pow(const var& x, const std::complex& y) { + return internal::complex_pow(x, y); +} + +/** + * Return the first argument raised to the power of the second argument. + * + * @tparam T arithmetic type + * @param x first argument + * @param y second argument + * @return first argument to the power of the second argument + */ +template > +inline std::complex pow(const var& x, std::complex y) { + return internal::complex_pow(x, y); +} + +/** + * Return the first argument raised to the power of the second argument. + * + * @tparam T arithmetic type + * @param x first argument + * @param y second argument + * @return first argument to the power of the second argument + */ + template > +inline std::complex pow(T x, const std::complex& y) { + return internal::complex_pow(x, y); +} + + } // namespace math } // namespace stan #endif diff --git a/test/unit/math/mix/fun/pow_test.cpp b/test/unit/math/mix/fun/pow_test.cpp index 199001770a6..b312398f241 100644 --- a/test/unit/math/mix/fun/pow_test.cpp +++ b/test/unit/math/mix/fun/pow_test.cpp @@ -46,3 +46,39 @@ TEST(mathMixScalFun, pow) { stan::test::expect_ad(f, nan, 1.0); stan::test::expect_ad(f, nan, nan); } +TEST(mathMixFun, complexPow) { + auto f = [](const auto& x1, const auto& x2) { + using std::pow; + using stan::math::pow; + return pow(x1, x2); + }; + stan::test::ad_tolerances tols; + tols.hessian_hessian_ = 5e-3; + tols.hessian_fvar_hessian_ = 5e-3; + // complex, complex + for (auto re1 : std::vector{ -1.8, 3.4 }) { + for (auto im1 : std::vector{ -1.8, 3.4 }) { + for (auto re2 : std::vector{ -2.7, 1, 2.3 }) { + for (auto im2 : std::vector{ -1.5, 1.2 }) { + stan::test::expect_ad(tols, f, std::complex{re1, im1}, + std::complex{re2, im2}); + } + } + } + } + // if real, first arg must be positive + for (auto re1 : std::vector{ 3.4 }) { + for (auto re2 : std::vector{ -2.7, 1, 2.3 }) { + for (auto im2 : std::vector{ -1.5, 1.2 }) { + stan::test::expect_ad(tols, f, re1, std::complex{re2, im2}); + } + } + } + for (auto re1 : std::vector{ -1.8, 3.4 }) { + for (auto im1 : std::vector{ -1.8, 3.4 }) { + for (auto re2 : std::vector{ -2.7, 1, 2.3 }) { + stan::test::expect_ad(tols, f, std::complex{re1, im1}, re2); + } + } + } +} From 04f0606cd809410c557b0997709e68456a8268d0 Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Thu, 5 Mar 2020 16:11:04 -0500 Subject: [PATCH 19/63] complex sinh --- stan/math/fwd/fun/sinh.hpp | 16 ++++++++++++++++ stan/math/prim/fun/sinh.hpp | 15 +++++++++++++++ stan/math/rev/fun/sinh.hpp | 12 ++++++++++++ test/unit/math/mix/fun/sinh_test.cpp | 6 +++++- 4 files changed, 48 insertions(+), 1 deletion(-) diff --git a/stan/math/fwd/fun/sinh.hpp b/stan/math/fwd/fun/sinh.hpp index 2260cf7f8bf..e7b2b7f9b95 100644 --- a/stan/math/fwd/fun/sinh.hpp +++ b/stan/math/fwd/fun/sinh.hpp @@ -1,8 +1,11 @@ #ifndef STAN_MATH_FWD_FUN_SINH_HPP #define STAN_MATH_FWD_FUN_SINH_HPP +#include #include #include +#include + namespace stan { namespace math { @@ -13,6 +16,19 @@ inline fvar sinh(const fvar& x) { using std::sinh; return fvar(sinh(x.val_), x.d_ * cosh(x.val_)); } + +/** + * Return the hyperbolic sine of the complex argument. + * + * @tparam T autodiff value type + * @param[in] z argument + * @return hyperbolic sine of the argument + */ +template +inline std::complex> sinh(const std::complex>& z) { + return stan::math::internal::complex_sinh(z); +} + } // namespace math } // namespace stan #endif diff --git a/stan/math/prim/fun/sinh.hpp b/stan/math/prim/fun/sinh.hpp index 4d9f2569555..abb5c646272 100644 --- a/stan/math/prim/fun/sinh.hpp +++ b/stan/math/prim/fun/sinh.hpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace stan { namespace math { @@ -61,6 +62,20 @@ inline auto sinh(const Eigen::ArrayBase& x) { return x.derived().sinh().eval(); } +namespace internal { +/** + * Return the hyperbolic sine of the complex argument. + * + * @tparam V value type of argument + * @param[in] z argument + * @return hyperbolic sine of the argument + */ +template +inline std::complex complex_sinh(const std::complex& z) { + return 0.5 * (exp(z) - exp(-z)); +} +} // namespace internal + } // namespace math } // namespace stan diff --git a/stan/math/rev/fun/sinh.hpp b/stan/math/rev/fun/sinh.hpp index 822b70940c2..4571e47a07f 100644 --- a/stan/math/rev/fun/sinh.hpp +++ b/stan/math/rev/fun/sinh.hpp @@ -1,9 +1,11 @@ #ifndef STAN_MATH_REV_FUN_SINH_HPP #define STAN_MATH_REV_FUN_SINH_HPP +#include #include #include #include +#include namespace stan { namespace math { @@ -45,6 +47,16 @@ class sinh_vari : public op_v_vari { */ inline var sinh(const var& a) { return var(new internal::sinh_vari(a.vi_)); } +/** + * Return the hyperbolic sine of the complex argument. + * + * @param[in] z argument + * @return hyperbolic sine of the argument + */ +inline std::complex sinh(const std::complex& z) { + return stan::math::internal::complex_sinh(z); +} + } // namespace math } // namespace stan #endif diff --git a/test/unit/math/mix/fun/sinh_test.cpp b/test/unit/math/mix/fun/sinh_test.cpp index b1282ee79b9..de285a71651 100644 --- a/test/unit/math/mix/fun/sinh_test.cpp +++ b/test/unit/math/mix/fun/sinh_test.cpp @@ -1,8 +1,12 @@ #include TEST(mathMixMatFun, sinh) { - auto f = [](const auto& x1) { return stan::math::sinh(x1); }; + auto f = [](const auto& x) { + using stan::math::sinh; + return sinh(x); + }; stan::test::expect_common_nonzero_unary_vectorized(f); stan::test::expect_unary_vectorized(f, -2, -1.2, -0.5, -0.2, 0.5, 1.3, 1.5, 3); + stan::test::expect_complex_common(f); } From d243df460c955effad9f93a7618295433b86fd20 Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Thu, 5 Mar 2020 16:25:47 -0500 Subject: [PATCH 20/63] complex cosh --- stan/math/fwd/fun/cosh.hpp | 15 +++++++++++++++ stan/math/prim/fun/cosh.hpp | 15 +++++++++++++++ stan/math/rev/fun/cosh.hpp | 14 ++++++++++++++ test/unit/math/mix/fun/cosh_test.cpp | 6 +++++- 4 files changed, 49 insertions(+), 1 deletion(-) diff --git a/stan/math/fwd/fun/cosh.hpp b/stan/math/fwd/fun/cosh.hpp index 124063b767e..d1194cf54ed 100644 --- a/stan/math/fwd/fun/cosh.hpp +++ b/stan/math/fwd/fun/cosh.hpp @@ -3,7 +3,10 @@ #include #include +#include +#include #include +#include namespace stan { namespace math { @@ -15,6 +18,18 @@ inline fvar cosh(const fvar& x) { return fvar(cosh(x.val_), x.d_ * sinh(x.val_)); } +/** + * Return the hyperbolic cosine of the complex argument. + * + * @tparam T autodiff value type + * @param[in] z argument + * @return hyperbolic cosine of the argument + */ +template +inline std::complex> cosh(const std::complex>& z) { + return stan::math::internal::complex_cosh(z); +} + } // namespace math } // namespace stan #endif diff --git a/stan/math/prim/fun/cosh.hpp b/stan/math/prim/fun/cosh.hpp index 80aecfcc275..97fc203bba9 100644 --- a/stan/math/prim/fun/cosh.hpp +++ b/stan/math/prim/fun/cosh.hpp @@ -3,6 +3,7 @@ #include #include +#include #include namespace stan { @@ -48,6 +49,20 @@ inline auto cosh(const Eigen::MatrixBase& x) { return x.derived().array().cosh().matrix().eval(); } +namespace internal { +/** + * Return the hyperbolic cosine of the complex argument. + * + * @tparam V value type of argument + * @param[in] z argument + * @return hyperbolic cosine of the argument + */ +template +inline std::complex complex_cosh(const std::complex& z) { + return 0.5 * (exp(z) + exp(-z)); +} +} // namespace internal + } // namespace math } // namespace stan diff --git a/stan/math/rev/fun/cosh.hpp b/stan/math/rev/fun/cosh.hpp index 4f1c377fa67..592759dbb38 100644 --- a/stan/math/rev/fun/cosh.hpp +++ b/stan/math/rev/fun/cosh.hpp @@ -1,9 +1,12 @@ #ifndef STAN_MATH_REV_FUN_COSH_HPP #define STAN_MATH_REV_FUN_COSH_HPP +#include #include #include +#include #include +#include namespace stan { namespace math { @@ -45,6 +48,17 @@ class cosh_vari : public op_v_vari { */ inline var cosh(const var& a) { return var(new internal::cosh_vari(a.vi_)); } +/** + * Return the hyperbolic cosine of the complex argument. + * + * @param[in] z argument + * @return hyperbolic cosine of the argument + */ +inline std::complex cosh(const std::complex& z) { + return stan::math::internal::complex_cosh(z); +} + + } // namespace math } // namespace stan #endif diff --git a/test/unit/math/mix/fun/cosh_test.cpp b/test/unit/math/mix/fun/cosh_test.cpp index 93922de9b05..4f9c90c5a51 100644 --- a/test/unit/math/mix/fun/cosh_test.cpp +++ b/test/unit/math/mix/fun/cosh_test.cpp @@ -1,8 +1,12 @@ #include TEST(mathMixMatFun, cosh) { - auto f = [](const auto& x1) { return stan::math::cosh(x1); }; + auto f = [](const auto& x1) { + using stan::math::cosh; + return cosh(x1); + }; stan::test::expect_common_unary_vectorized(f); stan::test::expect_unary_vectorized(f, -2.6, -2, -1.2, -0.2, 0.5, 1, 1.3, 1.5); + stan::test::expect_complex_common(f); } From 8ea8a7544a8f0ce859e8435316f3f70af83f8c5b Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Fri, 6 Mar 2020 14:45:16 -0500 Subject: [PATCH 21/63] logb, scalbn and complex tanh --- stan/math/fwd/fun/tanh.hpp | 16 +++++++++++++ stan/math/prim/fun.hpp | 2 ++ stan/math/prim/fun/logb.hpp | 18 +++++++++++++++ stan/math/prim/fun/scalbn.hpp | 19 ++++++++++++++++ stan/math/prim/fun/tanh.hpp | 21 +++++++++++++++++ stan/math/rev/fun/tanh.hpp | 13 +++++++++++ test/unit/math/mix/fun/logb_test.cpp | 29 ++++++++++++++++++++++++ test/unit/math/mix/fun/scalbn_test.cpp | 31 ++++++++++++++++++++++++++ test/unit/math/mix/fun/tanh_test.cpp | 6 ++++- 9 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 stan/math/prim/fun/logb.hpp create mode 100644 stan/math/prim/fun/scalbn.hpp create mode 100644 test/unit/math/mix/fun/logb_test.cpp create mode 100644 test/unit/math/mix/fun/scalbn_test.cpp diff --git a/stan/math/fwd/fun/tanh.hpp b/stan/math/fwd/fun/tanh.hpp index 2dff5e3ee58..9bb120ba4e3 100644 --- a/stan/math/fwd/fun/tanh.hpp +++ b/stan/math/fwd/fun/tanh.hpp @@ -3,7 +3,10 @@ #include #include +#include +#include #include +#include namespace stan { namespace math { @@ -14,6 +17,19 @@ inline fvar tanh(const fvar& x) { T u = tanh(x.val_); return fvar(u, x.d_ * (1 - u * u)); } + +/** + * Return the hyperbolic tangent of the complex argument. + * + * @tparam T autodiff value type + * @param[in] z argument + * @return hyperbolic tangent of the argument + */ +template +inline std::complex> tanh(const std::complex>& z) { + return stan::math::internal::complex_tanh(z); +} + } // namespace math } // namespace stan #endif diff --git a/stan/math/prim/fun.hpp b/stan/math/prim/fun.hpp index 49d1f1efed3..f214acd63ea 100644 --- a/stan/math/prim/fun.hpp +++ b/stan/math/prim/fun.hpp @@ -151,6 +151,7 @@ #include #include #include +#include #include #include #include @@ -263,6 +264,7 @@ #include #include #include +#include #include #include #include diff --git a/stan/math/prim/fun/logb.hpp b/stan/math/prim/fun/logb.hpp new file mode 100644 index 00000000000..ee765b8263f --- /dev/null +++ b/stan/math/prim/fun/logb.hpp @@ -0,0 +1,18 @@ +#ifndef STAN_MATH_PRIM_FUN_LOGB_HPP +#define STAN_MATH_PRIM_FUN_LOGB_HPP + +#include +#include + +namespace stan { +namespace math { + +template > +double logb(const T& x) { + return std::logb(value_of_rec(x)); +} + +} // namespace math +} // namespace stan + +#endif diff --git a/stan/math/prim/fun/scalbn.hpp b/stan/math/prim/fun/scalbn.hpp new file mode 100644 index 00000000000..6c3e54cdc24 --- /dev/null +++ b/stan/math/prim/fun/scalbn.hpp @@ -0,0 +1,19 @@ +#ifndef STAN_MATH_PRIM_FUN_SCALBN_HPP +#define STAN_MATH_PRIM_FUN_SCALBN_HPP + +#include +#include +#include + +namespace stan { +namespace math { + +template > +double scalbn(const T& x, int n) { + return std::scalbn(value_of_rec(x), n); +} + +} // namespace math +} // namespace stan + +#endif diff --git a/stan/math/prim/fun/tanh.hpp b/stan/math/prim/fun/tanh.hpp index 966aaad3a1c..d09302e8333 100644 --- a/stan/math/prim/fun/tanh.hpp +++ b/stan/math/prim/fun/tanh.hpp @@ -3,7 +3,10 @@ #include #include +#include +#include #include +#include namespace stan { namespace math { @@ -48,6 +51,24 @@ inline auto tanh(const Eigen::MatrixBase& x) { return x.derived().array().tanh().matrix().eval(); } +namespace internal { +/** + * Return the hyperbolic tangent of the complex argument. + * + * @tparam V value type of argument + * @param[in] z argument + * @return hyperbolic tangent of the argument + */ +template +inline std::complex complex_tanh(const std::complex& z) { + using std::exp; + using stan::math::operator/; + auto exp_z = exp(z); + auto exp_neg_z = exp(-z); + return stan::math::internal::complex_divide(exp_z - exp_neg_z, exp_z + exp_neg_z); +} +} // namespace internal + } // namespace math } // namespace stan diff --git a/stan/math/rev/fun/tanh.hpp b/stan/math/rev/fun/tanh.hpp index dde1ec7f9a8..ef9763989e2 100644 --- a/stan/math/rev/fun/tanh.hpp +++ b/stan/math/rev/fun/tanh.hpp @@ -1,9 +1,12 @@ #ifndef STAN_MATH_REV_FUN_TANH_HPP #define STAN_MATH_REV_FUN_TANH_HPP +#include #include #include +#include #include +#include namespace stan { namespace math { @@ -48,6 +51,16 @@ class tanh_vari : public op_v_vari { */ inline var tanh(const var& a) { return var(new internal::tanh_vari(a.vi_)); } +/** + * Return the hyperbolic tangent of the complex argument. + * + * @param[in] z argument + * @return hyperbolic tangent of the argument + */ +inline std::complex tanh(const std::complex& z) { + return stan::math::internal::complex_tanh(z); +} + } // namespace math } // namespace stan #endif diff --git a/test/unit/math/mix/fun/logb_test.cpp b/test/unit/math/mix/fun/logb_test.cpp new file mode 100644 index 00000000000..7562e64c10e --- /dev/null +++ b/test/unit/math/mix/fun/logb_test.cpp @@ -0,0 +1,29 @@ +#include +#include +#include + +template +void expect_logb(double x) { + using std::logb; + T xt(x); + stan::test::expect_near_rel("logb", logb(x), logb(xt)); +} + +void expect_all_logb(double x) { + using stan::math::var; + using stan::math::fvar; + expect_logb(x); + expect_logb(x); + expect_logb>(x); + expect_logb>>(x); + expect_logb>(x); + expect_logb>>(x); +} + +TEST(mathMixMatFun, logb) { + double inf = std::numeric_limits::infinity(); + double nan = std::numeric_limits::quiet_NaN(); + for (double x : std::vector{-inf, -2.3, 0, 1, 2, 3.9, inf, nan}) { + expect_all_logb(x); + } +} diff --git a/test/unit/math/mix/fun/scalbn_test.cpp b/test/unit/math/mix/fun/scalbn_test.cpp new file mode 100644 index 00000000000..364fa551cd0 --- /dev/null +++ b/test/unit/math/mix/fun/scalbn_test.cpp @@ -0,0 +1,31 @@ +#include +#include +#include + +template +void expect_scalbn(double x) { + using std::scalbn; + T xt(x); + for (int n = 2; n < 5; ++n) { + stan::test::expect_near_rel("scalbn", scalbn(x, n), scalbn(xt, n)); + } +} + +void expect_all_scalbn(double x) { + using stan::math::var; + using stan::math::fvar; + expect_scalbn(x); + expect_scalbn(x); + expect_scalbn>(x); + expect_scalbn>>(x); + expect_scalbn>(x); + expect_scalbn>>(x); +} + +TEST(mathMixMatFun, scalbn) { + double inf = std::numeric_limits::infinity(); + double nan = std::numeric_limits::quiet_NaN(); + for (double x : std::vector{ 2.3 }) { // {-inf, -2.3, 0, 1, 2, 3.9, inf, nan}) { + expect_all_scalbn(x); + } +} diff --git a/test/unit/math/mix/fun/tanh_test.cpp b/test/unit/math/mix/fun/tanh_test.cpp index b98a28298dc..78bca8cef01 100644 --- a/test/unit/math/mix/fun/tanh_test.cpp +++ b/test/unit/math/mix/fun/tanh_test.cpp @@ -1,7 +1,11 @@ #include TEST(mathMixMatFun, tanh) { - auto f = [](const auto& x1) { return stan::math::tanh(x1); }; + auto f = [](const auto& x1) { + using stan::math::tanh; + return tanh(x1); + }; stan::test::expect_common_nonzero_unary_vectorized(f); stan::test::expect_unary_vectorized(f, -2.6, -2, -1.2, -0.5, 0.5, 1.5); + stan::test::expect_complex_common(f); } From 8620d474bce65320654d319f2d87afb6e4957ca3 Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Tue, 10 Mar 2020 15:21:42 -0400 Subject: [PATCH 22/63] complex operator/ --- stan/math/fwd/core/operator_division.hpp | 62 +++++++++++++++++-- stan/math/rev/core.hpp | 1 + stan/math/rev/core/operator_division.hpp | 56 +++++++++++++++-- .../math/mix/core/operator_division_test.cpp | 14 +++++ test/unit/math/test_ad.hpp | 14 +++++ 5 files changed, 137 insertions(+), 10 deletions(-) diff --git a/stan/math/fwd/core/operator_division.hpp b/stan/math/fwd/core/operator_division.hpp index 6ed5bdb168e..de6c54f5230 100644 --- a/stan/math/fwd/core/operator_division.hpp +++ b/stan/math/fwd/core/operator_division.hpp @@ -1,7 +1,9 @@ #ifndef STAN_MATH_FWD_CORE_OPERATOR_DIVISION_HPP #define STAN_MATH_FWD_CORE_OPERATOR_DIVISION_HPP -#include +#include +#include +#include namespace stan { namespace math { @@ -28,8 +30,8 @@ inline fvar operator/(const fvar& x1, const fvar& x2) { * @param x2 second argument * @return first argument divided by second argument */ -template -inline fvar operator/(const fvar& x1, double x2) { +template ...> +inline fvar operator/(const fvar& x1, U x2) { return fvar(x1.val_ / x2, x1.d_ / x2); } @@ -41,11 +43,59 @@ inline fvar operator/(const fvar& x1, double x2) { * @param x2 second argument * @return first argument divided by second argument */ -template -inline fvar operator/(double x1, const fvar& x2) { - // TODO(carpenter): store x1 / x2.val_ and reuse +template ...> +inline fvar operator/(U x1, const fvar& x2) { return fvar(x1 / x2.val_, -x1 * x2.d_ / (x2.val_ * x2.val_)); } + +template +inline std::complex> operator/(const std::complex>& x1, + const std::complex>& x2) { + return internal::complex_divide(x1, x2); +} + template ...> +inline std::complex> operator/(const std::complex>& x1, + const std::complex& x2) { + return internal::complex_divide(x1, x2); +} +template +inline std::complex> operator/(const std::complex>& x1, + const fvar& x2) { + return internal::complex_divide(x1, x2); +} +template ...> +inline std::complex> operator/(const std::complex>& x1, U x2) { + return internal::complex_divide(x1, x2); +} + +template ...> +inline std::complex> operator/(const std::complex& x1, + const std::complex>& x2) { + return internal::complex_divide(x1, x2); +} +template ...> +inline std::complex> operator/(const std::complex& x1, + const fvar& x2) { + return internal::complex_divide(x1, x2); +} + +template +inline std::complex> operator/(const fvar& x1, + const std::complex>& x2) { + return internal::complex_divide(x1, x2); +} +template ::value>> +inline std::complex> operator/(const fvar& x1, + const std::complex& x2) { + return internal::complex_divide(x1, x2); +} + +template ...> +inline std::complex> operator/(U x1, const std::complex>& x2) { + return internal::complex_divide(x1, x2); +} + } // namespace math } // namespace stan #endif diff --git a/stan/math/rev/core.hpp b/stan/math/rev/core.hpp index 5d3c91f423b..b6b1891abd8 100644 --- a/stan/math/rev/core.hpp +++ b/stan/math/rev/core.hpp @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include diff --git a/stan/math/rev/core/operator_division.hpp b/stan/math/rev/core/operator_division.hpp index 5d5dc1e86c5..f5e968104c4 100644 --- a/stan/math/rev/core/operator_division.hpp +++ b/stan/math/rev/core/operator_division.hpp @@ -2,12 +2,13 @@ #define STAN_MATH_REV_CORE_OPERATOR_DIVISION_HPP #include -#include -#include -#include -#include +#include #include #include +#include +#include +#include +#include namespace stan { namespace math { @@ -132,6 +133,53 @@ inline var operator/(Arith dividend, var divisor) { return {new internal::divide_dv_vari(dividend, divisor.vi_)}; } +inline std::complex operator/(const std::complex& x1, + const std::complex& x2) { + return internal::complex_divide(x1, x2); +} + +template ...> +inline std::complex operator/(const std::complex& x1, + const std::complex& x2) { + return internal::complex_divide(x1, x2); +} +inline std::complex operator/(const std::complex& x1, + const var& x2) { + return internal::complex_divide(x1, x2); +} +template ...> +inline std::complex operator/(const std::complex& x1, + T x2) { + return internal::complex_divide(x1, x2); +} + +template ...> +inline std::complex operator/(const std::complex& x1, + const std::complex& x2) { + return internal::complex_divide(x1, x2); +} +template ...> +inline std::complex operator/(const std::complex& x1, + const var& x2) { + return internal::complex_divide(x1, x2); +} + +inline std::complex operator/(const var& x1, + const std::complex& x2) { + return internal::complex_divide(x1, x2); +} +template ...> +inline std::complex operator/(const var& x1, + const std::complex& x2) { + return internal::complex_divide(x1, x2); +} + +template ...> +inline std::complex operator/(T x1, + const std::complex& x2) { + return internal::complex_divide(x1, x2); +} + } // namespace math } // namespace stan #endif diff --git a/test/unit/math/mix/core/operator_division_test.cpp b/test/unit/math/mix/core/operator_division_test.cpp index 9193b24a7a8..c6222fce86c 100644 --- a/test/unit/math/mix/core/operator_division_test.cpp +++ b/test/unit/math/mix/core/operator_division_test.cpp @@ -17,4 +17,18 @@ TEST(mathMixCore, operatorDivision) { } } } + for (auto re1 : common_finite) { + for (auto re2 : common_finite) { + for (auto im2 : common_finite_nz) { + stan::test::expect_ad(f, re1, std::complex(re2, im2)); + } + } + } + for (auto re1 : common_finite) { + for (auto im1 : common_finite_nz) { + for (auto re2 : common_finite) { + stan::test::expect_ad(f, std::complex(re1, im1), re2); + } + } + } } diff --git a/test/unit/math/test_ad.hpp b/test/unit/math/test_ad.hpp index 9c5fef53c44..87c388d67b9 100644 --- a/test/unit/math/test_ad.hpp +++ b/test/unit/math/test_ad.hpp @@ -1743,12 +1743,26 @@ void expect_complex_common(const F& f) { template void expect_complex_common_binary(const F& f) { + auto xs = common_complex_parts(); auto zs = common_complex(); + // complex, complex for (auto z1 : zs) { for (auto z2 : zs) { expect_ad(f, z1, z2); } } + // complex, real + for (auto z1 : zs) { + for (auto x2 : xs) { + expect_ad(f, z1, x2); + } + } + // real, complex + for (auto x1 : xs) { + for (auto z2 : zs) { + expect_ad(f, x1, z2); + } + } } template From 29a8bf6d7bb7166c8c1e16db79d22086e67fa779 Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Tue, 10 Mar 2020 16:13:15 -0400 Subject: [PATCH 23/63] complex sin --- stan/math/fwd/fun/sin.hpp | 15 +++++++++++++++ stan/math/fwd/fun/sinh.hpp | 2 +- stan/math/prim/fun/sin.hpp | 17 +++++++++++++++++ stan/math/rev/fun/sin.hpp | 12 ++++++++++++ test/unit/math/mix/fun/sin_test.cpp | 6 +++++- 5 files changed, 50 insertions(+), 2 deletions(-) diff --git a/stan/math/fwd/fun/sin.hpp b/stan/math/fwd/fun/sin.hpp index 2adc1ac6473..bb5a5b11695 100644 --- a/stan/math/fwd/fun/sin.hpp +++ b/stan/math/fwd/fun/sin.hpp @@ -1,8 +1,10 @@ #ifndef STAN_MATH_FWD_FUN_SIN_HPP #define STAN_MATH_FWD_FUN_SIN_HPP +#include #include #include +#include namespace stan { namespace math { @@ -13,6 +15,19 @@ inline fvar sin(const fvar& x) { using std::sin; return fvar(sin(x.val_), x.d_ * cos(x.val_)); } + +/** + * Return the sine of the complex argument. + * + * @tparam T autodiff value type + * @param[in] z argument + * @return sine of the argument + */ +template +inline std::complex> sin(const std::complex>& z) { + return internal::complex_sin(z); +} + } // namespace math } // namespace stan #endif diff --git a/stan/math/fwd/fun/sinh.hpp b/stan/math/fwd/fun/sinh.hpp index e7b2b7f9b95..252afd686a5 100644 --- a/stan/math/fwd/fun/sinh.hpp +++ b/stan/math/fwd/fun/sinh.hpp @@ -26,7 +26,7 @@ inline fvar sinh(const fvar& x) { */ template inline std::complex> sinh(const std::complex>& z) { - return stan::math::internal::complex_sinh(z); + return internal::complex_sinh(z); } } // namespace math diff --git a/stan/math/prim/fun/sin.hpp b/stan/math/prim/fun/sin.hpp index 3c5ae0937e0..233f35c7d59 100644 --- a/stan/math/prim/fun/sin.hpp +++ b/stan/math/prim/fun/sin.hpp @@ -3,6 +3,8 @@ #include #include +#include +#include #include namespace stan { @@ -48,6 +50,21 @@ inline auto sin(const Eigen::MatrixBase& x) { return x.derived().array().sin().matrix().eval(); } +namespace internal { +/** + * Return the sine of the complex argument. + * + * @tparam V value type of argument + * @param[in] z argument + * @return sine of the argument + */ +template +inline std::complex complex_sin(const std::complex& z) { + return neg_i_times(sinh(i_times(z))); +} +} // namespace internal + + } // namespace math } // namespace stan diff --git a/stan/math/rev/fun/sin.hpp b/stan/math/rev/fun/sin.hpp index 9a478e7b731..846dc743c0b 100644 --- a/stan/math/rev/fun/sin.hpp +++ b/stan/math/rev/fun/sin.hpp @@ -1,9 +1,11 @@ #ifndef STAN_MATH_REV_FUN_SIN_HPP #define STAN_MATH_REV_FUN_SIN_HPP +#include #include #include #include +#include namespace stan { namespace math { @@ -45,6 +47,16 @@ class sin_vari : public op_v_vari { */ inline var sin(const var& a) { return var(new internal::sin_vari(a.vi_)); } +/** + * Return the sine of the complex argument. + * + * @param[in] z argument + * @return sine of the argument + */ +inline std::complex sin(const std::complex& z) { + return stan::math::internal::complex_sin(z); +} + } // namespace math } // namespace stan #endif diff --git a/test/unit/math/mix/fun/sin_test.cpp b/test/unit/math/mix/fun/sin_test.cpp index 88ce5db4630..896351d76ee 100644 --- a/test/unit/math/mix/fun/sin_test.cpp +++ b/test/unit/math/mix/fun/sin_test.cpp @@ -1,7 +1,11 @@ #include TEST(mathMixMatFun, sin) { - auto f = [](const auto& x1) { return stan::math::sin(x1); }; + auto f = [](const auto& x1) { + using stan::math::sin; + return sin(x1); + }; stan::test::expect_common_nonzero_unary_vectorized(f); stan::test::expect_unary_vectorized(f, -2.6, -2, -0.2, 3, 5, 5.3); + stan::test::expect_complex_common(f); } From 77cdad1c35836ed567d46453b66bf9694136fe65 Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Tue, 10 Mar 2020 16:30:42 -0400 Subject: [PATCH 24/63] complex cosine --- stan/math/fwd/fun/cos.hpp | 16 +++++++++++++++- stan/math/fwd/fun/sin.hpp | 5 +++-- stan/math/prim/fun/cos.hpp | 17 +++++++++++++++++ stan/math/prim/fun/sin.hpp | 1 + stan/math/rev/fun/cos.hpp | 15 ++++++++++++++- stan/math/rev/fun/sin.hpp | 2 +- test/unit/math/mix/fun/cos_test.cpp | 6 +++++- 7 files changed, 56 insertions(+), 6 deletions(-) diff --git a/stan/math/fwd/fun/cos.hpp b/stan/math/fwd/fun/cos.hpp index de589753db3..0cfe38166b8 100644 --- a/stan/math/fwd/fun/cos.hpp +++ b/stan/math/fwd/fun/cos.hpp @@ -1,9 +1,11 @@ #ifndef STAN_MATH_FWD_FUN_COS_HPP #define STAN_MATH_FWD_FUN_COS_HPP -#include #include +#include +#include #include +#include namespace stan { namespace math { @@ -15,6 +17,18 @@ inline fvar cos(const fvar& x) { return fvar(cos(x.val_), x.d_ * -sin(x.val_)); } +/** + * Return the cosine of the complex argument. + * + * @tparam T autodiff value type + * @param[in] z argument + * @return cosine of the argument + */ +template +inline std::complex> cos(const std::complex>& z) { + return internal::complex_cos(z); +} + } // namespace math } // namespace stan #endif diff --git a/stan/math/fwd/fun/sin.hpp b/stan/math/fwd/fun/sin.hpp index bb5a5b11695..c938cf4948d 100644 --- a/stan/math/fwd/fun/sin.hpp +++ b/stan/math/fwd/fun/sin.hpp @@ -1,9 +1,10 @@ #ifndef STAN_MATH_FWD_FUN_SIN_HPP #define STAN_MATH_FWD_FUN_SIN_HPP -#include -#include #include +#include +#include +#include #include namespace stan { diff --git a/stan/math/prim/fun/cos.hpp b/stan/math/prim/fun/cos.hpp index cce0ddef2da..d0729ce85f7 100644 --- a/stan/math/prim/fun/cos.hpp +++ b/stan/math/prim/fun/cos.hpp @@ -2,8 +2,11 @@ #define STAN_MATH_PRIM_FUN_COS_HPP #include +#include #include +#include #include +#include namespace stan { namespace math { @@ -48,6 +51,20 @@ inline auto cos(const Eigen::MatrixBase& x) { return x.derived().array().cos().matrix().eval(); } +namespace internal { +/** + * Return the cosine of the complex argument. + * + * @tparam T value type of argument + * @param[in] z argument + * @return cosine of the argument + */ +template +inline std::complex complex_cos(const std::complex& z) { + return cosh(i_times(z)); +} +} + } // namespace math } // namespace stan diff --git a/stan/math/prim/fun/sin.hpp b/stan/math/prim/fun/sin.hpp index 233f35c7d59..b19ef5fd315 100644 --- a/stan/math/prim/fun/sin.hpp +++ b/stan/math/prim/fun/sin.hpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace stan { namespace math { diff --git a/stan/math/rev/fun/cos.hpp b/stan/math/rev/fun/cos.hpp index 7256f8ab23c..0e7f22e8c74 100644 --- a/stan/math/rev/fun/cos.hpp +++ b/stan/math/rev/fun/cos.hpp @@ -1,9 +1,11 @@ #ifndef STAN_MATH_REV_FUN_COS_HPP #define STAN_MATH_REV_FUN_COS_HPP -#include +#include #include +#include #include +#include namespace stan { namespace math { @@ -45,6 +47,17 @@ class cos_vari : public op_v_vari { */ inline var cos(const var& a) { return var(new internal::cos_vari(a.vi_)); } +/** + * Return the cosine of the complex argument. + * + * @param[in] z argument + * @return cosine of the argument + */ +inline std::complex cos(const std::complex& z) { + return stan::math::internal::complex_cos(z); +} + + } // namespace math } // namespace stan #endif diff --git a/stan/math/rev/fun/sin.hpp b/stan/math/rev/fun/sin.hpp index 846dc743c0b..5781b1cc643 100644 --- a/stan/math/rev/fun/sin.hpp +++ b/stan/math/rev/fun/sin.hpp @@ -2,8 +2,8 @@ #define STAN_MATH_REV_FUN_SIN_HPP #include -#include #include +#include #include #include diff --git a/test/unit/math/mix/fun/cos_test.cpp b/test/unit/math/mix/fun/cos_test.cpp index ccd3a79f5c7..bda64a2f8b6 100644 --- a/test/unit/math/mix/fun/cos_test.cpp +++ b/test/unit/math/mix/fun/cos_test.cpp @@ -1,8 +1,12 @@ #include TEST(mathMixMatFun, cos) { - auto f = [](const auto& x1) { return stan::math::cos(x1); }; + auto f = [](const auto& x) { + using stan::math::cos; + return cos(x); + }; stan::test::expect_common_nonzero_unary_vectorized(f); stan::test::expect_unary_vectorized(f, -2.6, -2, -0.2, -0.5, 0, 1.5, 3, 5, 5.3); + stan::test::expect_complex_common(f); } From 5095a242a67e77044852727e916a55615eb4c85f Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Tue, 10 Mar 2020 16:36:28 -0400 Subject: [PATCH 25/63] complex tan --- stan/math/fwd/fun/tan.hpp | 5 ++++- stan/math/prim/fun/tan.hpp | 17 +++++++++++++++++ stan/math/rev/fun/tan.hpp | 12 ++++++++++++ test/unit/math/mix/fun/tan_test.cpp | 6 +++++- 4 files changed, 38 insertions(+), 2 deletions(-) diff --git a/stan/math/fwd/fun/tan.hpp b/stan/math/fwd/fun/tan.hpp index 7fe5f92de5e..66ca0c2c071 100644 --- a/stan/math/fwd/fun/tan.hpp +++ b/stan/math/fwd/fun/tan.hpp @@ -1,8 +1,11 @@ #ifndef STAN_MATH_FWD_FUN_TAN_HPP #define STAN_MATH_FWD_FUN_TAN_HPP -#include #include +#include +#include +#include +#include namespace stan { namespace math { diff --git a/stan/math/prim/fun/tan.hpp b/stan/math/prim/fun/tan.hpp index 88048922084..774812827b0 100644 --- a/stan/math/prim/fun/tan.hpp +++ b/stan/math/prim/fun/tan.hpp @@ -3,7 +3,10 @@ #include #include +#include +#include #include +#include namespace stan { namespace math { @@ -48,6 +51,20 @@ inline auto tan(const Eigen::MatrixBase& x) { return x.derived().array().tan().matrix().eval(); } +namespace internal { +/** + * Return the tangent of the complex argument. + * + * @tparam V value type of argument + * @param[in] z argument + * @return tangent of the argument + */ +template +inline std::complex complex_tan(const std::complex& z) { + return neg_i_times(tanh(i_times(z))); +} +} // namespace internal + } // namespace math } // namespace stan diff --git a/stan/math/rev/fun/tan.hpp b/stan/math/rev/fun/tan.hpp index 28f03b6eb5e..fb94841e714 100644 --- a/stan/math/rev/fun/tan.hpp +++ b/stan/math/rev/fun/tan.hpp @@ -1,9 +1,11 @@ #ifndef STAN_MATH_REV_FUN_TAN_HPP #define STAN_MATH_REV_FUN_TAN_HPP +#include #include #include #include +#include namespace stan { namespace math { @@ -45,6 +47,16 @@ class tan_vari : public op_v_vari { */ inline var tan(const var& a) { return var(new internal::tan_vari(a.vi_)); } +/** + * Return the tangent of the complex argument. + * + * @param[in] z argument + * @return tangent of the argument + */ +inline std::complex tan(const std::complex& z) { + return stan::math::internal::complex_tan(z); +} + } // namespace math } // namespace stan #endif diff --git a/test/unit/math/mix/fun/tan_test.cpp b/test/unit/math/mix/fun/tan_test.cpp index 36c994d35e1..6570cd3b48b 100644 --- a/test/unit/math/mix/fun/tan_test.cpp +++ b/test/unit/math/mix/fun/tan_test.cpp @@ -1,7 +1,11 @@ #include TEST(mathMixMatFun, tan) { - auto f = [](const auto& x1) { return stan::math::tan(x1); }; + auto f = [](const auto& x) { + using stan::math::tan; + return tan(x); + }; stan::test::expect_common_nonzero_unary_vectorized(f); stan::test::expect_unary_vectorized(f, -2, -0.5, 0.5, 1.5, 3, 4.4); + stan::test::expect_complex_common(f); } From 673c4fc93bc2ab5921c38e98460057e27effcf7a Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Tue, 10 Mar 2020 17:09:52 -0400 Subject: [PATCH 26/63] complex asinh, acosh --- stan/math/fwd/fun/acosh.hpp | 15 ++++++++++++ stan/math/fwd/fun/asinh.hpp | 15 ++++++++---- stan/math/prim/fun/acosh.hpp | 23 ++++++++++++++++++ stan/math/prim/fun/asin.hpp | 1 + stan/math/prim/fun/asinh.hpp | 33 ++++++++++++++------------ stan/math/rev/fun/acosh.hpp | 16 +++++++++++-- stan/math/rev/fun/asinh.hpp | 16 +++++++++---- test/unit/math/mix/fun/acosh_test.cpp | 11 ++++++++- test/unit/math/mix/fun/asin_test.cpp | 7 ++++-- test/unit/math/mix/fun/asinh_test.cpp | 34 ++++++++++----------------- 10 files changed, 121 insertions(+), 50 deletions(-) diff --git a/stan/math/fwd/fun/acosh.hpp b/stan/math/fwd/fun/acosh.hpp index 948e7fe226c..b5c797bd41b 100644 --- a/stan/math/fwd/fun/acosh.hpp +++ b/stan/math/fwd/fun/acosh.hpp @@ -5,7 +5,10 @@ #include #include #include +#include #include +#include + namespace stan { namespace math { @@ -16,6 +19,18 @@ inline fvar acosh(const fvar& x) { return fvar(acosh(x.val_), x.d_ / sqrt(square(x.val_) - 1)); } +/** + * Return the hyperbolic arc cosine of the complex argument. + * + * @tparam T autodiff value type + * @param[in] z argument + * @return hyperbolic arc cosine of the argument + */ +template +inline std::complex> acosh(const std::complex>& z) { + return internal::complex_acosh(z); +} + } // namespace math } // namespace stan #endif diff --git a/stan/math/fwd/fun/asinh.hpp b/stan/math/fwd/fun/asinh.hpp index 6d90484d8d7..c2c362202d1 100644 --- a/stan/math/fwd/fun/asinh.hpp +++ b/stan/math/fwd/fun/asinh.hpp @@ -17,10 +17,17 @@ inline fvar asinh(const fvar& x) { return fvar(asinh(x.val_), x.d_ / sqrt(square(x.val_) + 1)); } -// template -// inline std::complex> asinh(const std::complex>& z) { -// return internal::complex_asinh(z); -// } +/** + * Return the hyperbolic arcsine of the complex argument. + * + * @tparam T autodiff value type + * @param[in] z argument + * @return hyperbolic arcsine of the argument + */ +template +inline std::complex> asinh(const std::complex>& z) { + return internal::complex_asinh(z); +} } // namespace math } // namespace stan diff --git a/stan/math/prim/fun/acosh.hpp b/stan/math/prim/fun/acosh.hpp index e0374ce8031..ee1d81f4399 100644 --- a/stan/math/prim/fun/acosh.hpp +++ b/stan/math/prim/fun/acosh.hpp @@ -3,9 +3,13 @@ #include #include +#include #include #include +#include +#include #include +#include namespace stan { namespace math { @@ -83,6 +87,25 @@ inline auto acosh(const T& x) { return apply_scalar_unary::apply(x); } +namespace internal { + +/** + * Return the hyperbolic arc cosine of the complex argument. + * + * @tparam V value type of argument + * @param[in] z argument + * @return hyperbolic arc cosine of the argument + */ +template +inline std::complex complex_acosh(const std::complex& z) { + std::complex y_d = acosh(value_of_rec(z)); + auto y = log(z + sqrt(z * z - 1)); + return copysign(y, y_d); +} + +} // namespace internal + + } // namespace math } // namespace stan diff --git a/stan/math/prim/fun/asin.hpp b/stan/math/prim/fun/asin.hpp index 71c133adad6..96d97d85a2b 100644 --- a/stan/math/prim/fun/asin.hpp +++ b/stan/math/prim/fun/asin.hpp @@ -3,6 +3,7 @@ #include #include +#include #include namespace stan { diff --git a/stan/math/prim/fun/asinh.hpp b/stan/math/prim/fun/asinh.hpp index c195a61f86a..0f64cba1eee 100644 --- a/stan/math/prim/fun/asinh.hpp +++ b/stan/math/prim/fun/asinh.hpp @@ -1,8 +1,11 @@ #ifndef STAN_MATH_PRIM_FUN_ASINH_HPP #define STAN_MATH_PRIM_FUN_ASINH_HPP +#include #include #include +#include +#include #include #include #include @@ -55,21 +58,21 @@ inline auto asinh(const T& x) { return apply_scalar_unary::apply(x); } -// namespace internal { -// /** -// * Return the hyperbolic arc sine of the complex argument. -// * -// * @tparam V value type of argument -// * @param[in] z argument -// * @return hyperbolic arc sine of the argument -// */ -// template -// inline std::complex complex_asinh(const std::complex& z) { -// std::complex y_d = asinh(value_of_rec(z)); -// auto y = log(z + sqrt(1 + z * z)); -// return copysign(y, y_d); -// } -// } // namespace internal +namespace internal { +/** + * Return the hyperbolic arc sine of the complex argument. + * + * @tparam V value type of argument + * @param[in] z argument + * @return hyperbolic arc sine of the argument + */ +template +inline std::complex complex_asinh(const std::complex& z) { + std::complex y_d = asinh(value_of_rec(z)); + auto y = log(z + sqrt(1 + z * z)); + return copysign(y, y_d); +} +} // namespace internal } // namespace math } // namespace stan diff --git a/stan/math/rev/fun/acosh.hpp b/stan/math/rev/fun/acosh.hpp index 3d4833445e5..9eca93df17b 100644 --- a/stan/math/rev/fun/acosh.hpp +++ b/stan/math/rev/fun/acosh.hpp @@ -1,10 +1,11 @@ #ifndef STAN_MATH_REV_FUN_ACOSH_HPP #define STAN_MATH_REV_FUN_ACOSH_HPP -#include -#include #include +#include +#include #include +#include namespace stan { namespace math { @@ -62,6 +63,17 @@ inline var acosh(const var& a) { return var(new internal::acosh_vari(acosh(a.val()), a.vi_)); } +/** + * Return the hyperbolic arc cosine of the complex argument. + * + * @param[in] z argument + * @return hyperbolic arc cosine of the argument + */ +inline std::complex acosh(const std::complex& z) { + return stan::math::internal::complex_acosh(z); +} + + } // namespace math } // namespace stan #endif diff --git a/stan/math/rev/fun/asinh.hpp b/stan/math/rev/fun/asinh.hpp index 2ad76b5418e..24d6ab7464d 100644 --- a/stan/math/rev/fun/asinh.hpp +++ b/stan/math/rev/fun/asinh.hpp @@ -1,9 +1,9 @@ #ifndef STAN_MATH_REV_FUN_ASINH_HPP #define STAN_MATH_REV_FUN_ASINH_HPP -#include -#include #include +#include +#include #include #include @@ -57,9 +57,15 @@ inline var asinh(const var& a) { return var(new internal::asinh_vari(asinh(a.val()), a.vi_)); } -// inline std::complex asinh(const std::complex& z) { -// return internal::complex_asinh(z); -// } +/** + * Return the hyperbolic arcsine of the complex argument. + * + * @param[in] z argument + * @return hyperbolic arcsine of the argument + */ +inline std::complex asinh(const std::complex& z) { + return stan::math::internal::complex_asinh(z); +} } // namespace math } // namespace stan diff --git a/test/unit/math/mix/fun/acosh_test.cpp b/test/unit/math/mix/fun/acosh_test.cpp index 3784354e961..9353551579b 100644 --- a/test/unit/math/mix/fun/acosh_test.cpp +++ b/test/unit/math/mix/fun/acosh_test.cpp @@ -1,8 +1,17 @@ #include TEST(mathMixMatFun, acosh) { - auto f = [](const auto& x1) { return stan::math::acosh(x1); }; + auto f = [](const auto& x1) { + using stan::math::acosh; + return acosh(x1); + }; for (double x : stan::test::internal::common_args()) stan::test::expect_unary_vectorized(x); stan::test::expect_unary_vectorized(f, 1.5, 3.2, 5, 10, 12.9); + // avoid pole at complex zero that can't be autodiffed + for (double re : std::vector{-0.2, 0, 0.3 }) { + for (double im : std::vector{-0.3, 0.2}) { + stan::test::expect_ad(f, std::complex{re, im}); + } + } } diff --git a/test/unit/math/mix/fun/asin_test.cpp b/test/unit/math/mix/fun/asin_test.cpp index badc174d3f2..af51a29e4e1 100644 --- a/test/unit/math/mix/fun/asin_test.cpp +++ b/test/unit/math/mix/fun/asin_test.cpp @@ -1,10 +1,13 @@ #include -#include TEST(mathMixMatFun, asin) { - auto f = [](const auto& x1) { return stan::math::asin(x1); }; + auto f = [](const auto& x1) { + using stan::math::asin; + return asin(x1); + }; // can't autodiff asin through integers for (auto x : stan::test::internal::common_nonzero_args()) stan::test::expect_unary_vectorized(f, x); stan::test::expect_unary_vectorized(f, -2.6, -2, -0.2, 0.7, 1.3, 3.4, 5); + stan::test::expect_complex_common(f); } diff --git a/test/unit/math/mix/fun/asinh_test.cpp b/test/unit/math/mix/fun/asinh_test.cpp index 231c5ea5138..d4badb9bf7b 100644 --- a/test/unit/math/mix/fun/asinh_test.cpp +++ b/test/unit/math/mix/fun/asinh_test.cpp @@ -1,25 +1,17 @@ #include TEST(mathMixFun, asinh) { - auto f = [](const auto& x1) { return stan::math::asinh(x1); }; - // stan::test::expect_common_unary_vectorized(f); - // stan::test::expect_unary_vectorized(f, -2.6, -1.2, -0.2, 0.5, 2, -1.2); - // stan::test::expect_complex_common(f); -} - -TEST(mathMixFun, asinhComplex) { - auto f = [](const auto& z) { return asinh(z); }; - stan::test::ad_tolerances tols; - tols.hessian_hessian_ = 1e-2; - tols.hessian_fvar_hessian_ = 1e-2; - // for (double re : std::vector{-1.1, 2.9}) { - // for (double im : std::vector{-1.1, 2.9}) { - // stan::test::expect_ad(tols, f, std::complex{re, im}); - // } - // } - // stan::test::expect_ad(tols, f, std::complex{1.1, -1.3}); - // stan::test::expect_ad(tols, f, std::complex{-1.1, -1.3}); - stan::test::expect_ad(tols, f, std::complex{0.1, 0.1}); - - stan::test::expect_complex_common(f); + auto f = [](const auto& x1) { + using stan::math::asinh; + return asinh(x1); + }; + stan::test::expect_common_unary_vectorized(f); + stan::test::expect_unary_vectorized(f, -2.6, -1.2, -0.2, 0.5, 2, -1.2); + stan::test::expect_ad(f, std::complex{0.2}); + // avoid pole at real zero that can't be autodiffed + for (double re : std::vector{-0.2, 0.3, }) { + for (double im : std::vector{-0.3, 0, 0.2}) { + stan::test::expect_ad(f, std::complex{re, im}); + } + } } From 654717dbff2614c350343cc435e1a241edc66b23 Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Tue, 10 Mar 2020 17:21:41 -0400 Subject: [PATCH 27/63] complex atanh --- stan/math/fwd/fun/asinh.hpp | 2 +- stan/math/fwd/fun/atanh.hpp | 16 +++++++++++++++- stan/math/prim/fun/atanh.hpp | 23 ++++++++++++++++++++++- stan/math/rev/fun/atanh.hpp | 14 +++++++++++++- test/unit/math/mix/fun/asinh_test.cpp | 2 +- test/unit/math/mix/fun/atanh_test.cpp | 10 +++++++++- 6 files changed, 61 insertions(+), 6 deletions(-) diff --git a/stan/math/fwd/fun/asinh.hpp b/stan/math/fwd/fun/asinh.hpp index c2c362202d1..4e430514ec4 100644 --- a/stan/math/fwd/fun/asinh.hpp +++ b/stan/math/fwd/fun/asinh.hpp @@ -1,8 +1,8 @@ #ifndef STAN_MATH_FWD_FUN_ASINH_HPP #define STAN_MATH_FWD_FUN_ASINH_HPP -#include #include +#include #include #include #include diff --git a/stan/math/fwd/fun/atanh.hpp b/stan/math/fwd/fun/atanh.hpp index bd1154d281c..ded211fd2d4 100644 --- a/stan/math/fwd/fun/atanh.hpp +++ b/stan/math/fwd/fun/atanh.hpp @@ -1,10 +1,12 @@ #ifndef STAN_MATH_FWD_FUN_ATANH_HPP #define STAN_MATH_FWD_FUN_ATANH_HPP -#include #include +#include #include #include +#include +#include namespace stan { namespace math { @@ -23,6 +25,18 @@ inline fvar atanh(const fvar& x) { return fvar(atanh(x.val_), x.d_ / (1 - square(x.val_))); } +/** + * Return the hyperbolic arc tangent of the complex argument. + * + * @tparam T autodiff value type + * @param[in] z argument + * @return hyperbolic arc tangent of the argument + */ +template +inline std::complex> atanh(const std::complex>& z) { + return internal::complex_atanh(z); +} + } // namespace math } // namespace stan #endif diff --git a/stan/math/prim/fun/atanh.hpp b/stan/math/prim/fun/atanh.hpp index 8a309ea9c12..1351a2ee0cc 100644 --- a/stan/math/prim/fun/atanh.hpp +++ b/stan/math/prim/fun/atanh.hpp @@ -1,10 +1,14 @@ #ifndef STAN_MATH_PRIM_FUN_ATANH_HPP #define STAN_MATH_PRIM_FUN_ATANH_HPP -#include +#include #include +#include +#include #include +#include #include +#include namespace stan { namespace math { @@ -76,6 +80,23 @@ inline auto atanh(const T& x) { return apply_scalar_unary::apply(x); } +namespace internal { +/** + * Return the hyperbolic arc tangent of the complex argument. + * + * @tparam V value type of argument + * @param[in] z argument + * @return hyperbolic arc tangent of the argument + */ +template +inline std::complex complex_atanh(const std::complex& z) { + std::complex y_d = atanh(value_of_rec(z)); + V one(1); + auto y = 0.5 * (log(one + z) - log(one - z)); + return copysign(y, y_d); +} +} // namespace internal + } // namespace math } // namespace stan diff --git a/stan/math/rev/fun/atanh.hpp b/stan/math/rev/fun/atanh.hpp index e1c0383f68d..e5f6ecfcb5d 100644 --- a/stan/math/rev/fun/atanh.hpp +++ b/stan/math/rev/fun/atanh.hpp @@ -1,9 +1,11 @@ #ifndef STAN_MATH_REV_FUN_ATANH_HPP #define STAN_MATH_REV_FUN_ATANH_HPP +#include #include #include -#include +#include +#include namespace stan { namespace math { @@ -59,6 +61,16 @@ inline var atanh(const var& a) { return var(new internal::atanh_vari(atanh(a.val()), a.vi_)); } +/** + * Return the hyperbolic arc tangent of the complex argument. + * + * @param[in] z argument + * @return hyperbolic arc tangent of the argument + */ +inline std::complex atanh(const std::complex& z) { + return stan::math::internal::complex_atanh(z); +} + } // namespace math } // namespace stan #endif diff --git a/test/unit/math/mix/fun/asinh_test.cpp b/test/unit/math/mix/fun/asinh_test.cpp index d4badb9bf7b..a7ed41559ff 100644 --- a/test/unit/math/mix/fun/asinh_test.cpp +++ b/test/unit/math/mix/fun/asinh_test.cpp @@ -9,7 +9,7 @@ TEST(mathMixFun, asinh) { stan::test::expect_unary_vectorized(f, -2.6, -1.2, -0.2, 0.5, 2, -1.2); stan::test::expect_ad(f, std::complex{0.2}); // avoid pole at real zero that can't be autodiffed - for (double re : std::vector{-0.2, 0.3, }) { + for (double re : std::vector{-0.2, 0.3 }) { for (double im : std::vector{-0.3, 0, 0.2}) { stan::test::expect_ad(f, std::complex{re, im}); } diff --git a/test/unit/math/mix/fun/atanh_test.cpp b/test/unit/math/mix/fun/atanh_test.cpp index 831ce1c697e..a701df7aceb 100644 --- a/test/unit/math/mix/fun/atanh_test.cpp +++ b/test/unit/math/mix/fun/atanh_test.cpp @@ -1,7 +1,15 @@ #include TEST(mathMixMatFun, atanh) { - auto f = [](const auto& x1) { return stan::math::atanh(x1); }; + auto f = [](const auto& x1) { + using stan::math::atanh; + return atanh(x1); + }; stan::test::expect_common_unary_vectorized(f); stan::test::expect_unary_vectorized(f, -0.9, 0.5); + for (double re : std::vector{-0.2, 0, 0.3 }) { + for (double im : std::vector{-0.3, 0, 0.2}) { + stan::test::expect_ad(f, std::complex{re, im}); + } + } } From 5d4bad1ec10ba9ab06d38eeaa0843b38365cd948 Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Tue, 10 Mar 2020 17:33:26 -0400 Subject: [PATCH 28/63] complex asin --- stan/math/fwd/fun/asin.hpp | 14 ++++++++++++++ stan/math/prim/fun/asin.hpp | 23 ++++++++++++++++++++++- stan/math/rev/fun/asin.hpp | 14 +++++++++++++- test/unit/math/mix/fun/asin_test.cpp | 10 +++++++--- 4 files changed, 56 insertions(+), 5 deletions(-) diff --git a/stan/math/fwd/fun/asin.hpp b/stan/math/fwd/fun/asin.hpp index a4d4e4de0c8..0ce1b593342 100644 --- a/stan/math/fwd/fun/asin.hpp +++ b/stan/math/fwd/fun/asin.hpp @@ -3,8 +3,10 @@ #include #include +#include #include #include +#include namespace stan { namespace math { @@ -16,6 +18,18 @@ inline fvar asin(const fvar& x) { return fvar(asin(x.val_), x.d_ / sqrt(1 - square(x.val_))); } +/** + * Return the arc sine of the complex argument. + * + * @tparam T autodiff value type + * @param[in] z argument + * @return arc sine of the argument + */ +template +inline std::complex> asin(const std::complex>& z) { + return internal::complex_asin(z); +} + } // namespace math } // namespace stan #endif diff --git a/stan/math/prim/fun/asin.hpp b/stan/math/prim/fun/asin.hpp index 96d97d85a2b..59c89cfc017 100644 --- a/stan/math/prim/fun/asin.hpp +++ b/stan/math/prim/fun/asin.hpp @@ -1,10 +1,15 @@ #ifndef STAN_MATH_PRIM_FUN_ASIN_HPP #define STAN_MATH_PRIM_FUN_ASIN_HPP +#include #include +#include +#include #include -#include +#include +#include #include +#include namespace stan { namespace math { @@ -49,6 +54,22 @@ inline auto asin(const Eigen::MatrixBase& x) { return x.derived().array().asin().matrix().eval(); } +namespace internal { +/** + * Return the arc sine of the complex argument. + * + * @tparam V value type of argument + * @param[in] z argument + * @return arc sine of the argument + */ +template +inline std::complex complex_asin(const std::complex& z) { + auto y_d = asin(value_of_rec(z)); + auto y = neg_i_times(asinh(i_times(z))); + return copysign(y, y_d); +} +} // namespace internal + } // namespace math } // namespace stan diff --git a/stan/math/rev/fun/asin.hpp b/stan/math/rev/fun/asin.hpp index 64e63d0a5fb..cf2485e2e08 100644 --- a/stan/math/rev/fun/asin.hpp +++ b/stan/math/rev/fun/asin.hpp @@ -1,9 +1,11 @@ #ifndef STAN_MATH_REV_FUN_ASIN_HPP #define STAN_MATH_REV_FUN_ASIN_HPP -#include +#include #include +#include #include +#include namespace stan { namespace math { @@ -56,6 +58,16 @@ class asin_vari : public op_v_vari { */ inline var asin(const var& a) { return var(new internal::asin_vari(a.vi_)); } +/** + * Return the arc sine of the complex argument. + * + * @param[in] z argument + * @return arc sine of the argument + */ +inline std::complex asin(const std::complex& z) { + return stan::math::internal::complex_asin(z); +} + } // namespace math } // namespace stan #endif diff --git a/test/unit/math/mix/fun/asin_test.cpp b/test/unit/math/mix/fun/asin_test.cpp index af51a29e4e1..20d8b5bbc06 100644 --- a/test/unit/math/mix/fun/asin_test.cpp +++ b/test/unit/math/mix/fun/asin_test.cpp @@ -1,13 +1,17 @@ #include TEST(mathMixMatFun, asin) { - auto f = [](const auto& x1) { + auto f = [](const auto& x) { using stan::math::asin; - return asin(x1); + return asin(x); }; // can't autodiff asin through integers for (auto x : stan::test::internal::common_nonzero_args()) stan::test::expect_unary_vectorized(f, x); stan::test::expect_unary_vectorized(f, -2.6, -2, -0.2, 0.7, 1.3, 3.4, 5); - stan::test::expect_complex_common(f); + for (double re : std::vector{-0.2, 0, 0.3 }) { + for (double im : std::vector{-0.3, 0, 0.2}) { + stan::test::expect_ad(f, std::complex{re, im}); + } + } } From 13a1e39973415cd7ef945b89c03dee0a1679d80d Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Tue, 10 Mar 2020 17:43:10 -0400 Subject: [PATCH 29/63] complex acos --- stan/math/fwd/fun/acos.hpp | 17 ++++++++++++++++- stan/math/prim/fun/acos.hpp | 20 ++++++++++++++++++++ stan/math/rev/fun/acos.hpp | 14 +++++++++++++- test/unit/math/mix/fun/acos_test.cpp | 11 ++++++++++- test/unit/math/mix/fun/asinh_test.cpp | 1 + 5 files changed, 60 insertions(+), 3 deletions(-) diff --git a/stan/math/fwd/fun/acos.hpp b/stan/math/fwd/fun/acos.hpp index b6f9bfbd683..a3cf5315686 100644 --- a/stan/math/fwd/fun/acos.hpp +++ b/stan/math/fwd/fun/acos.hpp @@ -1,10 +1,12 @@ #ifndef STAN_MATH_FWD_FUN_ACOS_HPP #define STAN_MATH_FWD_FUN_ACOS_HPP -#include #include +#include #include +#include #include +#include namespace stan { namespace math { @@ -15,6 +17,19 @@ inline fvar acos(const fvar& x) { using std::sqrt; return fvar(acos(x.val_), x.d_ / -sqrt(1 - square(x.val_))); } + +/** + * Return the arc cosine of the complex argument. + * + * @tparam T autodiff value type + * @param[in] z argument + * @return arc cosine of the argument + */ +template +inline std::complex> acos(const std::complex>& z) { + return internal::complex_acos(z); +} + } // namespace math } // namespace stan #endif diff --git a/stan/math/prim/fun/acos.hpp b/stan/math/prim/fun/acos.hpp index 3b9b0557b88..8973b566bd5 100644 --- a/stan/math/prim/fun/acos.hpp +++ b/stan/math/prim/fun/acos.hpp @@ -1,9 +1,13 @@ #ifndef STAN_MATH_PRIM_FUN_ACOS_HPP #define STAN_MATH_PRIM_FUN_ACOS_HPP +#include #include +#include +#include #include #include +#include namespace stan { namespace math { @@ -47,6 +51,22 @@ inline auto acos(const Eigen::MatrixBase& x) { return x.derived().array().acos().matrix().eval(); } +namespace internal { +/** + * Return the arc cosine of the complex argument. + * + * @tparam V value type of argument + * @param[in] z argument + * @return arc cosine of the argument + */ +template +inline std::complex complex_acos(const std::complex& z) { + return V(0.5 * pi()) - asin(z); +} +} + + + } // namespace math } // namespace stan diff --git a/stan/math/rev/fun/acos.hpp b/stan/math/rev/fun/acos.hpp index f6510e46191..602cf5eb457 100644 --- a/stan/math/rev/fun/acos.hpp +++ b/stan/math/rev/fun/acos.hpp @@ -1,9 +1,11 @@ #ifndef STAN_MATH_REV_FUN_ACOS_HPP #define STAN_MATH_REV_FUN_ACOS_HPP -#include +#include #include +#include #include +#include namespace stan { namespace math { @@ -56,6 +58,16 @@ class acos_vari : public op_v_vari { */ inline var acos(const var& a) { return var(new internal::acos_vari(a.vi_)); } +/** + * Return the arc cosine of the complex argument. + * + * @param[in] z argument + * @return arc cosine of the argument + */ +inline std::complex acos(const std::complex& z) { + return stan::math::internal::complex_acos(z); +} + } // namespace math } // namespace stan #endif diff --git a/test/unit/math/mix/fun/acos_test.cpp b/test/unit/math/mix/fun/acos_test.cpp index 7d274d7d19c..32486d9951b 100644 --- a/test/unit/math/mix/fun/acos_test.cpp +++ b/test/unit/math/mix/fun/acos_test.cpp @@ -1,13 +1,22 @@ #include #include +#include TEST(mathMixMatFun, acos) { using stan::test::expect_unary_vectorized; - auto f = [](const auto& x1) { return stan::math::acos(x1); }; + auto f = [](const auto& x1) { + using stan::math::acos; + return acos(x1); + }; // can't autodiff acos through integers for (auto x : stan::test::internal::common_nonzero_args()) stan::test::expect_unary_vectorized(f, x); expect_unary_vectorized(f, -2.2, -0.8, 0.5, 1 + std::numeric_limits::epsilon(), 1.5, 3, 3.4, 4); + for (double re : std::vector{-0.2, 0, 0.3 }) { + for (double im : std::vector{-0.3, 0, 0.2}) { + stan::test::expect_ad(f, std::complex{re, im}); + } + } } diff --git a/test/unit/math/mix/fun/asinh_test.cpp b/test/unit/math/mix/fun/asinh_test.cpp index a7ed41559ff..e71373c55b6 100644 --- a/test/unit/math/mix/fun/asinh_test.cpp +++ b/test/unit/math/mix/fun/asinh_test.cpp @@ -1,4 +1,5 @@ #include +#include TEST(mathMixFun, asinh) { auto f = [](const auto& x1) { From 606a3c3407ef185eb874c397dcc58aefab2a7337 Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Tue, 10 Mar 2020 17:52:50 -0400 Subject: [PATCH 30/63] complex atan --- stan/math/fwd/fun/atan.hpp | 16 +++++++++++++++- stan/math/prim/fun/atan.hpp | 18 ++++++++++++++++++ stan/math/rev/fun/atan.hpp | 14 +++++++++++++- test/unit/math/mix/fun/atan_test.cpp | 12 +++++++++++- 4 files changed, 57 insertions(+), 3 deletions(-) diff --git a/stan/math/fwd/fun/atan.hpp b/stan/math/fwd/fun/atan.hpp index 5ded2b132f4..a16f6ef8792 100644 --- a/stan/math/fwd/fun/atan.hpp +++ b/stan/math/fwd/fun/atan.hpp @@ -1,10 +1,12 @@ #ifndef STAN_MATH_FWD_FUN_ATAN_HPP #define STAN_MATH_FWD_FUN_ATAN_HPP -#include #include +#include +#include #include #include +#include namespace stan { namespace math { @@ -15,6 +17,18 @@ inline fvar atan(const fvar& x) { return fvar(atan(x.val_), x.d_ / (1 + square(x.val_))); } +/** + * Return the arc tangent of the complex argument. + * + * @tparam T autodiff value type + * @param[in] z argument + * @return arc tanget of the argument + */ +template +inline std::complex> atan(const std::complex>& z) { + return internal::complex_atan(z); +} + } // namespace math } // namespace stan #endif diff --git a/stan/math/prim/fun/atan.hpp b/stan/math/prim/fun/atan.hpp index 51a787f21bc..890c6a6a479 100644 --- a/stan/math/prim/fun/atan.hpp +++ b/stan/math/prim/fun/atan.hpp @@ -1,9 +1,13 @@ #ifndef STAN_MATH_PRIM_FUN_ATAN_HPP #define STAN_MATH_PRIM_FUN_ATAN_HPP +#include #include +#include #include +#include #include +#include namespace stan { namespace math { @@ -48,6 +52,20 @@ inline auto atan(const Eigen::MatrixBase& x) { return x.derived().array().atan().matrix().eval(); } +namespace internal { +/** + * Return the arc tangent of the complex argument. + * + * @tparam V value type of argument + * @param[in] z argument + * @return arc tangent of the argument + */ +template +inline std::complex complex_atan(const std::complex& z) { + return neg_i_times(atanh(i_times(z))); +} +} + } // namespace math } // namespace stan diff --git a/stan/math/rev/fun/atan.hpp b/stan/math/rev/fun/atan.hpp index 8a62d347fa3..a4357c9f42d 100644 --- a/stan/math/rev/fun/atan.hpp +++ b/stan/math/rev/fun/atan.hpp @@ -1,9 +1,11 @@ #ifndef STAN_MATH_REV_FUN_ATAN_HPP #define STAN_MATH_REV_FUN_ATAN_HPP -#include +#include #include +#include #include +#include namespace stan { namespace math { @@ -48,6 +50,16 @@ class atan_vari : public op_v_vari { */ inline var atan(const var& a) { return var(new internal::atan_vari(a.vi_)); } +/** + * Return the arc tangent of the complex argument. + * + * @param[in] z argument + * @return arc tangent of the argument + */ +inline std::complex atan(const std::complex& z) { + return stan::math::internal::complex_atan(z); +} + } // namespace math } // namespace stan #endif diff --git a/test/unit/math/mix/fun/atan_test.cpp b/test/unit/math/mix/fun/atan_test.cpp index 506bcc16099..f5d6c241fda 100644 --- a/test/unit/math/mix/fun/atan_test.cpp +++ b/test/unit/math/mix/fun/atan_test.cpp @@ -1,7 +1,17 @@ #include +#include TEST(mathMixMatFun, atan) { - auto f = [](const auto& x1) { return stan::math::atan(x1); }; + auto f = [](const auto& x) { + using stan::math::atan; + return atan(x); + }; stan::test::expect_common_nonzero_unary_vectorized(f); stan::test::expect_unary_vectorized(f, -2.6, -2, -0.2, 0.5, 1, 1.3, 1.5, 3); + // avoid 0 imaginary component where autodiff doesn't work + for (double re : std::vector{-0.2, 0, 0.3 }) { + for (double im : std::vector{-0.3, 0.2}) { + stan::test::expect_ad(f, std::complex{re, im}); + } + } } From ba8100a694c215075efd7ce8f5dbb24c7fbdf2b0 Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Tue, 10 Mar 2020 18:37:20 -0400 Subject: [PATCH 31/63] complex polar, still not passing with int args --- stan/math/fwd/fun/polar.hpp | 56 +++++++++++++++++++++++++++ stan/math/prim/fun/polar.hpp | 55 ++++++++++++++++++++++++++ stan/math/rev/fun/polar.hpp | 53 +++++++++++++++++++++++++ test/unit/math/mix/fun/polar_test.cpp | 19 +++++++++ 4 files changed, 183 insertions(+) create mode 100644 stan/math/fwd/fun/polar.hpp create mode 100644 stan/math/prim/fun/polar.hpp create mode 100644 stan/math/rev/fun/polar.hpp create mode 100644 test/unit/math/mix/fun/polar_test.cpp diff --git a/stan/math/fwd/fun/polar.hpp b/stan/math/fwd/fun/polar.hpp new file mode 100644 index 00000000000..891c2f0d500 --- /dev/null +++ b/stan/math/fwd/fun/polar.hpp @@ -0,0 +1,56 @@ +#ifndef STAN_MATH_FWD_FUN_POLAR_HPP +#define STAN_MATH_FWD_FUN_POLAR_HPP + +#include +#include +#include +#include +#include + +namespace stan { +namespace math { + +/** + * Returns complex number with specified magnitude and phase angle. + * + * @tparam T autodiff value type + * @param[in] r magnitude + * @param[in] theta phase angle + * @return complex number with magnitude and phase angle + */ +template +inline std::complex> polar(const fvar& r, const fvar& theta) { + return internal::complex_polar(r, theta); +} + +/** + * Returns complex number with specified magnitude and phase angle. + * + * @tparam T autodiff value type for magnitude + * @tparam U arithmetic type for phase angle + * @param[in] r magnitude + * @param[in] theta phase angle + * @return complex number with magnitude and phase angle + */ +template +inline std::complex> polar(const fvar& r, U theta) { + return internal::complex_polar(r, theta); +} + +/** + * Returns complex number with specified magnitude and phase angle. + * + * @tparam T autodiff value type for phase angle ++* * @tparam U arithmetic type for magnitude + * @param[in] r magnitude + * @param[in] theta phase angle + * @return complex number with magnitude and phase angle + */ +template +inline std::complex> polar(U r, const fvar& theta) { + return internal::complex_polar(r, theta); +} +} // namespace math +} // namespace stan + +#endif diff --git a/stan/math/prim/fun/polar.hpp b/stan/math/prim/fun/polar.hpp new file mode 100644 index 00000000000..8d364d9544d --- /dev/null +++ b/stan/math/prim/fun/polar.hpp @@ -0,0 +1,55 @@ +#ifndef STAN_MATH_PRIM_FUN_POLAR_HPP +#define STAN_MATH_PRIM_FUN_POLAR_HPP + +#include +#include +#include +#include +#include + +namespace stan { +namespace math { +namespace internal { +/** + * Returns complex number with specified magnitude and phase angle. + * + * @param[in] r magnitude + * @param[in] theta phase angle + * @return complex number with magnitude and phase angle + */ +template +inline complex_return_t complex_polar(const U& r, const V& theta) { + using std::cos; + using std::sin; + if (!(r >= 0) || is_inf(theta)) { + return {std::numeric_limits::quiet_NaN()}; + } + return {r * cos(theta), r * sin(theta)}; +} +} // namespace internal + + +/** + * Returns the complex number with specified magnitude and phase angle. + * + * @param[in] r magnitude + * @param[in] theta phase angle + * @return complex number with magnitude and phase angle + */ +std::complex polar(double r, double theta) { + return internal::complex_polar(r, theta); +} +std::complex polar(double r, int theta) { + return internal::complex_polar(r, static_cast(theta)); +} +std::complex polar(int r, double theta) { + return internal::complex_polar(static_cast(r), theta); +} +std::complex polar(int r, int theta) { + return internal::complex_polar(static_cast(r), static_cast(theta)); +} + +} // namespace math +} // namespace stan + +#endif diff --git a/stan/math/rev/fun/polar.hpp b/stan/math/rev/fun/polar.hpp new file mode 100644 index 00000000000..ab5339d2f6f --- /dev/null +++ b/stan/math/rev/fun/polar.hpp @@ -0,0 +1,53 @@ +#ifndef STAN_MATH_REV_FUN_POLAR_HPP +#define STAN_MATH_REV_FUN_POLAR_HPP + +#include +#include +#include +#include +#include + +namespace stan { +namespace math { + +/** + * Returns complex number with specified magnitude and phase angle. + * + * @param[in] r magnitude + * @param[in] theta phase angle + * @return complex number with magnitude and phase angle + */ +inline std::complex polar(const var& r, const var& theta) { + return internal::complex_polar(r, theta); +} + +/** + * Returns complex number with specified magnitude and phase angle. + * + * @tparam T arithmetic type of magnitude + * @param[in] r magnitude + * @param[in] theta phase angle + * @return complex number with magnitude and phase angle + */ +template +inline std::complex polar(T r, const var& theta) { + return internal::complex_polar(r, theta); +} + +/** + * Returns complex number with specified magnitude and phase angle. + * + * @tparam T arithmetic type of phase angle + * @param[in] r magnitude + * @param[in] theta phase angle + * @return complex number with magnitude and phase angle + */ +template +inline std::complex polar(const var& r, T theta) { + return internal::complex_polar(r, theta); +} + +} // namespace math +} // namespace stan + +#endif diff --git a/test/unit/math/mix/fun/polar_test.cpp b/test/unit/math/mix/fun/polar_test.cpp new file mode 100644 index 00000000000..c6ae290aa32 --- /dev/null +++ b/test/unit/math/mix/fun/polar_test.cpp @@ -0,0 +1,19 @@ +#include +#include +#include + +TEST(mathMixMatFun, polar) { + auto f = [](const auto& r, const auto& theta) { + using stan::math::polar; + return polar(r, theta); + }; + stan::test::expect_ad(f, 0.5, 0.5); + // TODO(carpente): these need to work + // stan::test::expect_ad(f, 1, 0.5); + // stan::test::expect_ad(f, 0.5, 1); + // stan::test::expect_ad(f, 1, 1); + // stan::test::expect_common_binary(f); + + // need to fix this, too, because it's failing + // EXPECT_TRUE(stan::is_stan_scalar>::value); +} From 01fb26af97dc1cb1a3dcc72afae3ab2ba14c5d80 Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Tue, 10 Mar 2020 22:30:00 -0400 Subject: [PATCH 32/63] complex polar tests componentwise --- stan/math/prim/fun/polar.hpp | 4 +-- stan/math/prim/fun/tanh.hpp | 3 +- test/unit/math/mix/fun/polar_test.cpp | 46 +++++++++++++++++++++++---- 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/stan/math/prim/fun/polar.hpp b/stan/math/prim/fun/polar.hpp index 8d364d9544d..76923bb5a7f 100644 --- a/stan/math/prim/fun/polar.hpp +++ b/stan/math/prim/fun/polar.hpp @@ -28,7 +28,6 @@ inline complex_return_t complex_polar(const U& r, const V& theta) { } } // namespace internal - /** * Returns the complex number with specified magnitude and phase angle. * @@ -46,7 +45,8 @@ std::complex polar(int r, double theta) { return internal::complex_polar(static_cast(r), theta); } std::complex polar(int r, int theta) { - return internal::complex_polar(static_cast(r), static_cast(theta)); + return internal::complex_polar(static_cast(r), + static_cast(theta)); } } // namespace math diff --git a/stan/math/prim/fun/tanh.hpp b/stan/math/prim/fun/tanh.hpp index d09302e8333..63d3b8149b1 100644 --- a/stan/math/prim/fun/tanh.hpp +++ b/stan/math/prim/fun/tanh.hpp @@ -65,7 +65,8 @@ inline std::complex complex_tanh(const std::complex& z) { using stan::math::operator/; auto exp_z = exp(z); auto exp_neg_z = exp(-z); - return stan::math::internal::complex_divide(exp_z - exp_neg_z, exp_z + exp_neg_z); + return stan::math::internal::complex_divide(exp_z - exp_neg_z, + exp_z + exp_neg_z); } } // namespace internal diff --git a/test/unit/math/mix/fun/polar_test.cpp b/test/unit/math/mix/fun/polar_test.cpp index c6ae290aa32..d0e6c70cf3b 100644 --- a/test/unit/math/mix/fun/polar_test.cpp +++ b/test/unit/math/mix/fun/polar_test.cpp @@ -1,18 +1,52 @@ #include #include #include +#include TEST(mathMixMatFun, polar) { + // test framework can't handle (real x real) -> complex, so factor tests auto f = [](const auto& r, const auto& theta) { using stan::math::polar; - return polar(r, theta); + auto y = polar(r, theta); + return y; }; - stan::test::expect_ad(f, 0.5, 0.5); - // TODO(carpente): these need to work + + stan::test::expect_ad(f, 0.2, 0.5); + // TODO(carpenter): fix this so it succeeds in test framework // stan::test::expect_ad(f, 1, 0.5); - // stan::test::expect_ad(f, 0.5, 1); - // stan::test::expect_ad(f, 1, 1); - // stan::test::expect_common_binary(f); + + auto f1 = [](const auto& r, const auto& theta) { + using stan::math::polar; + auto y = polar(r, theta); + return y.real(); + }; + + auto f2 = [](const auto& r, const auto& theta) { + using stan::math::polar; + auto y = polar(r, theta); + return y.imag(); + }; + stan::test::expect_ad(f1, 1, 1); + stan::test::expect_ad(f2, 1, 1); + + std::vector rs{-2.3, -0.3, 0.4, 1.2}; + std::vector thetas{-0.2, 0, 0.1}; + + for (double r : rs) { + for (double theta : thetas) { + stan::test::expect_ad(f1, r, theta); + stan::test::expect_ad(f2, r, theta); + } + } + + for (double r : rs) { + stan::test::expect_ad(f1, r, 1); + stan::test::expect_ad(f2, r, 1); + } + for (double theta : thetas) { + stan::test::expect_ad(f1, 1, theta); + stan::test::expect_ad(f2, 1, theta); + } // need to fix this, too, because it's failing // EXPECT_TRUE(stan::is_stan_scalar>::value); From c69263a583948c5a4877002a8a7eaf784eb1e88a Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Tue, 10 Mar 2020 23:03:34 -0400 Subject: [PATCH 33/63] cpplint include and spacing fixes --- stan/math/fwd/core/operator_division.hpp | 22 ++++++------- stan/math/fwd/fun/pow.hpp | 13 ++++---- stan/math/rev/core.hpp | 1 - stan/math/rev/core/operator_division.hpp | 24 ++++++-------- stan/math/rev/core/std_complex.hpp | 3 +- stan/math/rev/fun/norm.hpp | 4 ++- stan/math/rev/fun/pow.hpp | 7 ++--- .../math/mix/core/operator_division_test.cpp | 11 ++++--- test/unit/math/mix/fun/acos_test.cpp | 5 +-- test/unit/math/mix/fun/acosh_test.cpp | 3 +- test/unit/math/mix/fun/asin_test.cpp | 3 +- test/unit/math/mix/fun/asinh_test.cpp | 3 +- test/unit/math/mix/fun/atan_test.cpp | 3 +- test/unit/math/mix/fun/atanh_test.cpp | 3 +- test/unit/math/mix/fun/log10_test.cpp | 5 +-- test/unit/math/mix/fun/log_test.cpp | 7 +++-- test/unit/math/mix/fun/logb_test.cpp | 3 +- test/unit/math/mix/fun/pow_test.cpp | 31 ++++++++++--------- test/unit/math/mix/fun/scalbn_test.cpp | 5 +-- test/unit/math/mix/fun/sqrt_test.cpp | 1 + 20 files changed, 82 insertions(+), 75 deletions(-) diff --git a/stan/math/fwd/core/operator_division.hpp b/stan/math/fwd/core/operator_division.hpp index de6c54f5230..b99e140cbf0 100644 --- a/stan/math/fwd/core/operator_division.hpp +++ b/stan/math/fwd/core/operator_division.hpp @@ -43,24 +43,24 @@ inline fvar operator/(const fvar& x1, U x2) { * @param x2 second argument * @return first argument divided by second argument */ -template ...> +template ...> inline fvar operator/(U x1, const fvar& x2) { return fvar(x1 / x2.val_, -x1 * x2.d_ / (x2.val_ * x2.val_)); } template inline std::complex> operator/(const std::complex>& x1, - const std::complex>& x2) { + const std::complex>& x2) { return internal::complex_divide(x1, x2); } - template ...> +template ...> inline std::complex> operator/(const std::complex>& x1, - const std::complex& x2) { + const std::complex& x2) { return internal::complex_divide(x1, x2); } template inline std::complex> operator/(const std::complex>& x1, - const fvar& x2) { + const fvar& x2) { return internal::complex_divide(x1, x2); } template ...> @@ -70,28 +70,28 @@ inline std::complex> operator/(const std::complex>& x1, U x2) { template ...> inline std::complex> operator/(const std::complex& x1, - const std::complex>& x2) { + const std::complex>& x2) { return internal::complex_divide(x1, x2); } template ...> inline std::complex> operator/(const std::complex& x1, - const fvar& x2) { + const fvar& x2) { return internal::complex_divide(x1, x2); } template inline std::complex> operator/(const fvar& x1, - const std::complex>& x2) { + const std::complex>& x2) { return internal::complex_divide(x1, x2); } template ::value>> + typename = std::enable_if_t::value>> inline std::complex> operator/(const fvar& x1, - const std::complex& x2) { + const std::complex& x2) { return internal::complex_divide(x1, x2); } -template ...> +template ...> inline std::complex> operator/(U x1, const std::complex>& x2) { return internal::complex_divide(x1, x2); } diff --git a/stan/math/fwd/fun/pow.hpp b/stan/math/fwd/fun/pow.hpp index dc5ebe0622f..840ca06dcf1 100644 --- a/stan/math/fwd/fun/pow.hpp +++ b/stan/math/fwd/fun/pow.hpp @@ -78,7 +78,7 @@ inline fvar pow(const fvar& x1, U x2) { */ template inline std::complex> pow(const std::complex>& x, - const std::complex>& y) { + const std::complex>& y) { return internal::complex_pow(x, y); } @@ -93,7 +93,7 @@ inline std::complex> pow(const std::complex>& x, */ template > inline std::complex> pow(const std::complex>& x, - const std::complex& y) { + const std::complex& y) { return internal::complex_pow(x, y); } @@ -107,7 +107,7 @@ inline std::complex> pow(const std::complex>& x, */ template inline std::complex> pow(const std::complex>& x, - const fvar& y) { + const fvar& y) { return internal::complex_pow(x, y); } @@ -121,8 +121,7 @@ inline std::complex> pow(const std::complex>& x, * @return first argument to the power of the second argument */ template > -inline std::complex> pow(const std::complex>& x, - const T& y) { +inline std::complex> pow(const std::complex>& x, const T& y) { return internal::complex_pow(x, y); } @@ -137,7 +136,7 @@ inline std::complex> pow(const std::complex>& x, */ template > inline std::complex> pow(const std::complex& x, - const std::complex>& y) { + const std::complex>& y) { return internal::complex_pow(x, y); } @@ -165,7 +164,7 @@ inline std::complex> pow(const std::complex& x, const fvar& y) { */ template inline std::complex> pow(const fvar& x, - const std::complex>& y) { + const std::complex>& y) { return internal::complex_pow(x, y); } diff --git a/stan/math/rev/core.hpp b/stan/math/rev/core.hpp index b6b1891abd8..5d3c91f423b 100644 --- a/stan/math/rev/core.hpp +++ b/stan/math/rev/core.hpp @@ -51,7 +51,6 @@ #include #include #include -#include #include #include #include diff --git a/stan/math/rev/core/operator_division.hpp b/stan/math/rev/core/operator_division.hpp index f5e968104c4..5178d9080bb 100644 --- a/stan/math/rev/core/operator_division.hpp +++ b/stan/math/rev/core/operator_division.hpp @@ -134,49 +134,43 @@ inline var operator/(Arith dividend, var divisor) { } inline std::complex operator/(const std::complex& x1, - const std::complex& x2) { + const std::complex& x2) { return internal::complex_divide(x1, x2); } template ...> inline std::complex operator/(const std::complex& x1, - const std::complex& x2) { + const std::complex& x2) { return internal::complex_divide(x1, x2); } -inline std::complex operator/(const std::complex& x1, - const var& x2) { +inline std::complex operator/(const std::complex& x1, const var& x2) { return internal::complex_divide(x1, x2); } template ...> -inline std::complex operator/(const std::complex& x1, - T x2) { +inline std::complex operator/(const std::complex& x1, T x2) { return internal::complex_divide(x1, x2); } template ...> inline std::complex operator/(const std::complex& x1, - const std::complex& x2) { + const std::complex& x2) { return internal::complex_divide(x1, x2); } template ...> -inline std::complex operator/(const std::complex& x1, - const var& x2) { +inline std::complex operator/(const std::complex& x1, const var& x2) { return internal::complex_divide(x1, x2); } -inline std::complex operator/(const var& x1, - const std::complex& x2) { +inline std::complex operator/(const var& x1, const std::complex& x2) { return internal::complex_divide(x1, x2); } template ...> -inline std::complex operator/(const var& x1, - const std::complex& x2) { +inline std::complex operator/(const var& x1, const std::complex& x2) { return internal::complex_divide(x1, x2); } template ...> -inline std::complex operator/(T x1, - const std::complex& x2) { +inline std::complex operator/(T x1, const std::complex& x2) { return internal::complex_divide(x1, x2); } diff --git a/stan/math/rev/core/std_complex.hpp b/stan/math/rev/core/std_complex.hpp index b3d67b9643d..a68140ea742 100644 --- a/stan/math/rev/core/std_complex.hpp +++ b/stan/math/rev/core/std_complex.hpp @@ -46,7 +46,8 @@ class complex complex(const U& re) : base_t(re) {} // NOLINT(runtime/explicit) template - complex(const std::complex& z) : base_t(z.real(), z.imag()) {} + complex(const std::complex& z) // NOLINT(runtime/explicit) + : base_t(z.real(), z.imag()) {} /** * Set the real and imaginary components of this complex number to diff --git a/stan/math/rev/fun/norm.hpp b/stan/math/rev/fun/norm.hpp index 39ec4a7f9d7..6ded7229bb3 100644 --- a/stan/math/rev/fun/norm.hpp +++ b/stan/math/rev/fun/norm.hpp @@ -14,7 +14,9 @@ namespace math { * @param[in] z argument * @return squared magnitude of the argument */ -inline var norm(const std::complex& z) { return internal::complex_norm(z); } +inline var norm(const std::complex& z) { + return internal::complex_norm(z); +} } // namespace math } // namespace stan diff --git a/stan/math/rev/fun/pow.hpp b/stan/math/rev/fun/pow.hpp index 6c51a3a62da..19bbe7aa4ea 100644 --- a/stan/math/rev/fun/pow.hpp +++ b/stan/math/rev/fun/pow.hpp @@ -193,7 +193,7 @@ inline var pow(T base, const var& exponent) { * @return first argument to the power of the second argument */ inline std::complex pow(const std::complex& x, - const std::complex& y) { + const std::complex& y) { return internal::complex_pow(x, y); } @@ -207,7 +207,7 @@ inline std::complex pow(const std::complex& x, */ template > inline std::complex pow(const std::complex& x, - const std::complex y) { + const std::complex y) { return internal::complex_pow(x, y); } @@ -293,12 +293,11 @@ inline std::complex pow(const var& x, std::complex y) { * @param y second argument * @return first argument to the power of the second argument */ - template > +template > inline std::complex pow(T x, const std::complex& y) { return internal::complex_pow(x, y); } - } // namespace math } // namespace stan #endif diff --git a/test/unit/math/mix/core/operator_division_test.cpp b/test/unit/math/mix/core/operator_division_test.cpp index c6222fce86c..06bf2e9b291 100644 --- a/test/unit/math/mix/core/operator_division_test.cpp +++ b/test/unit/math/mix/core/operator_division_test.cpp @@ -1,4 +1,5 @@ #include +#include TEST(mathMixCore, operatorDivision) { auto f = [](const auto& x1, const auto& x2) { return x1 / x2; }; @@ -18,16 +19,16 @@ TEST(mathMixCore, operatorDivision) { } } for (auto re1 : common_finite) { - for (auto re2 : common_finite) { - for (auto im2 : common_finite_nz) { - stan::test::expect_ad(f, re1, std::complex(re2, im2)); - } + for (auto re2 : common_finite) { + for (auto im2 : common_finite_nz) { + stan::test::expect_ad(f, re1, std::complex(re2, im2)); } + } } for (auto re1 : common_finite) { for (auto im1 : common_finite_nz) { for (auto re2 : common_finite) { - stan::test::expect_ad(f, std::complex(re1, im1), re2); + stan::test::expect_ad(f, std::complex(re1, im1), re2); } } } diff --git a/test/unit/math/mix/fun/acos_test.cpp b/test/unit/math/mix/fun/acos_test.cpp index 32486d9951b..350fc5ef687 100644 --- a/test/unit/math/mix/fun/acos_test.cpp +++ b/test/unit/math/mix/fun/acos_test.cpp @@ -1,6 +1,7 @@ #include -#include #include +#include +#include TEST(mathMixMatFun, acos) { using stan::test::expect_unary_vectorized; @@ -14,7 +15,7 @@ TEST(mathMixMatFun, acos) { expect_unary_vectorized(f, -2.2, -0.8, 0.5, 1 + std::numeric_limits::epsilon(), 1.5, 3, 3.4, 4); - for (double re : std::vector{-0.2, 0, 0.3 }) { + for (double re : std::vector{-0.2, 0, 0.3}) { for (double im : std::vector{-0.3, 0, 0.2}) { stan::test::expect_ad(f, std::complex{re, im}); } diff --git a/test/unit/math/mix/fun/acosh_test.cpp b/test/unit/math/mix/fun/acosh_test.cpp index 9353551579b..3f3bd50ee4c 100644 --- a/test/unit/math/mix/fun/acosh_test.cpp +++ b/test/unit/math/mix/fun/acosh_test.cpp @@ -1,4 +1,5 @@ #include +#include TEST(mathMixMatFun, acosh) { auto f = [](const auto& x1) { @@ -9,7 +10,7 @@ TEST(mathMixMatFun, acosh) { stan::test::expect_unary_vectorized(x); stan::test::expect_unary_vectorized(f, 1.5, 3.2, 5, 10, 12.9); // avoid pole at complex zero that can't be autodiffed - for (double re : std::vector{-0.2, 0, 0.3 }) { + for (double re : std::vector{-0.2, 0, 0.3}) { for (double im : std::vector{-0.3, 0.2}) { stan::test::expect_ad(f, std::complex{re, im}); } diff --git a/test/unit/math/mix/fun/asin_test.cpp b/test/unit/math/mix/fun/asin_test.cpp index 20d8b5bbc06..6873a587510 100644 --- a/test/unit/math/mix/fun/asin_test.cpp +++ b/test/unit/math/mix/fun/asin_test.cpp @@ -1,4 +1,5 @@ #include +#include TEST(mathMixMatFun, asin) { auto f = [](const auto& x) { @@ -9,7 +10,7 @@ TEST(mathMixMatFun, asin) { for (auto x : stan::test::internal::common_nonzero_args()) stan::test::expect_unary_vectorized(f, x); stan::test::expect_unary_vectorized(f, -2.6, -2, -0.2, 0.7, 1.3, 3.4, 5); - for (double re : std::vector{-0.2, 0, 0.3 }) { + for (double re : std::vector{-0.2, 0, 0.3}) { for (double im : std::vector{-0.3, 0, 0.2}) { stan::test::expect_ad(f, std::complex{re, im}); } diff --git a/test/unit/math/mix/fun/asinh_test.cpp b/test/unit/math/mix/fun/asinh_test.cpp index e71373c55b6..f218bccdac1 100644 --- a/test/unit/math/mix/fun/asinh_test.cpp +++ b/test/unit/math/mix/fun/asinh_test.cpp @@ -1,5 +1,6 @@ #include #include +#include TEST(mathMixFun, asinh) { auto f = [](const auto& x1) { @@ -10,7 +11,7 @@ TEST(mathMixFun, asinh) { stan::test::expect_unary_vectorized(f, -2.6, -1.2, -0.2, 0.5, 2, -1.2); stan::test::expect_ad(f, std::complex{0.2}); // avoid pole at real zero that can't be autodiffed - for (double re : std::vector{-0.2, 0.3 }) { + for (double re : std::vector{-0.2, 0.3}) { for (double im : std::vector{-0.3, 0, 0.2}) { stan::test::expect_ad(f, std::complex{re, im}); } diff --git a/test/unit/math/mix/fun/atan_test.cpp b/test/unit/math/mix/fun/atan_test.cpp index f5d6c241fda..3c668654fc4 100644 --- a/test/unit/math/mix/fun/atan_test.cpp +++ b/test/unit/math/mix/fun/atan_test.cpp @@ -1,5 +1,6 @@ #include #include +#include TEST(mathMixMatFun, atan) { auto f = [](const auto& x) { @@ -9,7 +10,7 @@ TEST(mathMixMatFun, atan) { stan::test::expect_common_nonzero_unary_vectorized(f); stan::test::expect_unary_vectorized(f, -2.6, -2, -0.2, 0.5, 1, 1.3, 1.5, 3); // avoid 0 imaginary component where autodiff doesn't work - for (double re : std::vector{-0.2, 0, 0.3 }) { + for (double re : std::vector{-0.2, 0, 0.3}) { for (double im : std::vector{-0.3, 0.2}) { stan::test::expect_ad(f, std::complex{re, im}); } diff --git a/test/unit/math/mix/fun/atanh_test.cpp b/test/unit/math/mix/fun/atanh_test.cpp index a701df7aceb..fbf9dcf6da4 100644 --- a/test/unit/math/mix/fun/atanh_test.cpp +++ b/test/unit/math/mix/fun/atanh_test.cpp @@ -1,4 +1,5 @@ #include +#include TEST(mathMixMatFun, atanh) { auto f = [](const auto& x1) { @@ -7,7 +8,7 @@ TEST(mathMixMatFun, atanh) { }; stan::test::expect_common_unary_vectorized(f); stan::test::expect_unary_vectorized(f, -0.9, 0.5); - for (double re : std::vector{-0.2, 0, 0.3 }) { + for (double re : std::vector{-0.2, 0, 0.3}) { for (double im : std::vector{-0.3, 0, 0.2}) { stan::test::expect_ad(f, std::complex{re, im}); } diff --git a/test/unit/math/mix/fun/log10_test.cpp b/test/unit/math/mix/fun/log10_test.cpp index 85bb4653c4e..b572db0dcd5 100644 --- a/test/unit/math/mix/fun/log10_test.cpp +++ b/test/unit/math/mix/fun/log10_test.cpp @@ -1,4 +1,5 @@ #include +#include TEST(mathMixMatFun, log10) { auto f = [](const auto& x1) { @@ -10,8 +11,8 @@ TEST(mathMixMatFun, log10) { 1e6); // non-zero real and imaginary components - for (auto re : std::vector{ -2.7, 1, 2.3 }) { - for (auto im : std::vector{ -1.5, 1.2 }) { + for (auto re : std::vector{-2.7, 1, 2.3}) { + for (auto im : std::vector{-1.5, 1.2}) { stan::test::expect_ad(f, std::complex{re, im}); } } diff --git a/test/unit/math/mix/fun/log_test.cpp b/test/unit/math/mix/fun/log_test.cpp index 41a4de6aae8..21ff2c8fa03 100644 --- a/test/unit/math/mix/fun/log_test.cpp +++ b/test/unit/math/mix/fun/log_test.cpp @@ -1,4 +1,5 @@ #include +#include TEST(mathMixMatFun, log) { auto f = [](const auto& x1) { @@ -7,11 +8,11 @@ TEST(mathMixMatFun, log) { }; stan::test::expect_common_unary_vectorized(f); stan::test::expect_unary_vectorized(f, -0.2, 1e-3, 1, 1.3, 3, 3.7, 10, 10.2, - 1e6); + 1e6); // non-zero real and imaginary components - for (auto re : std::vector{ -2.7, 1, 2.3 }) { - for (auto im : std::vector{ -1.5, 1.2 }) { + for (auto re : std::vector{-2.7, 1, 2.3}) { + for (auto im : std::vector{-1.5, 1.2}) { stan::test::expect_ad(f, std::complex{re, im}); } } diff --git a/test/unit/math/mix/fun/logb_test.cpp b/test/unit/math/mix/fun/logb_test.cpp index 7562e64c10e..840ee6f3d47 100644 --- a/test/unit/math/mix/fun/logb_test.cpp +++ b/test/unit/math/mix/fun/logb_test.cpp @@ -1,6 +1,7 @@ #include #include #include +#include template void expect_logb(double x) { @@ -10,8 +11,8 @@ void expect_logb(double x) { } void expect_all_logb(double x) { - using stan::math::var; using stan::math::fvar; + using stan::math::var; expect_logb(x); expect_logb(x); expect_logb>(x); diff --git a/test/unit/math/mix/fun/pow_test.cpp b/test/unit/math/mix/fun/pow_test.cpp index b312398f241..aec26627dca 100644 --- a/test/unit/math/mix/fun/pow_test.cpp +++ b/test/unit/math/mix/fun/pow_test.cpp @@ -1,6 +1,7 @@ #include #include #include +#include template void expect_arith_instantiate() { @@ -56,28 +57,28 @@ TEST(mathMixFun, complexPow) { tols.hessian_hessian_ = 5e-3; tols.hessian_fvar_hessian_ = 5e-3; // complex, complex - for (auto re1 : std::vector{ -1.8, 3.4 }) { - for (auto im1 : std::vector{ -1.8, 3.4 }) { - for (auto re2 : std::vector{ -2.7, 1, 2.3 }) { - for (auto im2 : std::vector{ -1.5, 1.2 }) { - stan::test::expect_ad(tols, f, std::complex{re1, im1}, - std::complex{re2, im2}); - } + for (auto re1 : std::vector{-1.8, 3.4}) { + for (auto im1 : std::vector{-1.8, 3.4}) { + for (auto re2 : std::vector{-2.7, 1, 2.3}) { + for (auto im2 : std::vector{-1.5, 1.2}) { + stan::test::expect_ad(tols, f, std::complex{re1, im1}, + std::complex{re2, im2}); + } } } } // if real, first arg must be positive - for (auto re1 : std::vector{ 3.4 }) { - for (auto re2 : std::vector{ -2.7, 1, 2.3 }) { - for (auto im2 : std::vector{ -1.5, 1.2 }) { - stan::test::expect_ad(tols, f, re1, std::complex{re2, im2}); + for (auto re1 : std::vector{3.4}) { + for (auto re2 : std::vector{-2.7, 1, 2.3}) { + for (auto im2 : std::vector{-1.5, 1.2}) { + stan::test::expect_ad(tols, f, re1, std::complex{re2, im2}); } } } - for (auto re1 : std::vector{ -1.8, 3.4 }) { - for (auto im1 : std::vector{ -1.8, 3.4 }) { - for (auto re2 : std::vector{ -2.7, 1, 2.3 }) { - stan::test::expect_ad(tols, f, std::complex{re1, im1}, re2); + for (auto re1 : std::vector{-1.8, 3.4}) { + for (auto im1 : std::vector{-1.8, 3.4}) { + for (auto re2 : std::vector{-2.7, 1, 2.3}) { + stan::test::expect_ad(tols, f, std::complex{re1, im1}, re2); } } } diff --git a/test/unit/math/mix/fun/scalbn_test.cpp b/test/unit/math/mix/fun/scalbn_test.cpp index 364fa551cd0..d68618fc38e 100644 --- a/test/unit/math/mix/fun/scalbn_test.cpp +++ b/test/unit/math/mix/fun/scalbn_test.cpp @@ -1,6 +1,7 @@ #include #include #include +#include template void expect_scalbn(double x) { @@ -12,8 +13,8 @@ void expect_scalbn(double x) { } void expect_all_scalbn(double x) { - using stan::math::var; using stan::math::fvar; + using stan::math::var; expect_scalbn(x); expect_scalbn(x); expect_scalbn>(x); @@ -25,7 +26,7 @@ void expect_all_scalbn(double x) { TEST(mathMixMatFun, scalbn) { double inf = std::numeric_limits::infinity(); double nan = std::numeric_limits::quiet_NaN(); - for (double x : std::vector{ 2.3 }) { // {-inf, -2.3, 0, 1, 2, 3.9, inf, nan}) { + for (double x : std::vector{2.3}) { expect_all_scalbn(x); } } diff --git a/test/unit/math/mix/fun/sqrt_test.cpp b/test/unit/math/mix/fun/sqrt_test.cpp index 8949819613b..16d2c5c0be5 100644 --- a/test/unit/math/mix/fun/sqrt_test.cpp +++ b/test/unit/math/mix/fun/sqrt_test.cpp @@ -1,4 +1,5 @@ #include +#include TEST(mathMixMatFun, sqrt) { auto f = [](const auto& x1) { From 971337cc1986097b11b8be3c21ffed7ae2707d45 Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Wed, 11 Mar 2020 01:31:51 -0400 Subject: [PATCH 34/63] header include fixes, part 1 of many --- stan/math/fwd/core/operator_division.hpp | 3 +- stan/math/fwd/fun/exp.hpp | 1 + stan/math/fwd/fun/log.hpp | 2 + stan/math/fwd/fun/pow.hpp | 1 + stan/math/prim/core/operator_addition.hpp | 1 + stan/math/prim/core/operator_division.hpp | 1 + .../prim/core/operator_multiplication.hpp | 1 + stan/math/prim/core/operator_subtraction.hpp | 1 + stan/math/prim/fun/acos.hpp | 14 +++- stan/math/prim/fun/cosh.hpp | 1 + stan/math/prim/fun/polar.hpp | 1 + stan/math/rev/core/operator_division.hpp | 83 +++++++++++-------- stan/math/rev/fun/abs.hpp | 1 + stan/math/rev/fun/arg.hpp | 1 + stan/math/rev/fun/atan.hpp | 1 + stan/math/rev/fun/cos.hpp | 5 +- stan/math/rev/fun/cosh.hpp | 3 +- stan/math/rev/fun/exp.hpp | 7 ++ stan/math/rev/fun/polar.hpp | 6 ++ stan/math/rev/fun/sinh.hpp | 4 + 20 files changed, 96 insertions(+), 42 deletions(-) diff --git a/stan/math/fwd/core/operator_division.hpp b/stan/math/fwd/core/operator_division.hpp index b99e140cbf0..93514e0a642 100644 --- a/stan/math/fwd/core/operator_division.hpp +++ b/stan/math/fwd/core/operator_division.hpp @@ -1,7 +1,8 @@ #ifndef STAN_MATH_FWD_CORE_OPERATOR_DIVISION_HPP #define STAN_MATH_FWD_CORE_OPERATOR_DIVISION_HPP -#include +#include +#include #include #include diff --git a/stan/math/fwd/fun/exp.hpp b/stan/math/fwd/fun/exp.hpp index 440667b7e0e..d0690fd803d 100644 --- a/stan/math/fwd/fun/exp.hpp +++ b/stan/math/fwd/fun/exp.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include diff --git a/stan/math/fwd/fun/log.hpp b/stan/math/fwd/fun/log.hpp index b1c8f6e7003..d7ce96f0bfa 100644 --- a/stan/math/fwd/fun/log.hpp +++ b/stan/math/fwd/fun/log.hpp @@ -4,7 +4,9 @@ #include #include #include +#include #include +#include namespace stan { namespace math { diff --git a/stan/math/fwd/fun/pow.hpp b/stan/math/fwd/fun/pow.hpp index 840ca06dcf1..ccc858f5679 100644 --- a/stan/math/fwd/fun/pow.hpp +++ b/stan/math/fwd/fun/pow.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include diff --git a/stan/math/prim/core/operator_addition.hpp b/stan/math/prim/core/operator_addition.hpp index 34799f8b936..030e3e7e69b 100644 --- a/stan/math/prim/core/operator_addition.hpp +++ b/stan/math/prim/core/operator_addition.hpp @@ -1,6 +1,7 @@ #ifndef STAN_MATH_PRIM_CORE_OPERATOR_ADDITION_HPP #define STAN_MATH_PRIM_CORE_OPERATOR_ADDITION_HPP +#include #include namespace stan { diff --git a/stan/math/prim/core/operator_division.hpp b/stan/math/prim/core/operator_division.hpp index 07aa89ca577..090970b616c 100644 --- a/stan/math/prim/core/operator_division.hpp +++ b/stan/math/prim/core/operator_division.hpp @@ -1,6 +1,7 @@ #ifndef STAN_MATH_PRIM_CORE_OPERATOR_DIVISION_HPP #define STAN_MATH_PRIM_CORE_OPERATOR_DIVISION_HPP +#include #include namespace stan { diff --git a/stan/math/prim/core/operator_multiplication.hpp b/stan/math/prim/core/operator_multiplication.hpp index 523fa7e2f62..bb70715033b 100644 --- a/stan/math/prim/core/operator_multiplication.hpp +++ b/stan/math/prim/core/operator_multiplication.hpp @@ -1,6 +1,7 @@ #ifndef STAN_MATH_PRIM_CORE_OPERATOR_MULTIPLICATION_HPP #define STAN_MATH_PRIM_CORE_OPERATOR_MULTIPLICATION_HPP +#include #include namespace stan { diff --git a/stan/math/prim/core/operator_subtraction.hpp b/stan/math/prim/core/operator_subtraction.hpp index 4c4cc938308..cc1c35bc2b3 100644 --- a/stan/math/prim/core/operator_subtraction.hpp +++ b/stan/math/prim/core/operator_subtraction.hpp @@ -1,6 +1,7 @@ #ifndef STAN_MATH_PRIM_CORE_OPERATOR_SUBTRACTION_HPP #define STAN_MATH_PRIM_CORE_OPERATOR_SUBTRACTION_HPP +#include #include namespace stan { diff --git a/stan/math/prim/fun/acos.hpp b/stan/math/prim/fun/acos.hpp index 8973b566bd5..26d57e7ed6f 100644 --- a/stan/math/prim/fun/acos.hpp +++ b/stan/math/prim/fun/acos.hpp @@ -6,6 +6,16 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include @@ -63,9 +73,7 @@ template inline std::complex complex_acos(const std::complex& z) { return V(0.5 * pi()) - asin(z); } -} - - +} // namespace internal } // namespace math } // namespace stan diff --git a/stan/math/prim/fun/cosh.hpp b/stan/math/prim/fun/cosh.hpp index 97fc203bba9..a18bab4e012 100644 --- a/stan/math/prim/fun/cosh.hpp +++ b/stan/math/prim/fun/cosh.hpp @@ -1,6 +1,7 @@ #ifndef STAN_MATH_PRIM_FUN_COSH_HPP #define STAN_MATH_PRIM_FUN_COSH_HPP +#include #include #include #include diff --git a/stan/math/prim/fun/polar.hpp b/stan/math/prim/fun/polar.hpp index 76923bb5a7f..591677e54a3 100644 --- a/stan/math/prim/fun/polar.hpp +++ b/stan/math/prim/fun/polar.hpp @@ -1,6 +1,7 @@ #ifndef STAN_MATH_PRIM_FUN_POLAR_HPP #define STAN_MATH_PRIM_FUN_POLAR_HPP +#include #include #include #include diff --git a/stan/math/rev/core/operator_division.hpp b/stan/math/rev/core/operator_division.hpp index 5178d9080bb..49f1120d2fb 100644 --- a/stan/math/rev/core/operator_division.hpp +++ b/stan/math/rev/core/operator_division.hpp @@ -5,8 +5,15 @@ #include #include #include -#include +#include #include +#include +#include +#include +#include +#include +#include +#include #include #include @@ -138,41 +145,45 @@ inline std::complex operator/(const std::complex& x1, return internal::complex_divide(x1, x2); } -template ...> -inline std::complex operator/(const std::complex& x1, - const std::complex& x2) { - return internal::complex_divide(x1, x2); -} -inline std::complex operator/(const std::complex& x1, const var& x2) { - return internal::complex_divide(x1, x2); -} -template ...> -inline std::complex operator/(const std::complex& x1, T x2) { - return internal::complex_divide(x1, x2); -} - -template ...> -inline std::complex operator/(const std::complex& x1, - const std::complex& x2) { - return internal::complex_divide(x1, x2); -} -template ...> -inline std::complex operator/(const std::complex& x1, const var& x2) { - return internal::complex_divide(x1, x2); -} - -inline std::complex operator/(const var& x1, const std::complex& x2) { - return internal::complex_divide(x1, x2); -} -template ...> -inline std::complex operator/(const var& x1, const std::complex& x2) { - return internal::complex_divide(x1, x2); -} - -template ...> -inline std::complex operator/(T x1, const std::complex& x2) { - return internal::complex_divide(x1, x2); -} +// template ...> +// inline std::complex operator/(const std::complex& x1, +// const std::complex& x2) { +// return internal::complex_divide(x1, x2); +// } +// inline std::complex operator/(const std::complex& x1, const var& +// x2) { +// return internal::complex_divide(x1, x2); +// } +// template ...> +// inline std::complex operator/(const std::complex& x1, T x2) { +// return internal::complex_divide(x1, x2); +// } + +// template ...> +// inline std::complex operator/(const std::complex& x1, +// const std::complex& x2) { +// return internal::complex_divide(x1, x2); +// } +// template ...> +// inline std::complex operator/(const std::complex& x1, const var& x2) +// { +// return internal::complex_divide(x1, x2); +// } + +// inline std::complex operator/(const var& x1, const std::complex& +// x2) { +// return internal::complex_divide(x1, x2); +// } +// template ...> +// inline std::complex operator/(const var& x1, const std::complex& x2) +// { +// return internal::complex_divide(x1, x2); +// } + +// template ...> +// inline std::complex operator/(T x1, const std::complex& x2) { +// return internal::complex_divide(x1, x2); +// } } // namespace math } // namespace stan diff --git a/stan/math/rev/fun/abs.hpp b/stan/math/rev/fun/abs.hpp index 74cb0ddf81d..d77abd3e09e 100644 --- a/stan/math/rev/fun/abs.hpp +++ b/stan/math/rev/fun/abs.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include namespace stan { diff --git a/stan/math/rev/fun/arg.hpp b/stan/math/rev/fun/arg.hpp index e286ed34174..293dfd6b059 100644 --- a/stan/math/rev/fun/arg.hpp +++ b/stan/math/rev/fun/arg.hpp @@ -2,6 +2,7 @@ #define STAN_MATH_REV_FUN_ARG_HPP #include +#include #include #include diff --git a/stan/math/rev/fun/atan.hpp b/stan/math/rev/fun/atan.hpp index a4357c9f42d..076ae23a395 100644 --- a/stan/math/rev/fun/atan.hpp +++ b/stan/math/rev/fun/atan.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include diff --git a/stan/math/rev/fun/cos.hpp b/stan/math/rev/fun/cos.hpp index 0e7f22e8c74..06051bcf5aa 100644 --- a/stan/math/rev/fun/cos.hpp +++ b/stan/math/rev/fun/cos.hpp @@ -1,9 +1,13 @@ #ifndef STAN_MATH_REV_FUN_COS_HPP #define STAN_MATH_REV_FUN_COS_HPP +#include #include +#include +#include #include #include +#include #include #include @@ -57,7 +61,6 @@ inline std::complex cos(const std::complex& z) { return stan::math::internal::complex_cos(z); } - } // namespace math } // namespace stan #endif diff --git a/stan/math/rev/fun/cosh.hpp b/stan/math/rev/fun/cosh.hpp index 592759dbb38..87fb6607e23 100644 --- a/stan/math/rev/fun/cosh.hpp +++ b/stan/math/rev/fun/cosh.hpp @@ -4,7 +4,9 @@ #include #include #include +#include #include +#include #include #include @@ -58,7 +60,6 @@ inline std::complex cosh(const std::complex& z) { return stan::math::internal::complex_cosh(z); } - } // namespace math } // namespace stan #endif diff --git a/stan/math/rev/fun/exp.hpp b/stan/math/rev/fun/exp.hpp index 7cc70f42036..4a14a4811b1 100644 --- a/stan/math/rev/fun/exp.hpp +++ b/stan/math/rev/fun/exp.hpp @@ -3,6 +3,13 @@ #include #include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/stan/math/rev/fun/polar.hpp b/stan/math/rev/fun/polar.hpp index ab5339d2f6f..d2c73bf835b 100644 --- a/stan/math/rev/fun/polar.hpp +++ b/stan/math/rev/fun/polar.hpp @@ -3,7 +3,13 @@ #include #include +#include +#include +#include +#include #include +#include +#include #include #include diff --git a/stan/math/rev/fun/sinh.hpp b/stan/math/rev/fun/sinh.hpp index 4571e47a07f..fecc1f431fc 100644 --- a/stan/math/rev/fun/sinh.hpp +++ b/stan/math/rev/fun/sinh.hpp @@ -1,9 +1,13 @@ #ifndef STAN_MATH_REV_FUN_SINH_HPP #define STAN_MATH_REV_FUN_SINH_HPP +#include +#include +#include #include #include #include +#include #include #include From d25c1f95b0e861d7def6b44689efd9958ad5bf4b Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Wed, 11 Mar 2020 02:07:20 -0400 Subject: [PATCH 35/63] complex trig includes for headers --- stan/math/prim/fun/asinh.hpp | 6 ++++++ stan/math/rev/fun/acosh.hpp | 11 ++++++++++- stan/math/rev/fun/asin.hpp | 3 +++ stan/math/rev/fun/asinh.hpp | 9 +++++++++ stan/math/rev/fun/atan.hpp | 10 ++++++++++ stan/math/rev/fun/atanh.hpp | 3 +++ stan/math/rev/fun/cos.hpp | 1 + stan/math/rev/fun/sin.hpp | 4 ++++ stan/math/rev/fun/tan.hpp | 4 ++++ 9 files changed, 50 insertions(+), 1 deletion(-) diff --git a/stan/math/prim/fun/asinh.hpp b/stan/math/prim/fun/asinh.hpp index 0f64cba1eee..51871ce6067 100644 --- a/stan/math/prim/fun/asinh.hpp +++ b/stan/math/prim/fun/asinh.hpp @@ -3,8 +3,14 @@ #include #include +#include +#include #include +#include +#include +#include #include +#include #include #include #include diff --git a/stan/math/rev/fun/acosh.hpp b/stan/math/rev/fun/acosh.hpp index 9eca93df17b..59bd2c61cfa 100644 --- a/stan/math/rev/fun/acosh.hpp +++ b/stan/math/rev/fun/acosh.hpp @@ -1,9 +1,19 @@ #ifndef STAN_MATH_REV_FUN_ACOSH_HPP #define STAN_MATH_REV_FUN_ACOSH_HPP +#include +#include #include +#include #include #include +#include +#include +#include +#include +#include +#include +#include #include #include @@ -73,7 +83,6 @@ inline std::complex acosh(const std::complex& z) { return stan::math::internal::complex_acosh(z); } - } // namespace math } // namespace stan #endif diff --git a/stan/math/rev/fun/asin.hpp b/stan/math/rev/fun/asin.hpp index cf2485e2e08..9bf5fb74fc7 100644 --- a/stan/math/rev/fun/asin.hpp +++ b/stan/math/rev/fun/asin.hpp @@ -2,8 +2,11 @@ #define STAN_MATH_REV_FUN_ASIN_HPP #include +#include #include #include +#include +#include #include #include diff --git a/stan/math/rev/fun/asinh.hpp b/stan/math/rev/fun/asinh.hpp index 24d6ab7464d..97b27f009cb 100644 --- a/stan/math/rev/fun/asinh.hpp +++ b/stan/math/rev/fun/asinh.hpp @@ -1,9 +1,18 @@ #ifndef STAN_MATH_REV_FUN_ASINH_HPP #define STAN_MATH_REV_FUN_ASINH_HPP +#include +#include #include #include #include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/stan/math/rev/fun/atan.hpp b/stan/math/rev/fun/atan.hpp index 076ae23a395..9d4ead191fc 100644 --- a/stan/math/rev/fun/atan.hpp +++ b/stan/math/rev/fun/atan.hpp @@ -1,10 +1,20 @@ #ifndef STAN_MATH_REV_FUN_ATAN_HPP #define STAN_MATH_REV_FUN_ATAN_HPP +#include +#include +#include #include #include #include #include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/stan/math/rev/fun/atanh.hpp b/stan/math/rev/fun/atanh.hpp index e5f6ecfcb5d..e15b033d965 100644 --- a/stan/math/rev/fun/atanh.hpp +++ b/stan/math/rev/fun/atanh.hpp @@ -4,6 +4,9 @@ #include #include #include +#include +#include +#include #include #include diff --git a/stan/math/rev/fun/cos.hpp b/stan/math/rev/fun/cos.hpp index 06051bcf5aa..8fcd98e2400 100644 --- a/stan/math/rev/fun/cos.hpp +++ b/stan/math/rev/fun/cos.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include diff --git a/stan/math/rev/fun/sin.hpp b/stan/math/rev/fun/sin.hpp index 5781b1cc643..2011d0d3fb7 100644 --- a/stan/math/rev/fun/sin.hpp +++ b/stan/math/rev/fun/sin.hpp @@ -1,9 +1,13 @@ #ifndef STAN_MATH_REV_FUN_SIN_HPP #define STAN_MATH_REV_FUN_SIN_HPP +#include +#include +#include #include #include #include +#include #include #include diff --git a/stan/math/rev/fun/tan.hpp b/stan/math/rev/fun/tan.hpp index fb94841e714..e7f231b28ae 100644 --- a/stan/math/rev/fun/tan.hpp +++ b/stan/math/rev/fun/tan.hpp @@ -1,9 +1,13 @@ #ifndef STAN_MATH_REV_FUN_TAN_HPP #define STAN_MATH_REV_FUN_TAN_HPP +#include #include #include #include +#include +#include +#include #include #include From ef72d1c3aeca4ca9ed00b5560f198b6d320286ed Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Wed, 11 Mar 2020 02:26:02 -0400 Subject: [PATCH 36/63] complex updates passing header tests --- stan/math/rev/fun/log.hpp | 10 +++++++++- stan/math/rev/fun/log10.hpp | 8 +++++--- stan/math/rev/fun/norm.hpp | 2 +- stan/math/rev/fun/pow.hpp | 13 ++++++++++--- stan/math/rev/fun/proj.hpp | 4 +++- stan/math/rev/fun/sqrt.hpp | 3 +++ 6 files changed, 31 insertions(+), 9 deletions(-) diff --git a/stan/math/rev/fun/log.hpp b/stan/math/rev/fun/log.hpp index 0a69f864519..52b891da2ec 100644 --- a/stan/math/rev/fun/log.hpp +++ b/stan/math/rev/fun/log.hpp @@ -1,9 +1,18 @@ #ifndef STAN_MATH_REV_FUN_LOG_HPP #define STAN_MATH_REV_FUN_LOG_HPP +#include +#include #include #include #include +#include +#include +#include +#include +#include +#include +#include #include namespace stan { @@ -57,7 +66,6 @@ inline std::complex log(const std::complex& z) { return internal::complex_log(z); } - } // namespace math } // namespace stan #endif diff --git a/stan/math/rev/fun/log10.hpp b/stan/math/rev/fun/log10.hpp index 1cf15d9bae8..b0bc93962a3 100644 --- a/stan/math/rev/fun/log10.hpp +++ b/stan/math/rev/fun/log10.hpp @@ -1,10 +1,13 @@ #ifndef STAN_MATH_REV_FUN_LOG10_HPP #define STAN_MATH_REV_FUN_LOG10_HPP -#include -#include +#include #include #include +#include +#include +#include +#include #include #include @@ -62,7 +65,6 @@ inline std::complex log10(const std::complex& z) { return internal::complex_log10(z); } - } // namespace math } // namespace stan #endif diff --git a/stan/math/rev/fun/norm.hpp b/stan/math/rev/fun/norm.hpp index 6ded7229bb3..41a6b6af10c 100644 --- a/stan/math/rev/fun/norm.hpp +++ b/stan/math/rev/fun/norm.hpp @@ -1,8 +1,8 @@ #ifndef STAN_MATH_REV_FUN_NORM_HPP #define STAN_MATH_REV_FUN_NORM_HPP +#include #include -#include #include namespace stan { diff --git a/stan/math/rev/fun/pow.hpp b/stan/math/rev/fun/pow.hpp index 19bbe7aa4ea..f7b43c6fdde 100644 --- a/stan/math/rev/fun/pow.hpp +++ b/stan/math/rev/fun/pow.hpp @@ -1,16 +1,23 @@ #ifndef STAN_MATH_REV_FUN_POW_HPP #define STAN_MATH_REV_FUN_POW_HPP +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include #include #include +#include +#include #include #include -#include -#include -#include #include #include #include diff --git a/stan/math/rev/fun/proj.hpp b/stan/math/rev/fun/proj.hpp index e5797703e16..ceb83db8bfa 100644 --- a/stan/math/rev/fun/proj.hpp +++ b/stan/math/rev/fun/proj.hpp @@ -1,8 +1,10 @@ #ifndef STAN_MATH_REV_FUN_PROJ_HPP #define STAN_MATH_REV_FUN_PROJ_HPP -#include #include +#include +#include +#include #include namespace stan { diff --git a/stan/math/rev/fun/sqrt.hpp b/stan/math/rev/fun/sqrt.hpp index 4d343f38a8c..5dafb4dac4d 100644 --- a/stan/math/rev/fun/sqrt.hpp +++ b/stan/math/rev/fun/sqrt.hpp @@ -4,6 +4,9 @@ #include #include #include +#include +#include +#include #include #include From 19dbc28a89414daf612e0855f92e6a5be737ed02 Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Wed, 11 Mar 2020 16:50:43 -0400 Subject: [PATCH 37/63] overloads for g++; remove complex in complex in test --- stan/math/fwd/fun/tan.hpp | 12 +++++++ stan/math/prim/core/operator_equal_equal.hpp | 18 +++++++++-- stan/math/rev/core/operator_equal.hpp | 26 +++++++++++++++ stan/math/rev/core/operator_not_equal.hpp | 26 +++++++++++++++ test/unit/math/test_ad.hpp | 33 +++++++++++--------- 5 files changed, 97 insertions(+), 18 deletions(-) diff --git a/stan/math/fwd/fun/tan.hpp b/stan/math/fwd/fun/tan.hpp index 66ca0c2c071..503ca10e2ef 100644 --- a/stan/math/fwd/fun/tan.hpp +++ b/stan/math/fwd/fun/tan.hpp @@ -16,6 +16,18 @@ inline fvar tan(const fvar& x) { using std::tan; return fvar(tan(x.val_), x.d_ / (cos(x.val_) * cos(x.val_))); } + +/** + * Return the tangent of the complex argument. + * + * @param[in] z argument + * @return tangent of the argument + */ +template +inline std::complex> tan(const std::complex>& z) { + return stan::math::internal::complex_tan(z); +} + } // namespace math } // namespace stan #endif diff --git a/stan/math/prim/core/operator_equal_equal.hpp b/stan/math/prim/core/operator_equal_equal.hpp index 17334283674..cf5228a11cf 100644 --- a/stan/math/prim/core/operator_equal_equal.hpp +++ b/stan/math/prim/core/operator_equal_equal.hpp @@ -3,6 +3,7 @@ #include #include +#include // TODO(carpenter): get rid of this include namespace stan { namespace math { @@ -17,7 +18,7 @@ namespace math { * @param y second argument * @return `true` if the arguments are equal */ -template > +template inline bool operator==(const std::complex& x, const std::complex& y) { return x.real() == y.real() && x.imag() == y.imag(); } @@ -32,7 +33,7 @@ inline bool operator==(const std::complex& x, const std::complex& y) { * @param y second argument * @return `true` if the arguments are equal */ -template > +template inline bool operator==(const std::complex& x, const V& y) { return x.real() == y && x.imag() == 0; } @@ -48,11 +49,22 @@ inline bool operator==(const std::complex& x, const V& y) { * @param y second argument * @return `true` if the arguments are equal */ -template > +template inline bool operator==(const U& x, const std::complex& y) { return x == y.real() && 0 == y.imag(); } +// ambiguous with lib wo specific autodiff type +template > +inline bool operator==(const U& x, const std::complex& y) { + return x == y.real() && 0 == y.imag(); +} + +template > +inline bool operator==(const std::complex& x, const U& y) { + return x.real() == y && x.imag() == 0; +} + } // namespace math } // namespace stan diff --git a/stan/math/rev/core/operator_equal.hpp b/stan/math/rev/core/operator_equal.hpp index a6f33b12d41..1f123ac1da4 100644 --- a/stan/math/rev/core/operator_equal.hpp +++ b/stan/math/rev/core/operator_equal.hpp @@ -55,6 +55,32 @@ inline bool operator==(Arith a, var b) { return a == b.val(); } +/** + * Return `true` if the real number is equal to the real part of the + * complex number, and the imaginary part of the complex number is zero + * + * @param x real number + * @param z complex number + * @return `true` if the real number is equal to the real part of the + * complex number, and the imaginary part of the complex number is zero + */ +inline bool operator==(const var& x, const std::complex& z) { + return x == z.real() && 0 == z.imag(); +} + +/** + * Return `true` if the real number is equal to the real part of the + * complex number, and the imaginary part of the complex number is zero + * + * @param z complex number + * @param y real number + * @return `true` if the real number is equal to the real part of the + * complex number, and the imaginary part of the complex number is zero + */ +inline bool operator==(const std::complex& z, const var& y) { + return z.real() == y && z.imag() == 0; +} + } // namespace math } // namespace stan #endif diff --git a/stan/math/rev/core/operator_not_equal.hpp b/stan/math/rev/core/operator_not_equal.hpp index c5e6d71a7a7..1010b6efddb 100644 --- a/stan/math/rev/core/operator_not_equal.hpp +++ b/stan/math/rev/core/operator_not_equal.hpp @@ -56,6 +56,32 @@ inline bool operator!=(Arith a, var b) { return a != b.val(); } +/** + * Return `false` if the real number is equal to the real part of the + * complex number, and the imaginary part of the complex number is zero + * + * @param x real number + * @param z complex number + * @return `false` if the real number is equal to the real part of the + * complex number, and the imaginary part of the complex number is zero + */ +inline bool operator!=(const var& x, const std::complex& z) { + return !(x == z.real() && 0 == z.imag()); +} + +/** + * Return `false` if the real number is equal to the real part of the + * complex number, and the imaginary part of the complex number is zero + * + * @param z complex number + * @param y real number + * @return `false` if the real number is equal to the real part of the + * complex number, and the imaginary part of the complex number is zero + */ +inline bool operator!=(const std::complex& z, const var& y) { + return !(z.real() == y && z.imag() == 0); +} + } // namespace math } // namespace stan #endif diff --git a/test/unit/math/test_ad.hpp b/test/unit/math/test_ad.hpp index 6a9db15e8df..5652f44f302 100644 --- a/test/unit/math/test_ad.hpp +++ b/test/unit/math/test_ad.hpp @@ -1769,17 +1769,20 @@ template void expect_complex_compare(const F& f, const std::complex& z1, const std::complex& z2) { using c_t = std::complex; - EXPECT_EQ(f(z1, z2), f(c_t(z1), z2)); - EXPECT_EQ(f(z1, z2), f(z1, c_t(z2))); - EXPECT_EQ(f(z1, z2), f(c_t(z1), c_t(z2))); + c_t cz1{z1}; + c_t cz2{z2}; + T z1r{z1.real()}; + T z2r{z2.real()}; - EXPECT_EQ(f(z1.real(), z2), f(T(z1.real()), z2)); - EXPECT_EQ(f(z1.real(), z2), f(z1.real(), c_t(z2))); - EXPECT_EQ(f(z1.real(), z2), f(T(z1.real()), c_t(z2))); + // EXPECT_EQ(f(z1, z2), f(cz1, cz2)); // PASS + // EXPECT_EQ(f(z1, z2), f(cz1, z2)); // PASS + // EXPECT_EQ(f(z1, z2), f(z1, cz2)); // PASS - EXPECT_EQ(f(z1, z2.real()), f(c_t(z1), z2.real())); - EXPECT_EQ(f(z1, z2.real()), f(z1, T(z2.real()))); - EXPECT_EQ(f(z1, z2.real()), f(c_t(z1), T(z2.real()))); + EXPECT_EQ(f(z1.real(), z2), f(z1r, cz2)); // FAIL + // EXPECT_EQ(f(z1.real(), z2), f(z1r, z2)); // PASS + + // // EXPECT_EQ(f(z1, z2.real()), f(cz1, z2r)); // FAIL + // EXPECT_EQ(f(z1, z2.real()), f(z1, z2r)); // PASS } template @@ -1788,12 +1791,12 @@ void expect_complex_comparison(const F& f, const std::complex& z1, using stan::math::fvar; using stan::math::var; using std::complex; - expect_complex_compare(f, z1, z2); - expect_complex_compare(f, z1, z2); - expect_complex_compare>>(f, z1, z2); - expect_complex_compare>>>(f, z1, z2); - expect_complex_compare>>(f, z1, z2); - expect_complex_compare>>>(f, z1, z2); + // expect_complex_compare(f, z1, z2); // PASS + expect_complex_compare(f, z1, z2); // FAIL + // expect_complex_compare>(f, z1, z2); // PASS + // expect_complex_compare>>(f, z1, z2); // PASS + // expect_complex_compare>(f, z1, z2); // PASS + // expect_complex_compare>>(f, z1, z2); // PASS } template From 6563272c45929be2e49b8cafc0d4988f712d15b9 Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Wed, 11 Mar 2020 16:59:44 -0400 Subject: [PATCH 38/63] doxygen arg cleanup --- stan/math/prim/fun/pow.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stan/math/prim/fun/pow.hpp b/stan/math/prim/fun/pow.hpp index ffbcce780d2..560bc332de4 100644 --- a/stan/math/prim/fun/pow.hpp +++ b/stan/math/prim/fun/pow.hpp @@ -16,8 +16,8 @@ namespace internal { * * @tparam U type of first argument * @tparam V type of second argument - * @param[in] lhs first argument - * @param[in] rhs second argument + * @param[in] x first argument + * @param[in] y second argument * @return first argument raised to the power of the second argument */ template From eb16b342bec94f93d78a03762ba5402e49108f83 Mon Sep 17 00:00:00 2001 From: Stan Jenkins Date: Wed, 11 Mar 2020 17:01:30 -0400 Subject: [PATCH 39/63] [Jenkins] auto-formatting by clang-format version 6.0.0 (tags/google/stable/2017-11-14) --- stan/math/fwd/fun/acosh.hpp | 1 - stan/math/fwd/fun/sinh.hpp | 1 - stan/math/prim/fun/acosh.hpp | 1 - stan/math/prim/fun/atan.hpp | 2 +- stan/math/prim/fun/cos.hpp | 2 +- stan/math/prim/fun/exp.hpp | 1 - stan/math/prim/fun/sin.hpp | 1 - 7 files changed, 2 insertions(+), 7 deletions(-) diff --git a/stan/math/fwd/fun/acosh.hpp b/stan/math/fwd/fun/acosh.hpp index b5c797bd41b..376daa568aa 100644 --- a/stan/math/fwd/fun/acosh.hpp +++ b/stan/math/fwd/fun/acosh.hpp @@ -9,7 +9,6 @@ #include #include - namespace stan { namespace math { diff --git a/stan/math/fwd/fun/sinh.hpp b/stan/math/fwd/fun/sinh.hpp index 252afd686a5..0a7e6d4343a 100644 --- a/stan/math/fwd/fun/sinh.hpp +++ b/stan/math/fwd/fun/sinh.hpp @@ -6,7 +6,6 @@ #include #include - namespace stan { namespace math { diff --git a/stan/math/prim/fun/acosh.hpp b/stan/math/prim/fun/acosh.hpp index ee1d81f4399..015bc014112 100644 --- a/stan/math/prim/fun/acosh.hpp +++ b/stan/math/prim/fun/acosh.hpp @@ -105,7 +105,6 @@ inline std::complex complex_acosh(const std::complex& z) { } // namespace internal - } // namespace math } // namespace stan diff --git a/stan/math/prim/fun/atan.hpp b/stan/math/prim/fun/atan.hpp index 890c6a6a479..e9acedd219b 100644 --- a/stan/math/prim/fun/atan.hpp +++ b/stan/math/prim/fun/atan.hpp @@ -64,7 +64,7 @@ template inline std::complex complex_atan(const std::complex& z) { return neg_i_times(atanh(i_times(z))); } -} +} // namespace internal } // namespace math } // namespace stan diff --git a/stan/math/prim/fun/cos.hpp b/stan/math/prim/fun/cos.hpp index d0729ce85f7..57970266d4f 100644 --- a/stan/math/prim/fun/cos.hpp +++ b/stan/math/prim/fun/cos.hpp @@ -63,7 +63,7 @@ template inline std::complex complex_cos(const std::complex& z) { return cosh(i_times(z)); } -} +} // namespace internal } // namespace math } // namespace stan diff --git a/stan/math/prim/fun/exp.hpp b/stan/math/prim/fun/exp.hpp index cc7c1c3b1c9..55d1222f6ab 100644 --- a/stan/math/prim/fun/exp.hpp +++ b/stan/math/prim/fun/exp.hpp @@ -19,7 +19,6 @@ namespace math { */ inline double exp(int x) { return std::exp(x); } - /** * Structure to wrap exp() so that it can be * vectorized. diff --git a/stan/math/prim/fun/sin.hpp b/stan/math/prim/fun/sin.hpp index b19ef5fd315..da61321cc17 100644 --- a/stan/math/prim/fun/sin.hpp +++ b/stan/math/prim/fun/sin.hpp @@ -65,7 +65,6 @@ inline std::complex complex_sin(const std::complex& z) { } } // namespace internal - } // namespace math } // namespace stan From ea25a8e2cf1f6d6f2387849dc66aea53166bfd15 Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Wed, 11 Mar 2020 18:41:48 -0400 Subject: [PATCH 40/63] moved rev includes to rev for complex acos --- stan/math/prim/fun/acos.hpp | 6 ------ stan/math/rev/fun/acos.hpp | 6 ++++++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/stan/math/prim/fun/acos.hpp b/stan/math/prim/fun/acos.hpp index 26d57e7ed6f..113148dce35 100644 --- a/stan/math/prim/fun/acos.hpp +++ b/stan/math/prim/fun/acos.hpp @@ -10,12 +10,6 @@ #include #include #include -#include -#include -#include -#include -#include -#include #include #include diff --git a/stan/math/rev/fun/acos.hpp b/stan/math/rev/fun/acos.hpp index 602cf5eb457..909d1a73ab6 100644 --- a/stan/math/rev/fun/acos.hpp +++ b/stan/math/rev/fun/acos.hpp @@ -4,6 +4,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include #include From 05596a55b5511283d01e51d0c449efce4487c255 Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Wed, 11 Mar 2020 19:46:20 -0400 Subject: [PATCH 41/63] include operator_equal and complex var --- stan/math/rev/core/operator_not_equal.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/stan/math/rev/core/operator_not_equal.hpp b/stan/math/rev/core/operator_not_equal.hpp index 1010b6efddb..9a5148294fe 100644 --- a/stan/math/rev/core/operator_not_equal.hpp +++ b/stan/math/rev/core/operator_not_equal.hpp @@ -1,8 +1,11 @@ #ifndef STAN_MATH_REV_CORE_OPERATOR_NOT_EQUAL_HPP #define STAN_MATH_REV_CORE_OPERATOR_NOT_EQUAL_HPP +#include +#include #include #include +#include namespace stan { namespace math { From 16788e2e04be2b4f4e33364fcd043c05e39839eb Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Wed, 11 Mar 2020 22:50:44 -0400 Subject: [PATCH 42/63] includes for complex for g++ header tests --- stan/math/rev/fun/acosh.hpp | 1 + stan/math/rev/fun/asinh.hpp | 1 + stan/math/rev/fun/atanh.hpp | 3 +++ stan/math/rev/fun/cos.hpp | 1 + stan/math/rev/fun/cosh.hpp | 1 + stan/math/rev/fun/log10.hpp | 1 + stan/math/rev/fun/sin.hpp | 2 ++ 7 files changed, 10 insertions(+) diff --git a/stan/math/rev/fun/acosh.hpp b/stan/math/rev/fun/acosh.hpp index 59bd2c61cfa..dfc3b27bdab 100644 --- a/stan/math/rev/fun/acosh.hpp +++ b/stan/math/rev/fun/acosh.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/stan/math/rev/fun/asinh.hpp b/stan/math/rev/fun/asinh.hpp index 97b27f009cb..5ff296a19de 100644 --- a/stan/math/rev/fun/asinh.hpp +++ b/stan/math/rev/fun/asinh.hpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include diff --git a/stan/math/rev/fun/atanh.hpp b/stan/math/rev/fun/atanh.hpp index e15b033d965..b7a5b66c63f 100644 --- a/stan/math/rev/fun/atanh.hpp +++ b/stan/math/rev/fun/atanh.hpp @@ -6,6 +6,9 @@ #include #include #include +#include +#include +#include #include #include #include diff --git a/stan/math/rev/fun/cos.hpp b/stan/math/rev/fun/cos.hpp index 8fcd98e2400..da4c8067e32 100644 --- a/stan/math/rev/fun/cos.hpp +++ b/stan/math/rev/fun/cos.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include diff --git a/stan/math/rev/fun/cosh.hpp b/stan/math/rev/fun/cosh.hpp index 87fb6607e23..0b3605e8c9b 100644 --- a/stan/math/rev/fun/cosh.hpp +++ b/stan/math/rev/fun/cosh.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include diff --git a/stan/math/rev/fun/log10.hpp b/stan/math/rev/fun/log10.hpp index b0bc93962a3..460e45f89b9 100644 --- a/stan/math/rev/fun/log10.hpp +++ b/stan/math/rev/fun/log10.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include diff --git a/stan/math/rev/fun/sin.hpp b/stan/math/rev/fun/sin.hpp index 2011d0d3fb7..61dfc54d9af 100644 --- a/stan/math/rev/fun/sin.hpp +++ b/stan/math/rev/fun/sin.hpp @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include From de9a53e68b1a29bac69b677b8af20a1133d195ac Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Thu, 12 Mar 2020 01:35:59 -0400 Subject: [PATCH 43/63] inline complex polar function --- stan/math/prim/fun/polar.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stan/math/prim/fun/polar.hpp b/stan/math/prim/fun/polar.hpp index 591677e54a3..9ba15ee3aae 100644 --- a/stan/math/prim/fun/polar.hpp +++ b/stan/math/prim/fun/polar.hpp @@ -36,16 +36,16 @@ inline complex_return_t complex_polar(const U& r, const V& theta) { * @param[in] theta phase angle * @return complex number with magnitude and phase angle */ -std::complex polar(double r, double theta) { +inline std::complex polar(double r, double theta) { return internal::complex_polar(r, theta); } -std::complex polar(double r, int theta) { +inline std::complex polar(double r, int theta) { return internal::complex_polar(r, static_cast(theta)); } -std::complex polar(int r, double theta) { +inline std::complex polar(int r, double theta) { return internal::complex_polar(static_cast(r), theta); } -std::complex polar(int r, int theta) { +inline std::complex polar(int r, int theta) { return internal::complex_polar(static_cast(r), static_cast(theta)); } From 9e11c95a241d155d57c913842f085ec3ca1270bd Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Thu, 12 Mar 2020 09:31:54 -0400 Subject: [PATCH 44/63] remove unused var(std::complex) ctor and tests --- test/unit/math/rev/core/var_test.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/test/unit/math/rev/core/var_test.cpp b/test/unit/math/rev/core/var_test.cpp index 72b455af121..54d66f75db0 100644 --- a/test/unit/math/rev/core/var_test.cpp +++ b/test/unit/math/rev/core/var_test.cpp @@ -69,16 +69,6 @@ TEST_F(AgradRev, ctorOverloads) { // ptrdiff_t EXPECT_FLOAT_EQ(37, var(static_cast(37)).val()); EXPECT_FLOAT_EQ(0, var(static_cast(0)).val()); - - // complex but with zero imaginary part - EXPECT_FLOAT_EQ(37, var(std::complex(37, 0)).val()); - EXPECT_FLOAT_EQ(37, var(std::complex(37, 0)).val()); - EXPECT_FLOAT_EQ(37, var(std::complex(37, 0)).val()); - - // complex but with non-zero imaginary part - EXPECT_THROW(var(std::complex(37, 10)), std::invalid_argument); - EXPECT_THROW(var(std::complex(37, 10)), std::invalid_argument); - EXPECT_THROW(var(std::complex(37, 10)), std::invalid_argument); } TEST_F(AgradRev, a_eq_x) { From 7b0a3e2934aa863ab4eacfe906f8feae2412832f Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Thu, 12 Mar 2020 10:51:08 -0400 Subject: [PATCH 45/63] add using signbit in test --- test/unit/math/mix/fun/copysign_test.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/unit/math/mix/fun/copysign_test.cpp b/test/unit/math/mix/fun/copysign_test.cpp index 811084746a5..57ddeca4ff2 100644 --- a/test/unit/math/mix/fun/copysign_test.cpp +++ b/test/unit/math/mix/fun/copysign_test.cpp @@ -1,21 +1,22 @@ #include #include +#include #include #include #include template void expect_eq_signbit(const U& u, const V& v) { + using stan::math::signbit; + using std::signbit; EXPECT_EQ(signbit(u), signbit(v)); } template void expect_copysign() { using stan::math::copysign; - using stan::math::signbit; using std::copysign; using std::numeric_limits; - using std::signbit; double inf = numeric_limits::infinity(); std::vector ys{inf, -inf, -1, 0, 1}; From 5f3267c7b3207cd99e705c5c38cdef7ccd30f03c Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Thu, 12 Mar 2020 11:53:52 -0400 Subject: [PATCH 46/63] include std::abs for abs test --- test/unit/math/mix/fun/abs_test.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/test/unit/math/mix/fun/abs_test.cpp b/test/unit/math/mix/fun/abs_test.cpp index 7316a5e0af6..11f5da342b2 100644 --- a/test/unit/math/mix/fun/abs_test.cpp +++ b/test/unit/math/mix/fun/abs_test.cpp @@ -1,9 +1,13 @@ #include +#include #include #include TEST(mixScalFun, abs) { - auto f = [](const auto& x) { return abs(x); }; + auto f = [](const auto& x) { + using std::abs; + return abs(x); + }; stan::test::expect_common_nonzero_unary(f); stan::test::expect_value(f, 0); stan::test::expect_value(f, 0.0); @@ -19,13 +23,8 @@ TEST(mixScalFun, abs) { stan::test::expect_ad(f, 4.0); // not differentiable at zero - for (double re : - std::vector{-4, -2.5, -1.5, -0.3, -0.0, 0.0, 1.3, 2.1, 3.9}) { - for (double im : - std::vector{-4, -2.5, -1.5, -0.3, -0.0, 0.0, 1.3, 2.1, 3.9}) { - if ((re == 0.0 || re == -0.0) && (im == 0.0 || im == -0.0)) { - continue; - } + for (double re : std::vector{-4, -2.5, -1.5, -0.3, 1.3, 2.1, 3.9}) { + for (double im : std::vector{-4, -2.5, -1.5, -0.3, 1.3, 2.1, 3.9}) { stan::test::expect_ad(f, std::complex(re, im)); } } From f7b41dace453dd808b6dc89880ff437cd304b992 Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Mon, 23 Mar 2020 12:52:58 -0400 Subject: [PATCH 47/63] extended expect_near_rel to complex --- test/unit/math/expect_near_rel.hpp | 73 ++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/test/unit/math/expect_near_rel.hpp b/test/unit/math/expect_near_rel.hpp index 9f7f7ae0696..f3f7e645331 100644 --- a/test/unit/math/expect_near_rel.hpp +++ b/test/unit/math/expect_near_rel.hpp @@ -122,6 +122,17 @@ void expect_near_rel(const std::string& msg, EigMat1&& x1, EigMat2&& x2, expect_near_rel(msg2, x1_eval(i), x2_eval(i), tol); } +/** + * Tewsts that the elements of the specified standard vectors are + * relatively near one another by calling `expect_near_rel` + * recursively. + * + * @tparam T1 value type for first vector + * @tparam T2 value type for second vector + * @param[in] x1 first vector + * @param[in] x2 second vector + * @param[in] tol relative tolerance + */ template void expect_near_rel(const std::string& msg, const std::vector& x1, const std::vector& x2, @@ -136,6 +147,68 @@ void expect_near_rel(const std::string& msg, const std::vector& x1, expect_near_rel(msg2, x1[i], x2[i], tol); } +/** + * Tests that the real and complex parts of the specified complex numbers + * by calling `expect_near_rel` recursively with the specified message + * and tolerance. + * + * @tparam T1 value type of first complex number + * @tparam T2 value type of second complex number + * @param msg[in] message to print under failure + * @param z1[in] first complex number + * @param z2[in] second complex number + * @param tol[in] tolerance for comparison + */ +template +void expect_near_rel(const std::string& msg, const std::complex& z1, + const std::complex& z2, + relative_tolerance tol = relative_tolerance()) { + expect_near_rel(msg, z1.real(), z2.real(), tol); + expect_near_rel(msg, z1.imag(), z2.imag(), tol); +} + +/** + * Tests that the specified real number is near the real part of the + * specified complex number and the complex number's imaginary part is + * near zero by calling `expect_near_rel` recursively with the + * specified message and tolerance. + * + * @tparam T1 value type of first number + * @tparam T2 value type of second complex number + * @param msg[in] message to print under failure + * @param x1[in] real number + * @param z2[in] complex number + * @param tol[in] tolerance for comparison + */ +template +void expect_near_rel(const std::string& msg, const T1& x1, + const std::complex& z2, + relative_tolerance tol = relative_tolerance()) { + expect_near_rel(msg, x1, z2.real(), tol); + expect_near_rel(msg, 0, z2.imag(), tol); +} + +/** + * Tests that the specified real number is near the real part of the + * specified complex number and the complex number's imaginary part is + * near zero by calling `expect_near_rel` recursively with the + * specified message and tolerance. + * + * @tparam T1 value type of first number + * @tparam T2 value type of second complex number + * @param msg[in] message to print under failure + * @param z1[in] complex number + * @param x2[in] real number + * @param tol[in] tolerance for comparison + */ +template +void expect_near_rel(const std::string& msg, const std::complex& z1, + const T2& x2, + relative_tolerance tol = relative_tolerance()) { + expect_near_rel(msg, z1.real(), x2, tol); + expect_near_rel(msg, z1.imag(), 0, tol); +} + } // namespace test } // namespace stan #endif From 508fbc2fb9f52f1bbaf1c5fa5f18ca39d46bd805 Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Mon, 23 Mar 2020 12:53:22 -0400 Subject: [PATCH 48/63] added doc for logb --- stan/math/prim/fun/logb.hpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/stan/math/prim/fun/logb.hpp b/stan/math/prim/fun/logb.hpp index ee765b8263f..f0df32a4076 100644 --- a/stan/math/prim/fun/logb.hpp +++ b/stan/math/prim/fun/logb.hpp @@ -7,6 +7,19 @@ namespace stan { namespace math { +/** + * Returns the value of the unbiased radix-independent exponent from + * the floating-point argument. + * + * Implementation note: This implementation works for all autodiff + * types because it is a step function, so can return a `double` which + * will produce the correct zero derivative if promoted to an autodiff + * variable. + * + * @tparam T floating-point type + * @param[in] x floating-point argument + * @return unbiased radix-independent exponent of the argument + */ template > double logb(const T& x) { return std::logb(value_of_rec(x)); From 5b24cda3ddfa83e764d5b800f533766410228f15 Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Mon, 23 Mar 2020 12:53:46 -0400 Subject: [PATCH 49/63] use signbit instead of comparison for copysign --- stan/math/prim/fun/copysign.hpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/stan/math/prim/fun/copysign.hpp b/stan/math/prim/fun/copysign.hpp index 3d19bf8d2a3..96976e4cc50 100644 --- a/stan/math/prim/fun/copysign.hpp +++ b/stan/math/prim/fun/copysign.hpp @@ -2,6 +2,7 @@ #define STAN_MATH_PRIM_SCAL_FUN_COPYSIGN_HPP #include +#include #include namespace stan { @@ -17,17 +18,17 @@ namespace math { * Overload of `std::copysign` from `cmath` for argument-dependent * lookup. * - * @tparam ADType type of first argument + * @tparam T 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 -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; +template +inline T copysign(const T& x, const U& y) { + // return (x < 0 && y >= 0) || (x >= 0 && y < 0) ? -x : x; + return (signbit(value_of_rec(x)) != signbit(value_of_rec(y))) ? -x : x; } /** From 657b9d392dd011766f23484c7e58c18eefa49b88 Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Mon, 23 Mar 2020 12:54:11 -0400 Subject: [PATCH 50/63] added test cases and removed dead comments --- stan/math/rev/core/operator_division.hpp | 40 ------------------------ test/unit/math/mix/fun/arg_test.cpp | 4 +-- test/unit/math/mix/fun/copysign_test.cpp | 3 +- test/unit/math/mix/fun/polar_test.cpp | 8 ++--- 4 files changed, 7 insertions(+), 48 deletions(-) diff --git a/stan/math/rev/core/operator_division.hpp b/stan/math/rev/core/operator_division.hpp index 49f1120d2fb..420ec04d07d 100644 --- a/stan/math/rev/core/operator_division.hpp +++ b/stan/math/rev/core/operator_division.hpp @@ -145,46 +145,6 @@ inline std::complex operator/(const std::complex& x1, return internal::complex_divide(x1, x2); } -// template ...> -// inline std::complex operator/(const std::complex& x1, -// const std::complex& x2) { -// return internal::complex_divide(x1, x2); -// } -// inline std::complex operator/(const std::complex& x1, const var& -// x2) { -// return internal::complex_divide(x1, x2); -// } -// template ...> -// inline std::complex operator/(const std::complex& x1, T x2) { -// return internal::complex_divide(x1, x2); -// } - -// template ...> -// inline std::complex operator/(const std::complex& x1, -// const std::complex& x2) { -// return internal::complex_divide(x1, x2); -// } -// template ...> -// inline std::complex operator/(const std::complex& x1, const var& x2) -// { -// return internal::complex_divide(x1, x2); -// } - -// inline std::complex operator/(const var& x1, const std::complex& -// x2) { -// return internal::complex_divide(x1, x2); -// } -// template ...> -// inline std::complex operator/(const var& x1, const std::complex& x2) -// { -// return internal::complex_divide(x1, x2); -// } - -// template ...> -// inline std::complex operator/(T x1, const std::complex& x2) { -// return internal::complex_divide(x1, x2); -// } - } // namespace math } // namespace stan #endif diff --git a/test/unit/math/mix/fun/arg_test.cpp b/test/unit/math/mix/fun/arg_test.cpp index 9fe7b6dbd79..93c62aa1f09 100644 --- a/test/unit/math/mix/fun/arg_test.cpp +++ b/test/unit/math/mix/fun/arg_test.cpp @@ -7,8 +7,8 @@ TEST(mixScalFun, arg) { // undefined with 0 in denominator stan::test::expect_ad(f, std::complex(0.9, 0.8)); - for (double im : std::vector{-1.3, 2.3}) { - for (double re : std::vector{-3.6, -0.0, 0.0, 0.5}) { + for (double re : std::vector{-3.6, -0.0, 0.0, 0.5}) { + for (double im : std::vector{-1.3, 2.3}) { stan::test::expect_ad(f, std::complex(re, im)); } } diff --git a/test/unit/math/mix/fun/copysign_test.cpp b/test/unit/math/mix/fun/copysign_test.cpp index 57ddeca4ff2..1f5246bfbca 100644 --- a/test/unit/math/mix/fun/copysign_test.cpp +++ b/test/unit/math/mix/fun/copysign_test.cpp @@ -18,8 +18,9 @@ void expect_copysign() { using std::copysign; using std::numeric_limits; + double nan = numeric_limits::quiet_NaN(); double inf = numeric_limits::infinity(); - std::vector ys{inf, -inf, -1, 0, 1}; + std::vector ys{-inf, -1, -0.0, 0.0, 1, inf, nan}; // real for (double x : ys) { diff --git a/test/unit/math/mix/fun/polar_test.cpp b/test/unit/math/mix/fun/polar_test.cpp index d0e6c70cf3b..2e23f0843b8 100644 --- a/test/unit/math/mix/fun/polar_test.cpp +++ b/test/unit/math/mix/fun/polar_test.cpp @@ -12,8 +12,9 @@ TEST(mathMixMatFun, polar) { }; stan::test::expect_ad(f, 0.2, 0.5); - // TODO(carpenter): fix this so it succeeds in test framework - // stan::test::expect_ad(f, 1, 0.5); + stan::test::expect_ad(f, 1, 0.5); + stan::test::expect_ad(f, 0.2, 1); + stan::test::expect_ad(f, 1, 1); auto f1 = [](const auto& r, const auto& theta) { using stan::math::polar; @@ -47,7 +48,4 @@ TEST(mathMixMatFun, polar) { stan::test::expect_ad(f1, 1, theta); stan::test::expect_ad(f2, 1, theta); } - - // need to fix this, too, because it's failing - // EXPECT_TRUE(stan::is_stan_scalar>::value); } From 4af97831070891eb7bb306332bf647bb2914f8e3 Mon Sep 17 00:00:00 2001 From: Stan Jenkins Date: Mon, 23 Mar 2020 12:55:30 -0400 Subject: [PATCH 51/63] [Jenkins] auto-formatting by clang-format version 6.0.0 (tags/google/stable/2017-11-14) --- test/unit/math/prim/fun/binomial_coefficient_log_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/math/prim/fun/binomial_coefficient_log_test.cpp b/test/unit/math/prim/fun/binomial_coefficient_log_test.cpp index 91e7dd9ba04..e5df58947b9 100644 --- a/test/unit/math/prim/fun/binomial_coefficient_log_test.cpp +++ b/test/unit/math/prim/fun/binomial_coefficient_log_test.cpp @@ -48,8 +48,8 @@ TEST(MathFunctions, binomial_coefficient_log_nan) { } TEST(MathFunctions, binomial_coefficient_log_errors_edge_cases) { - using stan::math::binomial_coefficient_log; using stan::math::INFTY; + using stan::math::binomial_coefficient_log; EXPECT_NO_THROW(binomial_coefficient_log(10, 11)); EXPECT_THROW(binomial_coefficient_log(10, 11.01), std::domain_error); From c254454fd631159104272790fa64ce13b13032fd Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Mon, 23 Mar 2020 13:24:39 -0400 Subject: [PATCH 52/63] rev copysign includes --- stan/math/prim/fun/copysign.hpp | 5 +++-- stan/math/rev/fun/asin.hpp | 1 + stan/math/rev/fun/pow.hpp | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/stan/math/prim/fun/copysign.hpp b/stan/math/prim/fun/copysign.hpp index 96976e4cc50..781185c6a83 100644 --- a/stan/math/prim/fun/copysign.hpp +++ b/stan/math/prim/fun/copysign.hpp @@ -3,6 +3,7 @@ #include #include +#include #include namespace stan { @@ -27,8 +28,8 @@ namespace math { */ template inline T copysign(const T& x, const U& y) { - // return (x < 0 && y >= 0) || (x >= 0 && y < 0) ? -x : x; - return (signbit(value_of_rec(x)) != signbit(value_of_rec(y))) ? -x : x; + return std::signbit(value_of_rec(x)) != std::signbit(value_of_rec(y)) ? -x + : x; } /** diff --git a/stan/math/rev/fun/asin.hpp b/stan/math/rev/fun/asin.hpp index 9bf5fb74fc7..ed03e449ec8 100644 --- a/stan/math/rev/fun/asin.hpp +++ b/stan/math/rev/fun/asin.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include diff --git a/stan/math/rev/fun/pow.hpp b/stan/math/rev/fun/pow.hpp index f7b43c6fdde..c86e0280864 100644 --- a/stan/math/rev/fun/pow.hpp +++ b/stan/math/rev/fun/pow.hpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include From 2ddec401613f03648ba844fe776e5943faa47235 Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Mon, 23 Mar 2020 17:26:33 -0400 Subject: [PATCH 53/63] removed unnecessary constructor --- stan/math/prim/fun/acos.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stan/math/prim/fun/acos.hpp b/stan/math/prim/fun/acos.hpp index 09d128a89c1..88317641b0e 100644 --- a/stan/math/prim/fun/acos.hpp +++ b/stan/math/prim/fun/acos.hpp @@ -71,7 +71,7 @@ namespace internal { */ template inline std::complex complex_acos(const std::complex& z) { - return V(0.5 * pi()) - asin(z); + return 0.5 * pi() - asin(z); } } // namespace internal From 7f13bfb61b40ae63b35c7f263ebbdd715abbcc6b Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Mon, 23 Mar 2020 17:26:40 -0400 Subject: [PATCH 54/63] copysign boundary conditions --- stan/math/prim/fun/copysign.hpp | 38 +++++++++++++++---- test/unit/math/mix/fun/copysign_test.cpp | 48 ++++++++++++++++-------- 2 files changed, 63 insertions(+), 23 deletions(-) diff --git a/stan/math/prim/fun/copysign.hpp b/stan/math/prim/fun/copysign.hpp index 781185c6a83..3273ab2db1f 100644 --- a/stan/math/prim/fun/copysign.hpp +++ b/stan/math/prim/fun/copysign.hpp @@ -23,13 +23,31 @@ namespace math { * @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 + * @return copy of the first argument, negated if necessary to match + * the sign of the second argument */ template inline T copysign(const T& x, const U& y) { - return std::signbit(value_of_rec(x)) != std::signbit(value_of_rec(y)) ? -x - : x; + return (std::signbit(value_of_rec(x)) != std::signbit(value_of_rec(y))) ? -x + : x; +} + +/** + * Return the negation of the first argument if the first and second + * arguments have different signs and the first argument is not zero, + * otherwise return a copy of the first argument. + * + * @tparam T 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 the first argument, negated if necessary to match + * the sign of the second argument + * @see copysign + */ +template +inline T copysign_non_zero(const T& x, const U& y) { + return x != 0 ? stan::math::copysign(x, y) : x; } /** @@ -38,7 +56,10 @@ inline T copysign(const T& x, const U& y) { * arguments to the real and complex parts of the second. * * This is an overload of the standard libary `copysign` for complex - * numbers that will be used with argument-dependent lookup. + * numbers that will be used with argument-dependent lookup. Rather + * than using the standard library `copysign`, it uses + * `copysign_non_zero`, which does not change sign if the reference + * value is zero (`-0.0` or `0.0`). * * @tparam T value type of first argument * @tparam U value type of second argument @@ -48,9 +69,10 @@ inline T copysign(const T& x, const U& y) { * necessary to match sign of first argument */ template -inline std::complex copysign(const std::complex& y, - const std::complex& x) { - return {copysign(y.real(), x.real()), copysign(y.imag(), x.imag())}; +inline std::complex copysign(const std::complex& x, + const std::complex& y) { + return {copysign_non_zero(x.real(), y.real()), + copysign_non_zero(x.imag(), y.imag())}; } } // namespace math diff --git a/test/unit/math/mix/fun/copysign_test.cpp b/test/unit/math/mix/fun/copysign_test.cpp index 1f5246bfbca..e7b111c994f 100644 --- a/test/unit/math/mix/fun/copysign_test.cpp +++ b/test/unit/math/mix/fun/copysign_test.cpp @@ -15,38 +15,56 @@ void expect_eq_signbit(const U& u, const V& v) { template void expect_copysign() { using stan::math::copysign; + using stan::math::copysign_non_zero; + using stan::math::is_nan; + using stan::math::value_of_rec; using std::copysign; using std::numeric_limits; double nan = numeric_limits::quiet_NaN(); double inf = numeric_limits::infinity(); - std::vector ys{-inf, -1, -0.0, 0.0, 1, inf, nan}; + std::vector vs{-inf, -1, -0.0, 0.0, 1, inf, nan}; // real - for (double x : ys) { - for (double y : ys) { + for (double x : vs) { + for (double y : vs) { expect_eq_signbit(y, copysign(T(x), y)); expect_eq_signbit(y, copysign(x, T(y))); expect_eq_signbit(y, copysign(T(x), T(y))); } } + // complex - for (double re1 : ys) { - for (double im1 : ys) { + for (double re1 : vs) { + for (double im1 : vs) { auto x_d = std::complex(re1, im1); auto x_t = std::complex(re1, im1); - for (double re2 : ys) { - for (double im2 : ys) { + for (double re2 : vs) { + for (double im2 : vs) { auto y_d = std::complex(re2, im2); auto y_t = std::complex(re2, im2); - expect_eq_signbit(re2, copysign(x_d, y_d).real()); - expect_eq_signbit(re2, copysign(x_d, y_t).real()); - expect_eq_signbit(re2, copysign(x_t, y_d).real()); - expect_eq_signbit(re2, copysign(x_t, y_t).real()); - expect_eq_signbit(im2, copysign(x_d, y_d).imag()); - expect_eq_signbit(im2, copysign(x_d, y_t).imag()); - expect_eq_signbit(im2, copysign(x_t, y_d).imag()); - expect_eq_signbit(im2, copysign(x_t, y_t).imag()); + if (re1 == 0) { + EXPECT_FLOAT_EQ(0.0, value_of_rec(copysign(x_d, y_d).real())); + EXPECT_FLOAT_EQ(0.0, value_of_rec(copysign(x_d, y_t).real())); + EXPECT_FLOAT_EQ(0.0, value_of_rec(copysign(x_t, y_d).real())); + EXPECT_FLOAT_EQ(0.0, value_of_rec(copysign(x_t, y_t).real())); + } else { + expect_eq_signbit(re2, copysign(x_d, y_d).real()); + expect_eq_signbit(re2, copysign(x_d, y_t).real()); + expect_eq_signbit(re2, copysign(x_t, y_d).real()); + expect_eq_signbit(re2, copysign(x_t, y_t).real()); + } + if (im1 == 0) { + EXPECT_FLOAT_EQ(0.0, value_of_rec(copysign(x_d, y_d).imag())); + EXPECT_FLOAT_EQ(0.0, value_of_rec(copysign(x_d, y_t).imag())); + EXPECT_FLOAT_EQ(0.0, value_of_rec(copysign(x_t, y_d).imag())); + EXPECT_FLOAT_EQ(0.0, value_of_rec(copysign(x_t, y_t).imag())); + } else { + expect_eq_signbit(im2, copysign(x_d, y_d).imag()); + expect_eq_signbit(im2, copysign(x_d, y_t).imag()); + expect_eq_signbit(im2, copysign(x_t, y_d).imag()); + expect_eq_signbit(im2, copysign(x_t, y_t).imag()); + } } } } From 492b26c9db3a67d4a49c6ed5f65e28ac07c14e87 Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Mon, 23 Mar 2020 20:07:38 -0400 Subject: [PATCH 55/63] remove unused code and comments --- test/unit/math/mix/fun/polar_test.cpp | 3 +- test/unit/math/test_ad.hpp | 63 +++------------------------ 2 files changed, 8 insertions(+), 58 deletions(-) diff --git a/test/unit/math/mix/fun/polar_test.cpp b/test/unit/math/mix/fun/polar_test.cpp index 2e23f0843b8..f1a1a8805b9 100644 --- a/test/unit/math/mix/fun/polar_test.cpp +++ b/test/unit/math/mix/fun/polar_test.cpp @@ -3,8 +3,7 @@ #include #include -TEST(mathMixMatFun, polar) { - // test framework can't handle (real x real) -> complex, so factor tests +TEST(mathMixFun, polar) { auto f = [](const auto& r, const auto& theta) { using stan::math::polar; auto y = polar(r, theta); diff --git a/test/unit/math/test_ad.hpp b/test/unit/math/test_ad.hpp index 5652f44f302..05825067755 100644 --- a/test/unit/math/test_ad.hpp +++ b/test/unit/math/test_ad.hpp @@ -1774,66 +1774,17 @@ void expect_complex_compare(const F& f, const std::complex& z1, T z1r{z1.real()}; T z2r{z2.real()}; - // EXPECT_EQ(f(z1, z2), f(cz1, cz2)); // PASS - // EXPECT_EQ(f(z1, z2), f(cz1, z2)); // PASS - // EXPECT_EQ(f(z1, z2), f(z1, cz2)); // PASS + EXPECT_EQ(f(z1, z2), f(cz1, cz2)); + EXPECT_EQ(f(z1, z2), f(cz1, z2)); + EXPECT_EQ(f(z1, z2), f(z1, cz2)); - EXPECT_EQ(f(z1.real(), z2), f(z1r, cz2)); // FAIL - // EXPECT_EQ(f(z1.real(), z2), f(z1r, z2)); // PASS + EXPECT_EQ(f(z1.real(), z2), f(z1r, cz2)); + EXPECT_EQ(f(z1.real(), z2), f(z1r, z2)); - // // EXPECT_EQ(f(z1, z2.real()), f(cz1, z2r)); // FAIL - // EXPECT_EQ(f(z1, z2.real()), f(z1, z2r)); // PASS + EXPECT_EQ(f(z1, z2.real()), f(cz1, z2r)); + EXPECT_EQ(f(z1, z2.real()), f(z1, z2r)); } -template -void expect_complex_comparison(const F& f, const std::complex& z1, - const std::complex& z2) { - using stan::math::fvar; - using stan::math::var; - using std::complex; - // expect_complex_compare(f, z1, z2); // PASS - expect_complex_compare(f, z1, z2); // FAIL - // expect_complex_compare>(f, z1, z2); // PASS - // expect_complex_compare>>(f, z1, z2); // PASS - // expect_complex_compare>(f, z1, z2); // PASS - // expect_complex_compare>>(f, z1, z2); // PASS -} - -template -void expect_complex_common_comparison(const F& f) { - for (auto z1 : common_complex()) { - for (auto z2 : common_complex()) { - expect_complex_comparison(f, z1, z2); - } - } -} - -// template -// void expect_reduction(const F& f) { -// cvar_t x(1, 2); -// var_t y = f(x); - -// cdouble_t xd(1, 2); -// double yd = f(xd); -// EXPECT_FLOAT_EQ(yd, y.val()); -// } - -// std::vector common_complex_non_neg_parts() { -// double inf = std::numeric_limits::infinity(); -// double nan = std::numeric_limits::quiet_NaN(); -// double pos_zero = 0.0; -// return {0.0, 1.3, 2.1}; -// } - -// template -// std::vector to_array(const std::complex& a) { -// return {a.real(), a.imag()}; -// } -// template -// std::complex from_array(const std::vector& a) { -// return {a[0], a[1]}; -// } - } // namespace test } // namespace stan #endif From 9829029823779a17483750ab3cc92134e588b3e1 Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Mon, 23 Mar 2020 20:47:47 -0400 Subject: [PATCH 56/63] tests for complex ==, != w. framework --- stan/math/prim/core/operator_equal_equal.hpp | 19 +++------------- test/unit/math/test_ad.hpp | 23 ++++++++++++++++++++ 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/stan/math/prim/core/operator_equal_equal.hpp b/stan/math/prim/core/operator_equal_equal.hpp index cf5228a11cf..4c66cd90b5a 100644 --- a/stan/math/prim/core/operator_equal_equal.hpp +++ b/stan/math/prim/core/operator_equal_equal.hpp @@ -3,7 +3,6 @@ #include #include -#include // TODO(carpenter): get rid of this include namespace stan { namespace math { @@ -18,7 +17,7 @@ namespace math { * @param y second argument * @return `true` if the arguments are equal */ -template +template > inline bool operator==(const std::complex& x, const std::complex& y) { return x.real() == y.real() && x.imag() == y.imag(); } @@ -33,7 +32,7 @@ inline bool operator==(const std::complex& x, const std::complex& y) { * @param y second argument * @return `true` if the arguments are equal */ -template +template > inline bool operator==(const std::complex& x, const V& y) { return x.real() == y && x.imag() == 0; } @@ -49,23 +48,11 @@ inline bool operator==(const std::complex& x, const V& y) { * @param y second argument * @return `true` if the arguments are equal */ -template +template > inline bool operator==(const U& x, const std::complex& y) { return x == y.real() && 0 == y.imag(); } -// ambiguous with lib wo specific autodiff type -template > -inline bool operator==(const U& x, const std::complex& y) { - return x == y.real() && 0 == y.imag(); -} - -template > -inline bool operator==(const std::complex& x, const U& y) { - return x.real() == y && x.imag() == 0; -} - } // namespace math } // namespace stan - #endif diff --git a/test/unit/math/test_ad.hpp b/test/unit/math/test_ad.hpp index 05825067755..a75fd784733 100644 --- a/test/unit/math/test_ad.hpp +++ b/test/unit/math/test_ad.hpp @@ -1785,6 +1785,29 @@ void expect_complex_compare(const F& f, const std::complex& z1, EXPECT_EQ(f(z1, z2.real()), f(z1, z2r)); } +template +void expect_complex_comparison(const F& f, const std::complex& z1, + const std::complex& z2) { + using stan::math::fvar; + using stan::math::var; + using std::complex; + expect_complex_compare(f, z1, z2); // PASS + expect_complex_compare(f, z1, z2); // FAIL + expect_complex_compare>(f, z1, z2); // PASS + expect_complex_compare>>(f, z1, z2); // PASS + expect_complex_compare>(f, z1, z2); // PASS + expect_complex_compare>>(f, z1, z2); // PASS +} + +template +void expect_complex_common_comparison(const F& f) { + for (auto z1 : common_complex()) { + for (auto z2 : common_complex()) { + expect_complex_comparison(f, z1, z2); + } + } +} + } // namespace test } // namespace stan #endif From 779dc954542aac9adcd8e2918ace0b069d824472 Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Wed, 25 Mar 2020 17:06:33 -0400 Subject: [PATCH 57/63] doc for complex comparison test --- test/unit/math/test_ad.hpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/unit/math/test_ad.hpp b/test/unit/math/test_ad.hpp index a75fd784733..d9c9e5dd94c 100644 --- a/test/unit/math/test_ad.hpp +++ b/test/unit/math/test_ad.hpp @@ -1799,6 +1799,13 @@ void expect_complex_comparison(const F& f, const std::complex& z1, expect_complex_compare>>(f, z1, z2); // PASS } +/** + * Test the specified comparison operation provides results matching + * those for the double version for all the common complex numbers. + * + * @tparam F type of function to test + * @param f function to test + */ template void expect_complex_common_comparison(const F& f) { for (auto z1 : common_complex()) { From e04365de7a39cbf5a70ef85240f2710ac315aeab Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Thu, 26 Mar 2020 15:20:56 -0400 Subject: [PATCH 58/63] resolve pow(complex, int) ambiguity in gcc from C++99 --- stan/math/fwd/fun/pow.hpp | 17 +++++ stan/math/rev/fun/pow.hpp | 15 +++++ test/unit/math/mix/fun/pow_test.cpp | 99 +++++++++++++++++++++++++++-- 3 files changed, 125 insertions(+), 6 deletions(-) diff --git a/stan/math/fwd/fun/pow.hpp b/stan/math/fwd/fun/pow.hpp index ccc858f5679..c181df79b62 100644 --- a/stan/math/fwd/fun/pow.hpp +++ b/stan/math/fwd/fun/pow.hpp @@ -197,6 +197,23 @@ inline std::complex> pow(T x, const std::complex>& y) { return internal::complex_pow(x, y); } +/** + * Return the first argument raised to the power of the second argument. + * + * Note: this overload is required because gcc still provides the + * C++99 template function `pow(complex, int)`, which introduces + * an ambiguity. + * + * @tparam T autodiff value type + * @param x first argument + * @param y second argument + * @return first argument to the power of the second argument + */ +template +inline std::complex> pow(const std::complex>& x, int y) { + return internal::complex_pow(x, y); +} + } // namespace math } // namespace stan #endif diff --git a/stan/math/rev/fun/pow.hpp b/stan/math/rev/fun/pow.hpp index c86e0280864..577c23381fd 100644 --- a/stan/math/rev/fun/pow.hpp +++ b/stan/math/rev/fun/pow.hpp @@ -306,6 +306,21 @@ inline std::complex pow(T x, const std::complex& y) { return internal::complex_pow(x, y); } +/** + * Return the first argument raised to the power of the second argument. + * + * Note: this overload is required because gcc still provides the + * C++99 template function `pow(complex, int)`, which introduces + * an ambiguity. + * + * @param x first argument + * @param y second argument + * @return first argument to the power of the second argument + */ +inline std::complex pow(const std::complex& x, int y) { + return internal::complex_pow(x, y); +} + } // namespace math } // namespace stan #endif diff --git a/test/unit/math/mix/fun/pow_test.cpp b/test/unit/math/mix/fun/pow_test.cpp index aec26627dca..937809035e2 100644 --- a/test/unit/math/mix/fun/pow_test.cpp +++ b/test/unit/math/mix/fun/pow_test.cpp @@ -5,19 +5,26 @@ template void expect_arith_instantiate() { - using stan::math::pow; using std::pow; - auto a = pow(T(1.0), 1); - auto b = pow(T(1.0), 1.0); - auto c = pow(1, T(1.0)); - auto d = pow(1.0, T(1.0)); + auto a1 = pow(T(1.0), 1); + auto b1 = pow(T(1.0), 1.0); + auto c1 = pow(1, T(1.0)); + auto d1 = pow(1.0, T(1.0)); + auto e1 = pow(T(1.0), T(1.0)); + + auto a2 = pow(std::complex(1.0), 1); + auto b2 = pow(std::complex(1.0), 1.0); + auto c2 = pow(1, std::complex(1.0)); + auto d2 = pow(1.0, std::complex(1.0)); + auto e2 = pow(std::complex(1.0), std::complex(1.0)); + auto f2 = pow(std::complex(1.0), std::complex(1.0)); + auto g2 = pow(std::complex(1.0), std::complex(1.0)); } // this one's been tricky to instantiate, so test all instances TEST(mathMixScalFun, powInstantiations) { using stan::math::fvar; using stan::math::var; - expect_arith_instantiate(); expect_arith_instantiate(); expect_arith_instantiate(); expect_arith_instantiate>(); @@ -83,3 +90,83 @@ TEST(mathMixFun, complexPow) { } } } + +// TEST(mathMixFun, powIntAmbiguityTest) { +// using std::pow; +// using stan::math::var; +// using std::complex; +// int i = 2; +// double d = 2.5; +// var v = 2.5; +// complex cd = 2.5; +// complex cv = 2.5; + +// auto a1 = pow(i, i); +// auto a2 = pow(i, d); +// auto a3 = pow(i, v); +// auto a4 = pow(i, cd); +// auto a5 = pow(i, cv); + +// auto b1 = pow(d, i); +// auto b2 = pow(d, d); +// auto b3 = pow(d, v); +// auto b4 = pow(d, cd); +// auto b5 = pow(d, cv); + +// auto c1 = pow(cd, i); +// auto c2 = pow(cd, d); +// auto c3 = pow(cd, v); +// auto c4 = pow(cd, cd); +// auto c5 = pow(cd, cv); + +// auto d1 = pow(cv, i); +// auto d2 = pow(cv, d); +// auto d3 = pow(cv, v); +// auto d4 = pow(cv, cd); +// auto d5 = pow(cv, cv); + +// auto e = a1 + a2 + a3 + a4 + a5 +// + b1 + b2 + b3 + b4 + b5 +// + c1 + c2 + c3 + c4 + c5 +// + d1 + d2 + d3 + d4 + d5; +// } + +// TEST(mathMixFun, powIntAmbiguityTestFvar) { +// using std::pow; +// using stan::math::fvar; +// using std::complex; +// int i = 2; +// double d = 2.5; +// fvar v = 2.5; +// complex cd = 2.5; +// complex> cv = 2.5; + +// auto a1 = pow(i, i); +// auto a2 = pow(i, d); +// auto a3 = pow(i, v); +// auto a4 = pow(i, cd); +// auto a5 = pow(i, cv); + +// auto b1 = pow(d, i); +// auto b2 = pow(d, d); +// auto b3 = pow(d, v); +// auto b4 = pow(d, cd); +// auto b5 = pow(d, cv); + +// auto c1 = pow(cd, i); +// auto c2 = pow(cd, d); +// auto c3 = pow(cd, v); +// auto c4 = pow(cd, cd); +// auto c5 = pow(cd, cv); + +// auto d1 = pow(cv, i); +// auto d2 = pow(cv, d); +// auto d3 = pow(cv, v); +// auto d4 = pow(cv, cd); +// auto d5 = pow(cv, cv); + +// auto e = a1 + a2 + a3 + a4 + a5 +// + b1 + b2 + b3 + b4 + b5 +// + c1 + c2 + c3 + c4 + c5 +// + d1 + d2 + d3 + d4 + d5; +// } From b4bccc9308bbf8f982debc324b41dc887c556081 Mon Sep 17 00:00:00 2001 From: Stan Jenkins Date: Thu, 26 Mar 2020 15:21:52 -0400 Subject: [PATCH 59/63] [Jenkins] auto-formatting by clang-format version 6.0.0 (tags/google/stable/2017-11-14) --- stan/math/opencl/kernel_generator/load.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stan/math/opencl/kernel_generator/load.hpp b/stan/math/opencl/kernel_generator/load.hpp index af538d6653b..63836cc7a07 100644 --- a/stan/math/opencl/kernel_generator/load.hpp +++ b/stan/math/opencl/kernel_generator/load.hpp @@ -48,7 +48,7 @@ class load_ * Creates a deep copy of this expression. * @return copy of \c *this */ - inline load_ deep_copy() const & { return load_(a_); } + inline load_ deep_copy() const& { return load_(a_); } inline load_ deep_copy() && { return load_(std::forward(a_)); } /** From 1a64c9a59dcdf1bde8237ca29a9d88aba44962f1 Mon Sep 17 00:00:00 2001 From: Bob Carpenter Date: Fri, 27 Mar 2020 20:03:23 -0400 Subject: [PATCH 60/63] MINGW32-specific overload resolving pow(double, int) ambiguity --- stan/math/prim/fun/pow.hpp | 27 ++++- test/unit/math/mix/fun/pow_test.cpp | 163 ++++++++++++++-------------- 2 files changed, 106 insertions(+), 84 deletions(-) diff --git a/stan/math/prim/fun/pow.hpp b/stan/math/prim/fun/pow.hpp index 560bc332de4..1b3e3e7c044 100644 --- a/stan/math/prim/fun/pow.hpp +++ b/stan/math/prim/fun/pow.hpp @@ -8,17 +8,34 @@ namespace stan { namespace math { + +// This overload is required becuase MINGW32 does not include the +// specialization std::pow(double, int) as required by the C++11 +// standard library interface specification. Use with other compilers +// than MINGW32 would introduce an ambiguity with the standard library. +#if __MINGW32__ +/** + * Return the first argument raised to the power of the second + * argument. + * + * @param x base + * @param y exponent + * @return base raised to the power of the exponent + */ +double pow(double x, int y) { return std::pow(x, static_cast(y)); } +#endif + namespace internal { /** * Return the first argument raised to the power of the second * argument. At least one of the arguments must be a complex number. * - * @tparam U type of first argument - * @tparam V type of second argument - * @param[in] x first argument - * @param[in] y second argument - * @return first argument raised to the power of the second argument + * @tparam U type of base + * @tparam V type of exponent + * @param[in] x base + * @param[in] y exponent + * @return base raised to the power of the exponent */ template inline complex_return_t complex_pow(const U& x, const V& y) { diff --git a/test/unit/math/mix/fun/pow_test.cpp b/test/unit/math/mix/fun/pow_test.cpp index 937809035e2..4a48fa235b7 100644 --- a/test/unit/math/mix/fun/pow_test.cpp +++ b/test/unit/math/mix/fun/pow_test.cpp @@ -5,6 +5,7 @@ template void expect_arith_instantiate() { + using stan::math::pow; using std::pow; auto a1 = pow(T(1.0), 1); auto b1 = pow(T(1.0), 1.0); @@ -91,82 +92,86 @@ TEST(mathMixFun, complexPow) { } } -// TEST(mathMixFun, powIntAmbiguityTest) { -// using std::pow; -// using stan::math::var; -// using std::complex; -// int i = 2; -// double d = 2.5; -// var v = 2.5; -// complex cd = 2.5; -// complex cv = 2.5; - -// auto a1 = pow(i, i); -// auto a2 = pow(i, d); -// auto a3 = pow(i, v); -// auto a4 = pow(i, cd); -// auto a5 = pow(i, cv); - -// auto b1 = pow(d, i); -// auto b2 = pow(d, d); -// auto b3 = pow(d, v); -// auto b4 = pow(d, cd); -// auto b5 = pow(d, cv); - -// auto c1 = pow(cd, i); -// auto c2 = pow(cd, d); -// auto c3 = pow(cd, v); -// auto c4 = pow(cd, cd); -// auto c5 = pow(cd, cv); - -// auto d1 = pow(cv, i); -// auto d2 = pow(cv, d); -// auto d3 = pow(cv, v); -// auto d4 = pow(cv, cd); -// auto d5 = pow(cv, cv); - -// auto e = a1 + a2 + a3 + a4 + a5 -// + b1 + b2 + b3 + b4 + b5 -// + c1 + c2 + c3 + c4 + c5 -// + d1 + d2 + d3 + d4 + d5; -// } - -// TEST(mathMixFun, powIntAmbiguityTestFvar) { -// using std::pow; -// using stan::math::fvar; -// using std::complex; -// int i = 2; -// double d = 2.5; -// fvar v = 2.5; -// complex cd = 2.5; -// complex> cv = 2.5; - -// auto a1 = pow(i, i); -// auto a2 = pow(i, d); -// auto a3 = pow(i, v); -// auto a4 = pow(i, cd); -// auto a5 = pow(i, cv); - -// auto b1 = pow(d, i); -// auto b2 = pow(d, d); -// auto b3 = pow(d, v); -// auto b4 = pow(d, cd); -// auto b5 = pow(d, cv); - -// auto c1 = pow(cd, i); -// auto c2 = pow(cd, d); -// auto c3 = pow(cd, v); -// auto c4 = pow(cd, cd); -// auto c5 = pow(cd, cv); - -// auto d1 = pow(cv, i); -// auto d2 = pow(cv, d); -// auto d3 = pow(cv, v); -// auto d4 = pow(cv, cd); -// auto d5 = pow(cv, cv); - -// auto e = a1 + a2 + a3 + a4 + a5 -// + b1 + b2 + b3 + b4 + b5 -// + c1 + c2 + c3 + c4 + c5 -// + d1 + d2 + d3 + d4 + d5; -// } +TEST(mathMixFun, powIntAmbiguityTest) { + using stan::math::pow; // included to check ambiguities + using stan::math::var; + using std::complex; + using std::pow; + int i = 2; + double d = 2.5; + var v = 2.5; + complex cd = 2.5; + complex cv = 2.5; + + auto a1 = pow(i, i); + auto a2 = pow(i, d); + auto a3 = pow(i, v); + auto a4 = pow(i, cd); + auto a5 = pow(i, cv); + + auto b1 = pow(d, i); + auto b2 = pow(d, d); + auto b3 = pow(d, v); + auto b4 = pow(d, cd); + auto b5 = pow(d, cv); + + auto e1 = pow(v, i); + auto e2 = pow(v, d); + auto e3 = pow(v, v); + auto e4 = pow(v, cd); + auto e5 = pow(v, cv); + + auto c1 = pow(cd, i); + auto c2 = pow(cd, d); + auto c3 = pow(cd, v); + auto c4 = pow(cd, cd); + auto c5 = pow(cd, cv); + + auto d1 = pow(cv, i); + auto d2 = pow(cv, d); + auto d3 = pow(cv, v); + auto d4 = pow(cv, cd); + auto d5 = pow(cv, cv); + + auto e = a1 + a2 + a3 + a4 + a5 + b1 + b2 + b3 + b4 + b5 + c1 + c2 + c3 + c4 + + c5 + d1 + d2 + d3 + d4 + d5; +} + +TEST(mathMixFun, powIntAmbiguityTestFvar) { + using stan::math::fvar; + using stan::math::pow; // included to check ambiguities + using std::complex; + using std::pow; + int i = 2; + double d = 2.5; + fvar v = 2.5; + complex cd = 2.5; + complex> cv = 2.5; + + auto a1 = pow(i, i); + auto a2 = pow(i, d); + auto a3 = pow(i, v); + auto a4 = pow(i, cd); + auto a5 = pow(i, cv); + + auto b1 = pow(d, i); + auto b2 = pow(d, d); + auto b3 = pow(d, v); + auto b4 = pow(d, cd); + auto b5 = pow(d, cv); + + auto c1 = pow(cd, i); + auto c2 = pow(cd, d); + auto c3 = pow(cd, v); + auto c4 = pow(cd, cd); + auto c5 = pow(cd, cv); + + auto d1 = pow(cv, i); + auto d2 = pow(cv, d); + auto d3 = pow(cv, v); + auto d4 = pow(cv, cd); + auto d5 = pow(cv, cv); + + auto e = a1 + a2 + a3 + a4 + a5 + b1 + b2 + b3 + b4 + b5 + c1 + c2 + c3 + c4 + + c5 + d1 + d2 + d3 + d4 + d5; +} From d430f803c524b77eb32d6cb61a5c6159a61df8df Mon Sep 17 00:00:00 2001 From: Ben Date: Fri, 27 Mar 2020 21:53:36 -0400 Subject: [PATCH 61/63] Made mingw implementation of pow inline (issue #123) --- stan/math/prim/fun/pow.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stan/math/prim/fun/pow.hpp b/stan/math/prim/fun/pow.hpp index 1b3e3e7c044..78831642b5f 100644 --- a/stan/math/prim/fun/pow.hpp +++ b/stan/math/prim/fun/pow.hpp @@ -22,7 +22,7 @@ namespace math { * @param y exponent * @return base raised to the power of the exponent */ -double pow(double x, int y) { return std::pow(x, static_cast(y)); } +inline double pow(double x, int y) { return std::pow(x, static_cast(y)); } #endif namespace internal { From 06b15fd3485c3f4f515719f7c31b50fff4b1ede9 Mon Sep 17 00:00:00 2001 From: Stan Jenkins Date: Sat, 28 Mar 2020 01:56:14 +0000 Subject: [PATCH 62/63] [Jenkins] auto-formatting by clang-format version 5.0.0-3~16.04.1 (tags/RELEASE_500/final) --- stan/math/opencl/kernel_generator/load.hpp | 2 +- stan/math/prim/fun/pow.hpp | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/stan/math/opencl/kernel_generator/load.hpp b/stan/math/opencl/kernel_generator/load.hpp index ae0f7d1eb6d..799cdb551a0 100644 --- a/stan/math/opencl/kernel_generator/load.hpp +++ b/stan/math/opencl/kernel_generator/load.hpp @@ -49,7 +49,7 @@ class load_ * Creates a deep copy of this expression. * @return copy of \c *this */ - inline load_ deep_copy() const& { return load_(a_); } + inline load_ deep_copy() const & { return load_(a_); } inline load_ deep_copy() && { return load_(std::forward(a_)); } /** diff --git a/stan/math/prim/fun/pow.hpp b/stan/math/prim/fun/pow.hpp index 78831642b5f..da61000e00f 100644 --- a/stan/math/prim/fun/pow.hpp +++ b/stan/math/prim/fun/pow.hpp @@ -22,7 +22,9 @@ namespace math { * @param y exponent * @return base raised to the power of the exponent */ -inline double pow(double x, int y) { return std::pow(x, static_cast(y)); } +inline double pow(double x, int y) { + return std::pow(x, static_cast(y)); +} #endif namespace internal { From 1fce19711aa6368948b92db0ef05cb48d01fdf6d Mon Sep 17 00:00:00 2001 From: Stan Jenkins Date: Fri, 27 Mar 2020 21:57:00 -0400 Subject: [PATCH 63/63] [Jenkins] auto-formatting by clang-format version 6.0.0 (tags/google/stable/2017-11-14) --- stan/math/opencl/kernel_generator/load.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stan/math/opencl/kernel_generator/load.hpp b/stan/math/opencl/kernel_generator/load.hpp index 799cdb551a0..ae0f7d1eb6d 100644 --- a/stan/math/opencl/kernel_generator/load.hpp +++ b/stan/math/opencl/kernel_generator/load.hpp @@ -49,7 +49,7 @@ class load_ * Creates a deep copy of this expression. * @return copy of \c *this */ - inline load_ deep_copy() const & { return load_(a_); } + inline load_ deep_copy() const& { return load_(a_); } inline load_ deep_copy() && { return load_(std::forward(a_)); } /**