@@ -7,7 +7,7 @@ at expense of precision, one can use $(REF_ALTTEXT $(TT Summation.fast), Summati
7
7
8
8
License: $(LINK2 http://boost.org/LICENSE_1_0.txt, Boost License 1.0).
9
9
10
- Authors: Ilya Yaroshenko
10
+ Authors: Ilya Yaroshenko, John Michael Hall
11
11
12
12
Copyright: 2019 Symmetry Investments Group and Kaleidic Associates Advisory Limited.
13
13
@@ -23,41 +23,116 @@ import mir.math.common: fmamath;
23
23
import mir.math.sum;
24
24
import mir.primitives;
25
25
import std.range.primitives : isInputRange;
26
- import std.traits : isArray, isFloatingPoint;
26
+ import std.traits : isArray, isFloatingPoint, isMutable, isIterable ;
27
27
28
28
/+ +
29
- Computes the average of `r`, which must be a finite iterable.
30
-
31
- Returns:
32
- The average of all the elements in the range r.
29
+ Output range for mean.
33
30
+/
34
- template mean (Summation summation = Summation.appropriate)
31
+ struct MeanAccumulator (T, Summation summation)
32
+ if (isMutable! T)
35
33
{
36
34
// /
37
- @safe @fmamath sumType ! Range
38
- mean( Range )( Range r)
39
- if (hasLength ! Range
40
- || summation == Summation.appropriate
41
- || summation == Summation.fast
42
- || summation == Summation.naive)
35
+ size_t count;
36
+ // /
37
+ Summator ! (T, summation) sumAccumulator;
38
+
39
+ // /
40
+ F mean (F = T)() @property
43
41
{
44
- static if (hasLength! Range )
42
+ return cast (F) sumAccumulator.sum / cast (F) count;
43
+ }
44
+
45
+ // /
46
+ void put (Range )(Range r)
47
+ if (isIterable! Range )
48
+ {
49
+ static if (hasShape! Range )
45
50
{
46
- auto n = r.length ;
47
- return sum ! summation(r.move) / cast (sumType ! Range ) n ;
51
+ count + = r.elementCount ;
52
+ sumAccumulator.put(r) ;
48
53
}
49
54
else
50
55
{
51
- auto s = cast (typeof (return )) 0 ;
52
- size_t length;
53
- foreach (e; r)
56
+ foreach (x; r)
54
57
{
55
- length ++ ;
56
- s += e ;
58
+ count ++ ;
59
+ sumAccumulator.put(x) ;
57
60
}
58
- return s / cast (sumType! Range ) length;
59
61
}
60
62
}
63
+
64
+ // /
65
+ void put ()(T x)
66
+ {
67
+ count++ ;
68
+ sumAccumulator.put(x);
69
+ }
70
+ }
71
+
72
+ // /
73
+ version (mir_test)
74
+ @safe pure nothrow unittest
75
+ {
76
+ import mir.ndslice.slice : sliced;
77
+
78
+ MeanAccumulator! (double , Summation.pairwise) x;
79
+ x.put([0.0 , 1 , 2 , 3 , 4 ].sliced);
80
+ assert (x.mean == 2 );
81
+ x.put(5 );
82
+ assert (x.mean == 2.5 );
83
+ }
84
+
85
+ version (mir_test)
86
+ @safe pure nothrow unittest
87
+ {
88
+ import mir.ndslice.slice : sliced;
89
+
90
+ MeanAccumulator! (float , Summation.pairwise) x;
91
+ x.put([0 , 1 , 2 , 3 , 4 ].sliced);
92
+ assert (x.mean == 2 );
93
+ x.put(5 );
94
+ assert (x.mean == 2.5 );
95
+ }
96
+
97
+ /+ +
98
+ Computes the average of `r`, which must be a finite iterable.
99
+
100
+ Returns:
101
+ The average of all the elements in the range r.
102
+ +/
103
+ template mean (F, Summation summation = Summation.appropriate)
104
+ {
105
+ /+ +
106
+ Params:
107
+ r = range
108
+ +/
109
+ F mean (Range )(Range r)
110
+ if (isIterable! Range )
111
+ {
112
+ MeanAccumulator! (F, ResolveSummationType! (summation, Range , sumType! Range )) mean;
113
+ mean.put(r.move);
114
+ return mean.mean;
115
+ }
116
+ }
117
+
118
+ // / ditto
119
+ template mean (Summation summation = Summation.appropriate)
120
+ {
121
+ /+ +
122
+ Params:
123
+ r = range
124
+ +/
125
+ sumType! Range mean (Range )(Range r)
126
+ if (isIterable! Range )
127
+ {
128
+ return .mean! (sumType! Range , summation)(r.move);
129
+ }
130
+ }
131
+
132
+ // /ditto
133
+ template mean (F, string summation)
134
+ {
135
+ mixin (" alias mean = .mean!(F, Summation." ~ summation ~ " );" );
61
136
}
62
137
63
138
// /ditto
@@ -67,10 +142,23 @@ template mean(string summation)
67
142
}
68
143
69
144
// /
70
- version (mir_test) @safe pure nothrow unittest
145
+ version (mir_test)
146
+ @safe pure nothrow unittest
71
147
{
148
+ import mir.ndslice.slice : sliced;
149
+
72
150
assert (mean([1.0 , 2 , 3 ]) == 2 );
73
151
assert (mean([1.0 + 3i, 2 , 3 ]) == 2 + 1i);
152
+
153
+ assert (mean! float ([0 , 1 , 2 , 3 , 4 , 5 ].sliced(3 , 2 )) == 2.5 );
154
+
155
+ assert (is (typeof (mean! float ([1 , 2 , 3 ])) == float ));
156
+ }
157
+
158
+ version (mir_test)
159
+ @safe pure nothrow unittest
160
+ {
161
+ assert ([1.0 , 2 , 3 , 4 ].mean == 2.5 );
74
162
}
75
163
76
164
/+ +
@@ -157,7 +245,8 @@ template simpleLinearRegression(string summation)
157
245
}
158
246
159
247
// /
160
- version (mir_test) @safe pure nothrow @nogc unittest
248
+ version (mir_test)
249
+ @safe pure nothrow @nogc unittest
161
250
{
162
251
import mir.math.common: approxEqual;
163
252
static immutable x = [0 , 1 , 2 , 3 ];
0 commit comments