NUMhuber.cpp 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. /* NUMhuber.cpp
  2. *
  3. * Copyright (C) 1994-2008, 2015-2017 David Weenink
  4. *
  5. * This code is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or (at
  8. * your option) any later version.
  9. *
  10. * This code is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this work. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /*
  19. djmw 20030814 First version
  20. djmw 20080122 float -> double
  21. */
  22. #include "NUM2.h"
  23. void NUMmad (constVEC x, double *inout_location, bool wantlocation, double *out_mad, VEC *work) {
  24. Melder_assert (inout_location);
  25. if (x.size == 1) {
  26. if (wantlocation) *inout_location= x [1];
  27. if (out_mad) *out_mad = undefined;
  28. return;
  29. }
  30. VEC tmp;
  31. autoVEC atmp; // keep alive till end of function
  32. if (work) {
  33. tmp = *work;
  34. Melder_assert (tmp.size = x.size);
  35. } else {
  36. atmp = VECzero (x.size);
  37. tmp = atmp.get();
  38. }
  39. for (integer i = 1; i <= x.size; i ++)
  40. tmp [i] = x [i];
  41. if (wantlocation) {
  42. VECsort_inplace (tmp);
  43. *inout_location = NUMquantile (tmp, 0.5);
  44. }
  45. if (out_mad) {
  46. for (integer i = 1; i <= x.size; i ++)
  47. tmp [i] = fabs (tmp [i] - *inout_location);
  48. VECsort_inplace (tmp);
  49. *out_mad = 1.4826 * NUMquantile (tmp, 0.5);
  50. }
  51. }
  52. static double NUMgauss (double x) {
  53. return NUM1_sqrt2pi * exp (- 0.5 * x * x);
  54. }
  55. void NUMstatistics_huber (constVEC x, double *inout_location, bool wantlocation, double *inout_scale, bool wantscale, double k_stdev, double tol, VEC *work) {
  56. Melder_assert (inout_location && inout_scale);
  57. double theta = 2.0 * NUMgaussP (k_stdev) - 1.0;
  58. double beta = theta + k_stdev * k_stdev * (1.0 - theta) - 2.0 * k_stdev * NUMgauss (k_stdev);
  59. integer n1 = x.size;
  60. VEC tmp;
  61. autoVEC atmp;
  62. if (work) {
  63. tmp = *work;
  64. Melder_assert (tmp.size = x.size);
  65. } else {
  66. atmp = VECzero (x.size);
  67. tmp = atmp.get();
  68. }
  69. double mad;
  70. NUMmad (x, inout_location, wantlocation, & mad, & tmp);
  71. Melder_require (mad != 0, U"Scale is zero.");
  72. if (wantscale) {
  73. *inout_scale = mad;
  74. }
  75. double mu0, mu1 = *inout_location;
  76. double s0, s1 = *inout_scale;
  77. if (wantlocation) {
  78. n1 = x.size - 1;
  79. }
  80. do {
  81. mu0 = mu1;
  82. s0 = s1;
  83. double low = mu0 - k_stdev * s0;
  84. double high = mu0 + k_stdev * s0;
  85. for (integer i = 1; i <= x.size; i ++) {
  86. if (x [i] < low) {
  87. tmp [i] = low;
  88. } else if (x [i] > high) {
  89. tmp [i] = high;
  90. } else {
  91. tmp [i] = x [i];
  92. }
  93. }
  94. if (wantlocation)
  95. mu1 = NUMmean (tmp);
  96. if (wantscale) {
  97. s1 = 0.0;
  98. for (integer i = 1; i <= x.size; i ++) {
  99. double dx = tmp [i] - mu1;
  100. s1 += dx * dx;
  101. }
  102. s1 = sqrt (s1 / (n1 * beta));
  103. }
  104. } while (fabs (mu0 - mu1) > tol * s0 || fabs (s0 - s1) > tol * s0); //TODO fabs (mu0 - mu1) > tol * s0 ??
  105. if (wantlocation) {
  106. *inout_location = mu1;
  107. }
  108. if (wantscale) {
  109. *inout_scale = s1;
  110. }
  111. }