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