1 #ifndef STAN_MATH_PRIM_FUN_OFFSET_MULTIPLIER_FREE_HPP
2 #define STAN_MATH_PRIM_FUN_OFFSET_MULTIPLIER_FREE_HPP
3
4 #include <stan/math/prim/meta.hpp>
5 #include <stan/math/prim/err.hpp>
6 #include <stan/math/prim/fun/identity_free.hpp>
7 #include <stan/math/prim/fun/to_ref.hpp>
8 #include <stan/math/prim/fun/value_of.hpp>
9 #include <cmath>
10
11 namespace stan {
12 namespace math {
13
14 /**
15 * Return the unconstrained variable that transforms to the
16 * specified offset and multiplier constrained variable given the specified
17 * offset and multiplier.
18 *
19 * <p>The transform in <code>locmultiplier_constrain(T, double, double)</code>,
20 * is reversed by the reverse affine transformation,
21 *
22 * <p>\f$f^{-1}(y) = \frac{y - L}{S}\f$
23 *
24 * where \f$L\f$ and \f$S\f$ are the offset and multiplier.
25 *
26 * <p>If the offset is zero and multiplier is one,
27 * this function reduces to <code>identity_free(y)</code>.
28 *
29 * @tparam T type of constrained variable
30 * @tparam L type of offset
31 * @tparam S type of multiplier
32 * @param y constrained value
33 * @param[in] mu offset of constrained output
34 * @param[in] sigma multiplier of constrained output
35 * @return the unconstrained variable that transforms to the given constrained
36 * variable given the offset and multiplier
37 * @throw std::domain_error if sigma <= 0
38 * @throw std::domain_error if mu is not finite
39 * @throw std::invalid_argument if non-scalar arguments don't match in size
40 */
41 template <typename T, typename M, typename S>
offset_multiplier_free(const T & y,const M & mu,const S & sigma)42 inline auto offset_multiplier_free(const T& y, const M& mu, const S& sigma) {
43 auto&& mu_ref = to_ref(mu);
44 auto&& sigma_ref = to_ref(sigma);
45 if (is_matrix<T>::value && is_matrix<M>::value) {
46 check_matching_dims("offset_multiplier_constrain", "y", y, "mu", mu);
47 }
48 if (is_matrix<T>::value && is_matrix<S>::value) {
49 check_matching_dims("offset_multiplier_constrain", "y", y, "sigma", sigma);
50 } else if (is_matrix<M>::value && is_matrix<S>::value) {
51 check_matching_dims("offset_multiplier_constrain", "mu", mu, "sigma",
52 sigma);
53 }
54
55 check_finite("offset_multiplier_constrain", "offset", value_of(mu_ref));
56 check_positive_finite("offset_multiplier_constrain", "multiplier",
57 value_of(sigma_ref));
58 return divide(subtract(y, mu_ref), sigma_ref);
59 }
60
61 /**
62 * Overload for array of x and non-array mu and sigma
63 */
64 template <typename T, typename M, typename S,
65 require_all_not_std_vector_t<M, S>* = nullptr>
offset_multiplier_free(const std::vector<T> & x,const M & mu,const S & sigma)66 inline auto offset_multiplier_free(const std::vector<T>& x, const M& mu,
67 const S& sigma) {
68 std::vector<plain_type_t<decltype(offset_multiplier_free(x[0], mu, sigma))>>
69 ret;
70 ret.reserve(x.size());
71 const auto& mu_ref = to_ref(mu);
72 const auto& sigma_ref = to_ref(sigma);
73 for (size_t i = 0; i < x.size(); ++i) {
74 ret.emplace_back(offset_multiplier_free(x[i], mu_ref, sigma_ref));
75 }
76 return ret;
77 }
78
79 /**
80 * Overload for array of x and sigma and non-array mu
81 */
82 template <typename T, typename M, typename S,
83 require_not_std_vector_t<M>* = nullptr>
offset_multiplier_free(const std::vector<T> & x,const M & mu,const std::vector<S> & sigma)84 inline auto offset_multiplier_free(const std::vector<T>& x, const M& mu,
85 const std::vector<S>& sigma) {
86 check_matching_dims("offset_multiplier_free", "x", x, "sigma", sigma);
87 std::vector<
88 plain_type_t<decltype(offset_multiplier_free(x[0], mu, sigma[0]))>>
89 ret;
90 ret.reserve(x.size());
91 const auto& mu_ref = to_ref(mu);
92 for (size_t i = 0; i < x.size(); ++i) {
93 ret.emplace_back(offset_multiplier_free(x[i], mu_ref, sigma[i]));
94 }
95 return ret;
96 }
97
98 /**
99 * Overload for array of x and mu and non-array sigma
100 */
101 template <typename T, typename M, typename S,
102 require_not_std_vector_t<S>* = nullptr>
offset_multiplier_free(const std::vector<T> & x,const std::vector<M> & mu,const S & sigma)103 inline auto offset_multiplier_free(const std::vector<T>& x,
104 const std::vector<M>& mu, const S& sigma) {
105 check_matching_dims("offset_multiplier_free", "x", x, "mu", mu);
106 std::vector<
107 plain_type_t<decltype(offset_multiplier_free(x[0], mu[0], sigma))>>
108 ret;
109 ret.reserve(x.size());
110 const auto& sigma_ref = to_ref(sigma);
111 for (size_t i = 0; i < x.size(); ++i) {
112 ret.emplace_back(offset_multiplier_free(x[i], mu[i], sigma_ref));
113 }
114 return ret;
115 }
116
117 /**
118 * Overload for array of x, mu, and sigma
119 */
120 template <typename T, typename M, typename S>
offset_multiplier_free(const std::vector<T> & x,const std::vector<M> & mu,const std::vector<S> & sigma)121 inline auto offset_multiplier_free(const std::vector<T>& x,
122 const std::vector<M>& mu,
123 const std::vector<S>& sigma) {
124 check_matching_dims("offset_multiplier_free", "x", x, "mu", mu);
125 check_matching_dims("offset_multiplier_free", "x", x, "sigma", sigma);
126 std::vector<
127 plain_type_t<decltype(offset_multiplier_free(x[0], mu[0], sigma[0]))>>
128 ret;
129 ret.reserve(x.size());
130 for (size_t i = 0; i < x.size(); ++i) {
131 ret.emplace_back(offset_multiplier_free(x[i], mu[i], sigma[i]));
132 }
133 return ret;
134 }
135
136 } // namespace math
137 } // namespace stan
138 #endif
139