Skip to content

Commit 04c98d2

Browse files
committed
[TMath] Add moving mean, moving median and mode
1 parent 075aa8e commit 04c98d2

File tree

2 files changed

+229
-1
lines changed

2 files changed

+229
-1
lines changed

math/mathcore/inc/TMath.h

+183-1
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,10 @@ struct Limits {
517517
template <typename Iterator> Double_t Mean(Iterator first, Iterator last);
518518
template <typename Iterator, typename WeightIterator> Double_t Mean(Iterator first, Iterator last, WeightIterator wfirst);
519519

520+
template <typename T> T *MovMedian(Long64_t n, T *a, Long64_t k, Double_t *w = nullptr, Long64_t *work = nullptr);
521+
template <typename T> T *MovMean(Long64_t n, T *a, Long64_t k, Double_t *w = nullptr);
522+
template <typename T> Double_t Mode(const Long64_t n, T *a);
523+
520524
template <typename T> Double_t GeomMean(Long64_t n, const T *a);
521525
template <typename Iterator> Double_t GeomMean(Iterator first, Iterator last);
522526

@@ -1083,7 +1087,7 @@ Double_t TMath::Mean(Iterator first, Iterator last, WeightIterator w)
10831087
}
10841088

10851089
////////////////////////////////////////////////////////////////////////////////
1086-
/// Returns the weighted mean of an array a with length n.
1090+
/// Returns the weighted mean of an array with a length n.
10871091

10881092
template <typename T>
10891093
Double_t TMath::Mean(Long64_t n, const T *a, const Double_t *w)
@@ -1095,6 +1099,184 @@ Double_t TMath::Mean(Long64_t n, const T *a, const Double_t *w)
10951099
}
10961100
}
10971101

1102+
////////////////////////////////////////////////////////////////////////////////
1103+
/// Returns the moving mean of an array with a length n.
1104+
1105+
template <typename T>
1106+
class Moving {
1107+
public:
1108+
T *a0;
1109+
Double_t *w0;
1110+
Long64_t *work0;
1111+
Long64_t k0;
1112+
Long64_t n0;
1113+
1114+
virtual Double_t GetValue(Long64_t n, T *a, Double_t *w = nullptr, Long64_t *work = nullptr) = 0;
1115+
virtual ~Moving() {};
1116+
1117+
Moving(Long64_t n, T *a, Long64_t k, Double_t *w = nullptr, Long64_t *work = nullptr)
1118+
{
1119+
n0 = n;
1120+
a0 = a;
1121+
k0 = k;
1122+
w0 = w;
1123+
work0 = work;
1124+
}
1125+
1126+
template <typename U>
1127+
void SplitArray(U *v, U *v1, Int_t first, Int_t last)
1128+
{
1129+
int i = 0;
1130+
1131+
while (first <= last) {
1132+
v1[i] = v[first];
1133+
i++;
1134+
first++;
1135+
}
1136+
}
1137+
1138+
Double_t GetMoving(Long64_t n, Int_t first, Int_t last, Moving *sp)
1139+
{
1140+
Double_t result;
1141+
T *a1 = new T[n + 1];
1142+
SplitArray(a0, a1, first, last);
1143+
1144+
if (w0 != nullptr) {
1145+
Double_t *w1 = new Double_t[n + 1];
1146+
SplitArray(w0, w1, first, last);
1147+
1148+
if (work0 != nullptr) {
1149+
Long64_t *wrk1 = new Long64_t[n + 1];
1150+
SplitArray(work0, wrk1, first, last);
1151+
result = sp->GetValue(n, a1, w1, wrk1);
1152+
delete[] wrk1;
1153+
} else {
1154+
result = sp->GetValue(n, a1, w1);
1155+
}
1156+
delete[] w1;
1157+
} else {
1158+
result = sp->GetValue(n, a1);
1159+
}
1160+
delete[] a1;
1161+
return result;
1162+
}
1163+
1164+
T *GetResult(Moving *sp)
1165+
{
1166+
Long64_t kl = k0 / 2;
1167+
Long64_t kr = (k0 % 2) ? k0 / 2 : k0 / 2 - 1;
1168+
T *mov = new T[n0 + 1];
1169+
1170+
for (int i = 0; i != n0; i++) {
1171+
kl = (i < k0 / 2 and i > 0) ? i : k0 / 2;
1172+
if (i + kr > n0 - 1) {
1173+
kr--;
1174+
}
1175+
1176+
if (i == 0) {
1177+
if (k0 > 2) {
1178+
mov[i] = sp->GetMoving(kr + 1, 0, kr + 1, sp);
1179+
} else {
1180+
mov[i] = sp->GetMoving(1, 0, 1, sp);
1181+
}
1182+
} else if (i == n0 - 1) {
1183+
mov[i] = sp->GetMoving(kl + 1, i - kl, i, sp);
1184+
} else {
1185+
mov[i] = sp->GetMoving(kl + kr + 1, i - kl, i + kr, sp);
1186+
}
1187+
}
1188+
return mov;
1189+
}
1190+
};
1191+
1192+
template <typename T>
1193+
class MovingMean : public Moving<T> {
1194+
public:
1195+
MovingMean(Long64_t n, T *a, Long64_t k, Double_t *w) : Moving<T>(n, a, k, w) {}
1196+
1197+
Double_t GetValue(Long64_t n, T *a, Double_t *w = nullptr, Long64_t *work = nullptr)
1198+
{
1199+
(void) work;
1200+
Double_t mean = TMath::Mean(n, a, w);
1201+
return mean;
1202+
}
1203+
};
1204+
1205+
template <typename T>
1206+
T *TMath::MovMean(Long64_t n, T *a, Long64_t k, Double_t *w)
1207+
{
1208+
if (n <= 2) {
1209+
Fatal("MovMean", "the length of the array must be >1");
1210+
}
1211+
if (k > n) {
1212+
Fatal("MovMean", "the window length k is larger than the length of the array");
1213+
}
1214+
if (k == 1) {
1215+
Fatal("MovMean", "the window length k must be >1");
1216+
}
1217+
1218+
MovingMean<T> *movmean = new MovingMean(n, a, k, w);
1219+
T *result = movmean->GetResult(movmean);
1220+
delete movmean;
1221+
return result;
1222+
}
1223+
1224+
////////////////////////////////////////////////////////////////////////////////
1225+
/// Returns the moving median of an array with a length n.
1226+
1227+
template <typename T>
1228+
class MovingMedian : public Moving<T> {
1229+
public:
1230+
MovingMedian(Long64_t n, T *a, Long64_t k, Double_t *w, Long64_t *work) : Moving<T>(n, a, k, w, work) {}
1231+
1232+
Double_t GetValue(Long64_t n, T *a, Double_t *w, Long64_t *work)
1233+
{
1234+
Double_t median = TMath::Median(n, a, w, work);
1235+
return median;
1236+
}
1237+
};
1238+
1239+
template <typename T>
1240+
T *TMath::MovMedian(Long64_t n, T *a, Long64_t k, Double_t *w, Long64_t *work)
1241+
{
1242+
if (n <= 2) {
1243+
Fatal("MovMedian", "the length of the array must be >1");
1244+
}
1245+
if (k > n) {
1246+
Fatal("MovMedian", "the window length k is larger than the length of the array");
1247+
}
1248+
if (k == 1) {
1249+
Fatal("MovMedian", "the window length k must be >1");
1250+
}
1251+
1252+
MovingMedian<T> *movmedian = new MovingMedian(n, a, k, w, work);
1253+
T *result = movmedian->GetResult(movmedian);
1254+
delete movmedian;
1255+
return result;
1256+
}
1257+
1258+
////////////////////////////////////////////////////////////////////////////////
1259+
/// Returns the mode of an array. If there are an equal amount of
1260+
/// different values, the smallest value will be returned.
1261+
1262+
template <typename T>
1263+
Double_t TMath::Mode(const Long64_t n, T *a)
1264+
{
1265+
int N1 = 0;
1266+
int N2 = 0;
1267+
Double_t mode = 0;
1268+
std::sort(a, a + n);
1269+
1270+
for (Long64_t i = 0; i < n; i++) {
1271+
N2 = std::count(a, a + n, a[i]);
1272+
if (N2 > N1 && mode != a[i]) {
1273+
mode = a[i];
1274+
}
1275+
N1 = N2;
1276+
}
1277+
return mode;
1278+
}
1279+
10981280
////////////////////////////////////////////////////////////////////////////////
10991281
/// Returns the geometric mean of an array defined by the iterators.
11001282
/// \f[ GeomMean = (\prod_{i=0}^{n-1} |a[i]|)^{1/n} \f]

