glue_quantile_meat.hpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. // Copyright 2008-2016 Conrad Sanderson (http://conradsanderson.id.au)
  2. // Copyright 2008-2016 National ICT Australia (NICTA)
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // ------------------------------------------------------------------------
  15. //! \addtogroup glue_quantile
  16. //! @{
  17. template<typename eTa, typename eTb>
  18. inline
  19. void
  20. glue_quantile::worker(eTb* out_mem, Col<eTa>& Y, const Mat<eTb>& P)
  21. {
  22. arma_extra_debug_sigprint();
  23. // NOTE: assuming out_mem is an array with P.n_elem elements
  24. // TODO: ignore non-finite values ?
  25. // algorithm based on "Definition 5" in:
  26. // Rob J. Hyndman and Yanan Fan.
  27. // Sample Quantiles in Statistical Packages.
  28. // The American Statistician, Vol. 50, No. 4, pp. 361-365, 1996.
  29. // http://doi.org/10.2307/2684934
  30. const eTb* P_mem = P.memptr();
  31. const uword P_n_elem = P.n_elem;
  32. const eTb alpha = 0.5;
  33. const eTb N = eTb(Y.n_elem);
  34. const eTb P_min = (eTb(1) - alpha) / N;
  35. const eTb P_max = (N - alpha) / N;
  36. for(uword i=0; i < P_n_elem; ++i)
  37. {
  38. const eTb P_i = P_mem[i];
  39. eTb out_val = eTb(0);
  40. if(P_i < P_min)
  41. {
  42. out_val = (P_i < eTb(0)) ? eTb(-std::numeric_limits<eTb>::infinity()) : eTb(Y.min());
  43. }
  44. else
  45. if(P_i > P_max)
  46. {
  47. out_val = (P_i > eTb(1)) ? eTb( std::numeric_limits<eTb>::infinity()) : eTb(Y.max());
  48. }
  49. else
  50. {
  51. const uword k = uword(std::floor(N * P_i + alpha));
  52. const eTb P_k = (eTb(k) - alpha) / N;
  53. const eTb w = (P_i - P_k) * N;
  54. eTa* Y_k_ptr = Y.begin() + uword(k);
  55. std::nth_element( Y.begin(), Y_k_ptr, Y.end() );
  56. const eTa Y_k_val = (*Y_k_ptr);
  57. eTa* Y_km1_ptr = Y.begin() + uword(k-1);
  58. // std::nth_element( Y.begin(), Y_km1_ptr, Y.end() );
  59. std::nth_element( Y.begin(), Y_km1_ptr, Y_k_ptr );
  60. const eTa Y_km1_val = (*Y_km1_ptr);
  61. out_val = ((eTb(1) - w) * Y_km1_val) + (w * Y_k_val);
  62. }
  63. out_mem[i] = out_val;
  64. }
  65. }
  66. template<typename eTa, typename eTb>
  67. inline
  68. void
  69. glue_quantile::apply_noalias(Mat<eTb>& out, const Mat<eTa>& X, const Mat<eTb>& P, const uword dim)
  70. {
  71. arma_extra_debug_sigprint();
  72. arma_debug_check( ((P.is_vec() == false) && (P.is_empty() == false)), "quantile(): parameter 'P' must be a vector" );
  73. if(X.is_empty()) { out.reset(); return; }
  74. const uword X_n_rows = X.n_rows;
  75. const uword X_n_cols = X.n_cols;
  76. const uword P_n_elem = P.n_elem;
  77. if(dim == 0)
  78. {
  79. out.set_size(P_n_elem, X_n_cols);
  80. if(out.is_empty()) { return; }
  81. Col<eTa> Y(X_n_rows);
  82. if(X_n_cols == 1)
  83. {
  84. arrayops::copy(Y.memptr(), X.memptr(), X_n_rows);
  85. glue_quantile::worker(out.memptr(), Y, P);
  86. }
  87. else
  88. {
  89. for(uword col=0; col < X_n_cols; ++col)
  90. {
  91. arrayops::copy(Y.memptr(), X.colptr(col), X_n_rows);
  92. glue_quantile::worker(out.colptr(col), Y, P);
  93. }
  94. }
  95. }
  96. else
  97. if(dim == 1)
  98. {
  99. out.set_size(X_n_rows, P_n_elem);
  100. if(out.is_empty()) { return; }
  101. Col<eTa> Y(X_n_cols);
  102. if(X_n_rows == 1)
  103. {
  104. arrayops::copy(Y.memptr(), X.memptr(), X_n_cols);
  105. glue_quantile::worker(out.memptr(), Y, P);
  106. }
  107. else
  108. {
  109. Col<eTb> tmp(P_n_elem);
  110. eTb* tmp_mem = tmp.memptr();
  111. for(uword row=0; row < X_n_rows; ++row)
  112. {
  113. eTa* Y_mem = Y.memptr();
  114. for(uword col=0; col < X_n_cols; ++col) { Y_mem[col] = X.at(row,col); }
  115. glue_quantile::worker(tmp_mem, Y, P);
  116. for(uword i=0; i < P_n_elem; ++i) { out.at(row,i) = tmp_mem[i]; }
  117. }
  118. }
  119. }
  120. }
  121. template<typename T1, typename T2>
  122. inline
  123. void
  124. glue_quantile::apply(Mat<typename T2::elem_type>& out, const mtGlue<typename T2::elem_type,T1,T2,glue_quantile>& expr)
  125. {
  126. arma_extra_debug_sigprint();
  127. typedef typename T2::elem_type eTb;
  128. const uword dim = expr.aux_uword;
  129. arma_debug_check( (dim > 1), "quantile(): parameter 'dim' must be 0 or 1" );
  130. const quasi_unwrap<T1> UA(expr.A);
  131. const quasi_unwrap<T2> UB(expr.B);
  132. if(UA.is_alias(out) || UB.is_alias(out))
  133. {
  134. Mat<eTb> tmp;
  135. glue_quantile::apply_noalias(tmp, UA.M, UB.M, dim);
  136. out.steal_mem(tmp);
  137. }
  138. else
  139. {
  140. glue_quantile::apply_noalias(out, UA.M, UB.M, dim);
  141. }
  142. }
  143. template<typename T1, typename T2>
  144. inline
  145. void
  146. glue_quantile_default::apply(Mat<typename T2::elem_type>& out, const mtGlue<typename T2::elem_type,T1,T2,glue_quantile_default>& expr)
  147. {
  148. arma_extra_debug_sigprint();
  149. typedef typename T2::elem_type eTb;
  150. const quasi_unwrap<T1> UA(expr.A);
  151. const quasi_unwrap<T2> UB(expr.B);
  152. const uword dim = (T1::is_xvec) ? uword(UA.M.is_rowvec() ? 1 : 0) : uword((T1::is_row) ? 1 : 0);
  153. if(UA.is_alias(out) || UB.is_alias(out))
  154. {
  155. Mat<eTb> tmp;
  156. glue_quantile::apply_noalias(tmp, UA.M, UB.M, dim);
  157. out.steal_mem(tmp);
  158. }
  159. else
  160. {
  161. glue_quantile::apply_noalias(out, UA.M, UB.M, dim);
  162. }
  163. }
  164. //! @}