@@ -22,7 +22,6 @@ import core.lifetime: move;
22
22
import mir.math.common: fmamath;
23
23
import mir.math.sum;
24
24
import mir.primitives;
25
- import std.range.primitives : isInputRange;
26
25
import std.traits : isArray, isFloatingPoint, isMutable, isIterable;
27
26
28
27
/+ +
@@ -73,7 +72,7 @@ struct MeanAccumulator(T, Summation summation)
73
72
version (mir_test)
74
73
@safe pure nothrow unittest
75
74
{
76
- import mir.ndslice.slice : sliced;
75
+ import mir.ndslice.slice: sliced;
77
76
78
77
MeanAccumulator! (double , Summation.pairwise) x;
79
78
x.put([0.0 , 1 , 2 , 3 , 4 ].sliced);
@@ -85,7 +84,7 @@ version(mir_test)
85
84
version (mir_test)
86
85
@safe pure nothrow unittest
87
86
{
88
- import mir.ndslice.slice : sliced;
87
+ import mir.ndslice.slice: sliced;
89
88
90
89
MeanAccumulator! (float , Summation.pairwise) x;
91
90
x.put([0 , 1 , 2 , 3 , 4 ].sliced);
@@ -106,10 +105,10 @@ template mean(F, Summation summation = Summation.appropriate)
106
105
Params:
107
106
r = range
108
107
+/
109
- F mean (Range )(Range r)
108
+ @fmamath F mean(Range )(Range r)
110
109
if (isIterable! Range )
111
110
{
112
- MeanAccumulator! (F, ResolveSummationType! (summation, Range , sumType ! Range )) mean;
111
+ MeanAccumulator! (F, ResolveSummationType! (summation, Range , F )) mean;
113
112
mean.put(r.move);
114
113
return mean.mean;
115
114
}
@@ -122,7 +121,7 @@ template mean(Summation summation = Summation.appropriate)
122
121
Params:
123
122
r = range
124
123
+/
125
- sumType! Range mean (Range )(Range r)
124
+ @fmamath sumType! Range mean(Range )(Range r)
126
125
if (isIterable! Range )
127
126
{
128
127
return .mean! (sumType! Range , summation)(r.move);
@@ -145,7 +144,7 @@ template mean(string summation)
145
144
version (mir_test)
146
145
@safe pure nothrow unittest
147
146
{
148
- import mir.ndslice.slice : sliced;
147
+ import mir.ndslice.slice: sliced;
149
148
150
149
assert (mean([1.0 , 2 , 3 ]) == 2 );
151
150
assert (mean([1.0 + 3i, 2 , 3 ]) == 2 + 1i);
@@ -160,7 +159,7 @@ version(mir_test)
160
159
@safe @nogc pure nothrow
161
160
unittest
162
161
{
163
- import mir.ndslice.slice : sliced;
162
+ import mir.ndslice.slice: sliced;
164
163
165
164
static immutable x = [0.0 , 1.0 , 1.5 , 2.0 , 3.5 , 4.25 ,
166
165
2.0 , 7.5 , 5.0 , 1.0 , 1.5 , 0.0 ];
@@ -172,7 +171,7 @@ version(mir_test)
172
171
@safe @nogc pure nothrow
173
172
unittest
174
173
{
175
- import mir.ndslice.slice : sliced;
174
+ import mir.ndslice.slice: sliced;
176
175
177
176
static immutable x = [0.0 , 1.0 , 1.5 , 2.0 , 3.5 , 4.25 ,
178
177
2.0 , 7.5 , 5.0 , 1.0 , 1.5 , 0.0 ];
@@ -184,8 +183,8 @@ version(mir_test)
184
183
@safe @nogc pure nothrow
185
184
unittest
186
185
{
187
- import mir.ndslice.slice : sliced;
188
- import mir.ndslice.topology : alongDim, byDim, map;
186
+ import mir.ndslice.slice: sliced;
187
+ import mir.ndslice.topology: alongDim, byDim, map;
189
188
190
189
static immutable x = [0.0 , 1.0 , 1.5 , 2.0 , 3.5 , 4.25 ,
191
190
2.0 , 7.5 , 5.0 , 1.0 , 1.5 , 0.0 ];
@@ -204,6 +203,7 @@ unittest
204
203
// / Can also set algorithm or output type
205
204
version (mir_test)
206
205
@safe @nogc pure nothrow
206
+
207
207
unittest
208
208
{
209
209
import mir.ndslice.slice: sliced;
@@ -231,8 +231,8 @@ version(mir_test)
231
231
@safe @nogc pure nothrow
232
232
unittest
233
233
{
234
- import mir.ndslice.slice : sliced;
235
- import std .math : approxEqual;
234
+ import mir.ndslice.slice: sliced;
235
+ import mir .math.common : approxEqual;
236
236
237
237
static immutable x = [0 , 1 , 1 , 2 , 4 , 4 ,
238
238
2 , 7 , 5 , 1 , 2 , 0 ];
@@ -244,7 +244,7 @@ version(mir_test)
244
244
@safe @nogc pure nothrow
245
245
unittest
246
246
{
247
- import mir.ndslice.slice : sliced;
247
+ import mir.ndslice.slice: sliced;
248
248
249
249
static immutable cdouble [] x = [1.0 + 2i, 2 + 3i, 3 + 4i, 4 + 5i];
250
250
static immutable cdouble result = 2.5 + 3. 5i;
@@ -256,7 +256,7 @@ version(mir_test)
256
256
@safe @nogc pure nothrow
257
257
unittest
258
258
{
259
- import mir.ndslice : alongDim, iota, as, map;
259
+ import mir.ndslice: alongDim, iota, as, map;
260
260
/*
261
261
[[0,1,2],
262
262
[3,4,5]]
@@ -280,8 +280,8 @@ version(mir_test)
280
280
@safe @nogc pure nothrow
281
281
unittest
282
282
{
283
- import mir.ndslice.slice : sliced;
284
- import mir.ndslice.topology : alongDim, byDim, map;
283
+ import mir.ndslice.slice: sliced;
284
+ import mir.ndslice.topology: alongDim, byDim, map;
285
285
286
286
static immutable x = [0.0 , 1.00 , 1.50 , 2.0 , 3.5 , 4.250 ,
287
287
2.0 , 7.50 , 5.00 , 1.0 , 1.5 , 0.000 ];
@@ -298,12 +298,133 @@ version(mir_test)
298
298
assert ([1.0 , 2 , 3 , 4 ].mean == 2.5 );
299
299
}
300
300
301
+ /+ +
302
+ Computes the harmonic mean of a range.
303
+
304
+ See_also: $(SUBREF sum, sum)
305
+ +/
306
+ template hmean (F, Summation summation = Summation.appropriate)
307
+ {
308
+ /+ +
309
+ Params:
310
+ r = range
311
+ Returns:
312
+ harmonic mean of the range
313
+ +/
314
+ @fmamath F hmean(Range )(Range r)
315
+ if (isIterable! Range )
316
+ {
317
+ import mir.ndslice.topology: map;
318
+ static if (summation == Summation.fast && __traits(compiles, r.move.map! " 1.0 / a" ))
319
+ {
320
+ return 1.0 / r.move.map! " 1.0 / a" .mean! (F, summation);
321
+ }
322
+ else
323
+ {
324
+ MeanAccumulator! (F, ResolveSummationType! (summation, Range , F)) imean;
325
+ foreach (e; r)
326
+ imean.put(1.0 / e);
327
+ return 1.0 / imean.mean;
328
+ }
329
+ }
330
+ }
331
+
332
+ // / ditto
333
+ template hmean (Summation summation = Summation.appropriate)
334
+ {
335
+ /+ +
336
+ Params:
337
+ r = range
338
+ Returns:
339
+ harmonic mean of the range
340
+ +/
341
+ @fmamath sumType! Range hmean(Range )(Range r)
342
+ if (isIterable! Range )
343
+ {
344
+ return .hmean! (typeof (1.0 / sumType! Range .init), summation)(r.move);
345
+ }
346
+ }
347
+
348
+ // / ditto
349
+ template hmean (F, string summation)
350
+ {
351
+ mixin (" alias hmean = .hmean!(F, Summation." ~ summation ~ " );" );
352
+ }
353
+
354
+ // / ditto
355
+ template hmean (string summation)
356
+ {
357
+ mixin (" alias hmean = .hmean!(Summation." ~ summation ~ " );" );
358
+ }
359
+
360
+ // / Harmonic mean of vector
361
+ pure @safe nothrow @nogc
362
+ unittest
363
+ {
364
+ import mir.math.common: approxEqual;
365
+
366
+ static immutable x = [20.0 , 100.0 , 2000.0 , 10.0 , 5.0 , 2.0 ];
367
+
368
+ assert (x.hmean.approxEqual(6.97269 ));
369
+ }
370
+
371
+ // / Harmonic mean of matrix
372
+ pure @safe
373
+ unittest
374
+ {
375
+ import mir.math.common: approxEqual;
376
+ import mir.ndslice.fuse: fuse;
377
+
378
+ auto x = [[20.0 , 100.0 , 2000.0 ], [10.0 , 5.0 , 2.0 ]].fuse;
379
+
380
+ assert (x.hmean.approxEqual(6.97269 ));
381
+ }
382
+
383
+ // / Column harmonic mean of matrix
384
+ pure @safe
385
+ unittest
386
+ {
387
+ import mir.algorithm.iteration: all;
388
+ import mir.math.common: approxEqual;
389
+ import mir.ndslice: fuse;
390
+ import mir.ndslice.topology: alongDim, byDim, map;
391
+
392
+ auto x = [
393
+ [20.0 , 100.0 , 2000.0 ],
394
+ [ 10.0 , 5.0 , 2.0 ]
395
+ ].fuse;
396
+
397
+ auto y = [13.33333 , 9.52381 , 3.996004 ];
398
+
399
+ // Use byDim or alongDim with map to compute mean of row/column.
400
+ assert (x.byDim! 1. map! hmean.all! approxEqual(y));
401
+ assert (x.alongDim! 0. map! hmean.all! approxEqual(y));
402
+ }
403
+
404
+ // / Can also pass arguments to hmean
405
+ pure @safe
406
+ unittest
407
+ {
408
+ import mir.ndslice.topology: map, repeat;
409
+ import mir.math.common: approxEqual;
410
+
411
+ // Set sum algorithm or output type
412
+ auto x = [1 , 1e-100 , 1 , - 1e-100 ];
413
+
414
+ assert (x.hmean! " kb2" .approxEqual(2 ));
415
+ assert (x.hmean! " precise" .approxEqual(2 ));
416
+
417
+ // Provide the summation type
418
+ assert (float .max.repeat(3 ).hmean! (double , " fast" ).approxEqual(float .max));
419
+ }
420
+
301
421
/+ +
302
422
A linear regression model with a single explanatory variable.
303
423
+/
304
424
template simpleLinearRegression (Summation summation = Summation.kbn)
305
425
{
306
426
import mir.ndslice.slice;
427
+ import std.range.primitives : isInputRange;
307
428
308
429
/+ +
309
430
Params:
@@ -323,7 +444,7 @@ template simpleLinearRegression(Summation summation = Summation.kbn)
323
444
do {
324
445
alias X = typeof (sumType! XRange.init * sumType! XRange.init);
325
446
alias Y = sumType! YRange;
326
- enum summationX = ! __traits(isIntegral, X) ? summation : Summation.naive;
447
+ enum summationX = ! __traits(isIntegral, X) ? summation: Summation.naive;
327
448
Summator! (X, summationX) xms = 0 ;
328
449
Summator! (Y, summation) yms = 0 ;
329
450
Summator! (X, summationX) xxms = 0 ;
0 commit comments