math/mathcore/test/testTMath.cxx

+46
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,42 @@ void testNormCross()
3636
<< endl;
3737
}
3838

39+
template <typename T>
40+
void testMovingFunctions()
41+
{
42+
const Long64_t n = 10;
43+
const Long64_t k1 = 5;
44+
const Long64_t k2 = 6;
45+
T sa[n] = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20};
46+
47+
const T meanresulta[n] = {4, 5, 6, 7, 9, 11, 13, 15, 16, 17};
48+
const T medianresulta[n] = {4, 5, 6, 8, 10, 12, 14, 16, 17, 18};
49+
50+
Double_t w[n] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
51+
Long64_t work[n] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
52+
53+
T *movmediana = TMath::MovMedian(n, sa, k1, w, work);
54+
T *movmeana = TMath::MovMean(n, sa, k2, w);
55+
56+
// test results
57+
bool ok1 = true;
58+
bool ok2 = true;
59+
60+
for (Int_t i = 0; i < n && ok1 && ok2; i++) {
61+
ok1 &= (meanresulta[i] == movmeana[i]);
62+
63+
if (!ok1)
64+
Error("testMovingFunctions", "For MovMean, different values found at i = %d", i);
65+
66+
ok2 &= (medianresulta[i] == movmediana[i]);
67+
68+
if (!ok2)
69+
Error("testMovingFunctions", "For MovMedian, different values found at i = %d", i);
70+
}
71+
72+
delete[] movmediana;
73+
delete[] movmeana;
74+
}
3975

4076
template <typename T, typename U>
4177
void testArrayFunctions()
@@ -63,6 +99,7 @@ void testArrayFunctions()
6399
<< " RMS: " << RMS(n, sa)
64100
<< " Median: " << Median(n, sa)
65101
<< " KOrdStat(3): " << KOrdStat(n, sa, k)
102+
<< " Mode: " << Mode(n, sa)
66103
<< endl;
67104

68105
Sort(n, sa, index, kFALSE);
@@ -183,6 +220,15 @@ void testTMath()
183220
testIteratorFunctions<Long_t>();
184221
testIteratorFunctions<Long64_t>();
185222

223+
cout << "\nMoving functions tests: " << endl;
224+
225+
testMovingFunctions<Short_t>();
226+
testMovingFunctions<Int_t>();
227+
testMovingFunctions<Float_t>();
228+
testMovingFunctions<Double_t>();
229+
testMovingFunctions<Long_t>();
230+
testMovingFunctions<Long64_t>();
231+
186232
cout << "\nPoint functions tests: " << endl;
187233

188234
testPoints<Double_t>(1.3, 0.5);

0 commit comments

Comments
 (0)