Report a bug
Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using a local clone.

# mir.math.stat

This module contains base statistical algorithms.
Note that used specialized summing algorithms execute more primitive operations than vanilla summation. Therefore, if in certain cases maximum speed is required at expense of precision, one can use Summation.fast .
Authors:
Shigeki Karita (original numir code), Ilya Yaroshenko, John Michael Hall
template `statType`(T, bool checkComplex = true)
template `meanType`(T)
struct `MeanAccumulator`(T, Summation summation);
Output range for mean.
Examples:
```import mir.ndslice.slice: sliced;

MeanAccumulator!(double, Summation.pairwise) x;
x.put([0.0, 1, 2, 3, 4].sliced);
assert(x.mean == 2);
x.put(5);
assert(x.mean == 2.5);
```
size_t `count`;
Summator!(T, summation) `summator`;
const pure nothrow @nogc @property @safe F `mean`(F = T)();
const pure nothrow @nogc @property @safe F `sum`(F = T)();
void `put`(Range)(Range `r`)
if (isIterable!Range);
void `put`()(T `x`);
void `put`(F = T)(MeanAccumulator!(F, summation) `m`);
template `mean`(F, Summation summation = Summation.appropriate)

template `mean`(Summation summation = Summation.appropriate)

template `mean`(F, string summation)

template `mean`(string summation)
Computes the mean of the input.
By default, if F is not floating point type or complex type, then the result will have a double type if F is implicitly convertible to a floating point type or a type for which isComplex!F is true.
Parameters:
 F controls type of output summation algorithm for calculating sums (default: Summation.appropriate)
Returns:
The mean of all the elements in the input, must be floating point or complex type
Examples:
```import mir.ndslice.slice: sliced;
import mir.complex;
alias C = Complex!double;

assert(mean([1.0, 2, 3]) == 2);
assert(mean([C(1, 3), C(2), C(3)]) == C(2, 1));

assert(mean!float([0, 1, 2, 3, 4, 5].sliced(3, 2)) == 2.5);

static assert(is(typeof(mean!float([1, 2, 3])) == float));
```
Examples:
Mean of vector
```import mir.ndslice.slice: sliced;

auto x = [0.0, 1.0, 1.5, 2.0, 3.5, 4.25,
2.0, 7.5, 5.0, 1.0, 1.5, 0.0].sliced;
assert(x.mean == 29.25 / 12);
```
Examples:
Mean of matrix
```import mir.ndslice.fuse: fuse;

auto x = [
[0.0, 1.0, 1.5, 2.0, 3.5, 4.25],
[2.0, 7.5, 5.0, 1.0, 1.5, 0.0]
].fuse;

assert(x.mean == 29.25 / 12);
```
Examples:
Column mean of matrix
```import mir.ndslice.fuse: fuse;
import mir.ndslice.topology: alongDim, byDim, map;
import mir.algorithm.iteration: all;
import mir.math.common: approxEqual;

auto x = [
[0.0, 1.0, 1.5, 2.0, 3.5, 4.25],
[2.0, 7.5, 5.0, 1.0, 1.5, 0.0]
].fuse;
auto result = [1, 4.25, 3.25, 1.5, 2.5, 2.125];

// Use byDim or alongDim with map to compute mean of row/column.
assert(x.byDim!1.map!mean.all!approxEqual(result));
assert(x.alongDim!0.map!mean.all!approxEqual(result));

// FIXME
// Without using map, computes the mean of the whole slice
// assert(x.byDim!1.mean == x.sliced.mean);
// assert(x.alongDim!0.mean == x.sliced.mean);
```
Examples:
Can also set algorithm or output type
```import mir.ndslice.slice: sliced;
import mir.ndslice.topology: repeat;

//Set sum algorithm or output type

auto a = [1, 1e100, 1, -1e100].sliced;

auto x = a * 10_000;

assert(x.mean!"kbn" == 20_000 / 4);
assert(x.mean!"kb2" == 20_000 / 4);
assert(x.mean!"precise" == 20_000 / 4);
assert(x.mean!(double, "precise") == 20_000.0 / 4);

auto y = uint.max.repeat(3);
assert(y.mean!ulong == 12884901885 / 3);
```
Examples:
For integral slices, pass output type as template parameter to ensure output type is correct.
```import mir.math.common: approxEqual;
import mir.ndslice.slice: sliced;

auto x = [0, 1, 1, 2, 4, 4,
2, 7, 5, 1, 2, 0].sliced;

auto y = x.mean;
assert(y.approxEqual(29.0 / 12, 1.0e-10));
static assert(is(typeof(y) == double));

assert(x.mean!float.approxEqual(29f / 12, 1.0e-10));
```
Examples:
Mean works for complex numbers and other user-defined types (provided they can be converted to a floating point or complex type)
```import mir.math.common: approxEqual;
import mir.ndslice.slice: sliced;
import mir.complex;
alias C = Complex!double;

auto x = [C(1.0, 2), C(2, 3), C(3, 4), C(4, 5)].sliced;
assert(x.mean.approxEqual(C(2.5, 3.5)));
```
Examples:
Compute mean tensors along specified dimention of tensors
```import mir.ndslice: alongDim, iota, as, map;
/++
[[0,1,2],
[3,4,5]]
+/
auto x = iota(2, 3).as!double;
assert(x.mean == (5.0 / 2.0));

auto m0 = [(0.0+3.0)/2.0, (1.0+4.0)/2.0, (2.0+5.0)/2.0];
assert(x.alongDim!0.map!mean == m0);
assert(x.alongDim!(-2).map!mean == m0);

auto m1 = [(0.0+1.0+2.0)/3.0, (3.0+4.0+5.0)/3.0];
assert(x.alongDim!1.map!mean == m1);
assert(x.alongDim!(-1).map!mean == m1);

assert(iota(2, 3, 4, 5).as!double.alongDim!0.map!mean == iota([3, 4, 5], 3 * 4 * 5 / 2));
```
Examples:
Arbitrary mean
```assert(mean(1.0, 2, 3) == 2);
assert(mean!float(1, 2, 3) == 2);
```
meanType!F `mean`(Range)(Range `r`)
if (isIterable!Range);
Parameters:
 Range `r` range, must be finite iterable
meanType!F `mean`(scope const F[] `ar`...);
Parameters:
 F[] `ar` values
template `hmeanType`(T)
template `hmean`(F, Summation summation = Summation.appropriate)

template `hmean`(Summation summation = Summation.appropriate)

template `hmean`(F, string summation)

template `hmean`(string summation)
Computes the harmonic mean of the input.
By default, if F is not floating point type or complex type, then the result will have a double type if F is implicitly convertible to a floating point type or a type for which isComplex!F is true.
Parameters:
 F controls type of output summation algorithm for calculating sums (default: Summation.appropriate)
Returns:
harmonic mean of all the elements of the input, must be floating point or complex type
Examples:
Harmonic mean of vector
```import mir.math.common: approxEqual;
import mir.ndslice.slice: sliced;

auto x = [20.0, 100.0, 2000.0, 10.0, 5.0, 2.0].sliced;

assert(x.hmean.approxEqual(6.97269));
```
Examples:
Harmonic mean of matrix
```import mir.math.common: approxEqual;
import mir.ndslice.fuse: fuse;

auto x = [
[20.0, 100.0, 2000.0],
[10.0, 5.0, 2.0]
].fuse;

assert(x.hmean.approxEqual(6.97269));
```
Examples:
Column harmonic mean of matrix
```import mir.algorithm.iteration: all;
import mir.math.common: approxEqual;
import mir.ndslice: fuse;
import mir.ndslice.topology: alongDim, byDim, map;

auto x = [
[20.0, 100.0, 2000.0],
[ 10.0, 5.0, 2.0]
].fuse;

auto y = [13.33333, 9.52381, 3.996004];

// Use byDim or alongDim with map to compute mean of row/column.
assert(x.byDim!1.map!hmean.all!approxEqual(y));
assert(x.alongDim!0.map!hmean.all!approxEqual(y));
```
Examples:
Can also pass arguments to hmean
```import mir.math.common: approxEqual;
import mir.ndslice.topology: repeat;
import mir.ndslice.slice: sliced;

//Set sum algorithm or output type
auto x = [1, 1e-100, 1, -1e-100].sliced;

assert(x.hmean!"kb2".approxEqual(2));
assert(x.hmean!"precise".approxEqual(2));
assert(x.hmean!(double, "precise").approxEqual(2));

//Provide the summation type
assert(float.max.repeat(3).hmean!double.approxEqual(float.max));
```
Examples:
For integral slices, pass output type as template parameter to ensure output type is correct.
```import mir.math.common: approxEqual;
import mir.ndslice.slice: sliced;

auto x = [20, 100, 2000, 10, 5, 2].sliced;

auto y = x.hmean;

assert(y.approxEqual(6.97269));
static assert(is(typeof(y) == double));

assert(x.hmean!float.approxEqual(6.97269));
```
Examples:
hmean works for complex numbers and other user-defined types (provided they can be converted to a floating point or complex type)
```import mir.math.common: approxEqual;
import mir.ndslice.slice: sliced;
import mir.complex;
alias C = Complex!double;

auto x = [C(1, 2), C(2, 3), C(3, 4), C(4, 5)].sliced;
assert(x.hmean.approxEqual(C(1.97110904, 3.14849332)));
```
Examples:
Arbitrary harmonic mean
```import mir.math.common: approxEqual;
import mir.ndslice.slice: sliced;

auto x = hmean(20.0, 100, 2000, 10, 5, 2);
assert(x.approxEqual(6.97269));

auto y = hmean!float(20, 100, 2000, 10, 5, 2);
assert(y.approxEqual(6.97269));
```
hmeanType!F `hmean`(Range)(Range `r`)
if (isIterable!Range);
Parameters:
 Range `r` range
hmeanType!F `hmean`(scope const F[] `ar`...);
Parameters:
 F[] `ar` values
struct `GMeanAccumulator`(T) if (isMutable!T && isFloatingPoint!T);
Output range for gmean.
Examples:
```import mir.math.common: approxEqual;
import mir.ndslice.slice: sliced;

GMeanAccumulator!double x;
x.put([1.0, 2, 3, 4].sliced);
assert(x.gmean.approxEqual(2.21336384));
x.put(5);
assert(x.gmean.approxEqual(2.60517108));
```
size_t `count`;
ProdAccumulator!T `prodAccumulator`;
@property F `gmean`(F = T)()
if (isFloatingPoint!F);
void `put`(Range)(Range `r`)
if (isIterable!Range);
void `put`()(T `x`);
template `gmeanType`(T)
gmeanType!F `gmean`(F, Range)(Range `r`)
if (isFloatingPoint!F && isIterable!Range);

gmeanType!Range `gmean`(Range)(Range `r`)
if (isIterable!Range);
Computes the geometric average of the input.
By default, if F is not floating point type, then the result will have a double type if F is implicitly convertible to a floating point type.
Parameters:
 Range `r` range, must be finite iterable
Returns:
The geometric average of all the elements in the input, must be floating point type
gmeanType!F `gmean`(F)(scope const F[] `ar`...)
if (isFloatingPoint!F);
Parameters:
 F[] `ar` values
Examples:
```import mir.math.common: approxEqual;
import mir.ndslice.slice: sliced;

assert(gmean([1.0, 2, 3]).approxEqual(1.81712059));

assert(gmean!float([1, 2, 3, 4, 5, 6].sliced(3, 2)).approxEqual(2.99379516));

static assert(is(typeof(gmean!float([1, 2, 3])) == float));
```
Examples:
Geometric mean of vector
```import mir.math.common: approxEqual;
import mir.ndslice.slice: sliced;

auto x = [3.0, 1.0, 1.5, 2.0, 3.5, 4.25,
2.0, 7.5, 5.0, 1.0, 1.5, 2.0].sliced;

assert(x.gmean.approxEqual(2.36178395));
```
Examples:
Geometric mean of matrix
```import mir.math.common: approxEqual;
import mir.ndslice.fuse: fuse;

auto x = [
[3.0, 1.0, 1.5, 2.0, 3.5, 4.25],
[2.0, 7.5, 5.0, 1.0, 1.5, 2.0]
].fuse;

assert(x.gmean.approxEqual(2.36178395));
```
Examples:
Column gmean of matrix
```import mir.algorithm.iteration: all;
import mir.math.common: approxEqual;
import mir.ndslice.fuse: fuse;
import mir.ndslice.topology: alongDim, byDim, map;

auto x = [
[3.0, 1.0, 1.5, 2.0, 3.5, 4.25],
[2.0, 7.5, 5.0, 1.0, 1.5, 2.0]
].fuse;
auto result = [2.44948974, 2.73861278, 2.73861278, 1.41421356, 2.29128784, 2.91547594];

// Use byDim or alongDim with map to compute mean of row/column.
assert(x.byDim!1.map!gmean.all!approxEqual(result));
assert(x.alongDim!0.map!gmean.all!approxEqual(result));

// FIXME
// Without using map, computes the mean of the whole slice
// assert(x.byDim!1.gmean.all!approxEqual(result));
// assert(x.alongDim!0.gmean.all!approxEqual(result));
```
Examples:
Can also set output type
```import mir.math.common: approxEqual;
import mir.ndslice.slice: sliced;
import mir.ndslice.topology: repeat;

auto x = [5120.0, 7340032, 32, 3758096384].sliced;

assert(x.gmean!float.approxEqual(259281.45295212));

auto y = uint.max.repeat(2);
assert(y.gmean!float.approxEqual(cast(float) uint.max));
```
Examples:
For integral slices, pass output type as template parameter to ensure output type is correct.
```import mir.math.common: approxEqual;
import mir.ndslice.slice: sliced;

auto x = [5, 1, 1, 2, 4, 4,
2, 7, 5, 1, 2, 10].sliced;

auto y = x.gmean;
static assert(is(typeof(y) == double));

assert(x.gmean!float.approxEqual(2.79160522));
```
Examples:
gean works for user-defined types, provided the nth root can be taken for them
```static struct Foo {
float x;
alias x this;
}

import mir.math.common: approxEqual;
import mir.ndslice.slice: sliced;

auto x = [Foo(1.0), Foo(2.0), Foo(3.0)].sliced;
assert(x.gmean.approxEqual(1.81712059));
```
Examples:
Compute gmean tensors along specified dimention of tensors
```import mir.algorithm.iteration: all;
import mir.math.common: approxEqual;
import mir.ndslice.fuse: fuse;
import mir.ndslice.topology: alongDim, iota, map;

auto x = [
[1.0, 2, 3],
[4.0, 5, 6]
].fuse;

assert(x.gmean.approxEqual(2.99379516));

auto result0 = [2.0, 3.16227766, 4.24264069];
assert(x.alongDim!0.map!gmean.all!approxEqual(result0));
assert(x.alongDim!(-2).map!gmean.all!approxEqual(result0));

auto result1 = [1.81712059, 4.93242414];
assert(x.alongDim!1.map!gmean.all!approxEqual(result1));
assert(x.alongDim!(-1).map!gmean.all!approxEqual(result1));

auto y = [
[
[1.0, 2, 3],
[4.0, 5, 6]
], [
[7.0, 8, 9],
[10.0, 9, 10]
]
].fuse;

auto result3 = [
[2.64575131, 4.0,        5.19615242],
[6.32455532, 6.70820393, 7.74596669]
];
assert(y.alongDim!0.map!gmean.all!approxEqual(result3));
```
Examples:
Arbitrary gmean
```import mir.math.common: approxEqual;

assert(gmean(1.0, 2, 3).approxEqual(1.81712059));
assert(gmean!float(1, 2, 3).approxEqual(1.81712059));
```
template `median`(F, bool allowModify = false)

template `median`(bool allowModify = false)
Computes the median of slice.
By default, if F is not floating point type or complex type, then the result will have a double type if F is implicitly convertible to a floating point type or a type for which isComplex!F is true.
Can also pass a boolean variable, allowModify, that allows the input slice to be modified. By default, a reference-counted copy is made.
Parameters:
 F output type allowModify Allows the input slice to be modified, default is false
Returns:
the median of the slice
@nogc meanType!F `median`(Iterator, size_t N, SliceKind kind)(Slice!(Iterator, N, kind) `slice`);
Parameters:
 Slice!(Iterator, N, kind) `slice` slice
meanType!(T[]) `median`(T)(scope const T[] `ar`...);
Parameters:
 T[] `ar` array
auto `median`(T)(T `withAsSlice`)
if (hasAsSlice!T);
Parameters:
 T `withAsSlice` input that satisfies hasAsSlice
Examples:
Median of vector
```import mir.ndslice.slice: sliced;

auto x0 = [9.0, 1, 0, 2, 3, 4, 6, 8, 7, 10, 5].sliced;
assert(x0.median == 5);

auto x1 = [9.0, 1, 0, 2, 3, 4, 6, 8, 7, 10].sliced;
assert(x1.median == 5);
```
Examples:
Median of dynamic array
```auto x0 = [9.0, 1, 0, 2, 3, 4, 6, 8, 7, 10, 5];
assert(x0.median == 5);

auto x1 = [9.0, 1, 0, 2, 3, 4, 6, 8, 7, 10];
assert(x1.median == 5);
```
Examples:
Median of matrix
```import mir.ndslice.fuse: fuse;

auto x0 = [
[9.0, 1, 0, 2,  3],
[4.0, 6, 8, 7, 10]
].fuse;

assert(x0.median == 5);
```
Examples:
Row median of matrix
```import mir.algorithm.iteration: all;
import mir.math.common: approxEqual;
import mir.ndslice.fuse: fuse;
import mir.ndslice.slice: sliced;
import mir.ndslice.topology: alongDim, byDim, map;

auto x = [
[0.0, 1.0, 1.5, 2.0, 3.5, 4.25],
[2.0, 7.5, 5.0, 1.0, 1.5, 0.0]
].fuse;

auto result = [1.75, 1.75].sliced;

// Use byDim or alongDim with map to compute median of row/column.
assert(x.byDim!0.map!median.all!approxEqual(result));
assert(x.alongDim!1.map!median.all!approxEqual(result));
```
Examples:
Can allow original slice to be modified or set output type
```import mir.ndslice.slice: sliced;

auto x0 = [9.0, 1, 0, 2, 3, 4, 6, 8, 7, 10, 5].sliced;
assert(x0.median!true == 5);

auto x1 = [9, 1, 0, 2, 3, 4, 6, 8, 7, 10].sliced;
assert(x1.median!(float, true) == 5);
```
Examples:
Arbitrary median
```assert(median(0, 1, 2, 3, 4) == 2);
```
Examples:
For integral slices, can pass output type as template parameter to ensure output type is correct
```import mir.ndslice.slice: sliced;

auto x = [9, 1, 0, 2, 3, 4, 6, 8, 7, 10].sliced;
assert(x.median!float == 5f);

auto y = x.median;
assert(y == 5.0);
static assert(is(typeof(y) == double));
```
template `center`(alias centralTendency = mean!(Summation.appropriate))
Centers slice, which must be a finite iterable.
By default, slice is centered by the mean. A custom function may also be provided using centralTendency.
Returns:
The elements in the slice with the average subtracted from them.
Examples:
Center vector
```import mir.algorithm.iteration: all;
import mir.math.common: approxEqual;
import mir.ndslice.slice: sliced;

auto x = [1.0, 2, 3, 4, 5, 6].sliced;
assert(x.center.all!approxEqual([-2.5, -1.5, -0.5, 0.5, 1.5, 2.5]));

// Can center using different functions
assert(x.center!hmean.all!approxEqual([-1.44898, -0.44898, 0.55102, 1.55102, 2.55102, 3.55102]));
assert(x.center!gmean.all!approxEqual([-1.99379516, -0.99379516, 0.00620483, 1.00620483, 2.00620483, 3.00620483]));
assert(x.center!median.all!approxEqual([-2.5, -1.5, -0.5, 0.5, 1.5, 2.5]));
```
Examples:
Center dynamic array
```import mir.algorithm.iteration: all;
import mir.math.common: approxEqual;

auto x = [1.0, 2, 3, 4, 5, 6];
assert(x.center.all!approxEqual([-2.5, -1.5, -0.5, 0.5, 1.5, 2.5]));
```
Examples:
Center matrix
```import mir.algorithm.iteration: all;
import mir.math.common: approxEqual;
import mir.ndslice: fuse;

auto x = [
[0.0, 1, 2],
[3.0, 4, 5]
].fuse;

auto y = [
[-2.5, -1.5, -0.5],
[ 0.5,  1.5,  2.5]
].fuse;

assert(x.center.all!approxEqual(y));
```
Examples:
Column center matrix
```import mir.algorithm.iteration: all, equal;
import mir.math.common: approxEqual;
import mir.ndslice: fuse;
import mir.ndslice.topology: alongDim, byDim, map;

auto x = [
[20.0, 100.0, 2000.0],
[10.0,   5.0,    2.0]
].fuse;

auto result = [
[ 5.0,  47.5,  999],
[-5.0, -47.5, -999]
].fuse;

// Use byDim with map to compute average of row/column.
auto xCenterByDim = x.byDim!1.map!center;
auto resultByDim = result.byDim!1;
assert(xCenterByDim.equal!(equal!approxEqual)(resultByDim));

auto xCenterAlongDim = x.alongDim!0.map!center;
auto resultAlongDim = result.alongDim!0;
assert(xCenterByDim.equal!(equal!approxEqual)(resultAlongDim));
```
Examples:
Can also pass arguments to average function used by center
```import mir.ndslice.slice: sliced;

//Set sum algorithm or output type
auto a = [1, 1e100, 1, -1e100];

auto x = a.sliced * 10_000;

//Due to Floating Point precision, subtracting the mean from the second
//and fourth numbers in `x` does not change the value of the result
auto result = [5000, 1e104, 5000, -1e104].sliced;

assert(x.center!(mean!"kbn") == result);
assert(x.center!(mean!"kb2") == result);
assert(x.center!(mean!"precise") == result);
```
Examples:
Passing a centered input to variance or standardDeviation with the assumeZeroMean algorithm is equivalent to calculating variance or standardDeviation on the original input.
```import mir.algorithm.iteration: all;
import mir.math.common: approxEqual;
import mir.ndslice.slice: sliced;

auto x = [1.0, 2, 3, 4, 5, 6].sliced;
assert(x.center.variance!"assumeZeroMean".approxEqual(x.variance));
assert(x.center.standardDeviation!"assumeZeroMean".approxEqual(x.standardDeviation));
```
auto `center`(Iterator, size_t N, SliceKind kind)(Slice!(Iterator, N, kind) `slice`);

auto `center`(T)(T[] `array`);

auto `center`(T)(T `withAsSlice`)
if (hasAsSlice!T);
Parameters:
 Slice!(Iterator, N, kind) `slice` slice
struct `MapSummator`(alias fun, T, Summation summation) if (isMutable!T);
Output range that applies function fun to each input before summing
Examples:
```import mir.math.common: powi;
import mir.ndslice.slice: sliced;

alias f = (double x) => (powi(x, 2));
MapSummator!(f, double, Summation.pairwise) x;
x.put([0.0, 1, 2, 3, 4].sliced);
assert(x.sum == 30.0);
x.put(5);
assert(x.sum == 55.0);
```
Summator!(T, summation) `summator`;
@property F `sum`(F = T)();
void `put`(Range)(Range `r`)
if (isIterable!Range);
void `put`()(T `x`);
enum `VarianceAlgo`: int;
Variance algorithms.
`online`
Performs Welford's online algorithm for updating variance. Can also put another VarianceAccumulator of the same type, which uses the parallel algorithm from Chan et al., described above.
`naive`
Calculates variance using E(x^^2) - E(x)^2 (alowing for adjustments for population/sample variance). This algorithm can be numerically unstable.
`twoPass`
Calculates variance using a two-pass algorithm whereby the input is first centered and then the sum of squares is calculated from that.
`assumeZeroMean`
Calculates variance assuming the mean of the dataseries is zero.
struct `VarianceAccumulator`(T, VarianceAlgo varianceAlgo, Summation summation) if (isMutable!T && (varianceAlgo == VarianceAlgo.naive));
Examples:
```import mir.math.common: approxEqual;
import mir.ndslice.slice: sliced;

auto x = [0.0, 1.0, 1.5, 2.0, 3.5, 4.25,
2.0, 7.5, 5.0, 1.0, 1.5, 0.0].sliced;

enum PopulationTrueCT = true;
enum PopulationFalseCT = false;
bool PopulationTrueRT = true;
bool PopulationFalseRT = false;

VarianceAccumulator!(double, VarianceAlgo.naive, Summation.naive) v;
v.put(x);
assert(v.variance(PopulationTrueRT).approxEqual(54.76562 / 12));
assert(v.variance(PopulationTrueCT).approxEqual(54.76562 / 12));
assert(v.variance(PopulationFalseRT).approxEqual(54.76562 / 11));
assert(v.variance(PopulationFalseCT).approxEqual(54.76562 / 11));

v.put(4.0);
assert(v.variance(PopulationTrueRT).approxEqual(57.01923 / 13));
assert(v.variance(PopulationTrueCT).approxEqual(57.01923 / 13));
assert(v.variance(PopulationFalseRT).approxEqual(57.01923 / 12));
assert(v.variance(PopulationFalseCT).approxEqual(57.01923 / 12));
```
this(Range)(Range `r`)
if (isIterable!Range);
this()(T `x`);
MeanAccumulator!(T, summation) `meanAccumulator`;
@property size_t `count`();
@property F `mean`(F = T)();
Summator!(T, summation) `sumOfSquares`;
void `put`(Range)(Range `r`)
if (isIterable!Range);
void `put`()(T `x`);
@property F `variance`(F = T)(bool `isPopulation`);
struct `VarianceAccumulator`(T, VarianceAlgo varianceAlgo, Summation summation) if (isMutable!T && (varianceAlgo == VarianceAlgo.online));
Examples:
```import mir.math.common: approxEqual;
import mir.ndslice.slice: sliced;

auto x = [0.0, 1.0, 1.5, 2.0, 3.5, 4.25,
2.0, 7.5, 5.0, 1.0, 1.5, 0.0].sliced;

enum PopulationTrueCT = true;
enum PopulationFalseCT = false;
bool PopulationTrueRT = true;
bool PopulationFalseRT = false;

VarianceAccumulator!(double, VarianceAlgo.online, Summation.naive) v;
v.put(x);

assert(v.variance(PopulationTrueRT).approxEqual(54.76562 / 12));
assert(v.variance(PopulationTrueCT).approxEqual(54.76562 / 12));
assert(v.variance(PopulationFalseRT).approxEqual(54.76562 / 11));
assert(v.variance(PopulationFalseCT).approxEqual(54.76562 / 11));

v.put(4.0);
assert(v.variance(PopulationTrueRT).approxEqual(57.01923 / 13));
assert(v.variance(PopulationTrueCT).approxEqual(57.01923 / 13));
assert(v.variance(PopulationFalseRT).approxEqual(57.01923 / 12));
assert(v.variance(PopulationFalseCT).approxEqual(57.01923 / 12));
```
Examples:
```import mir.math.common: approxEqual;
import mir.ndslice.slice: sliced;

auto x = [0.0, 1.0, 1.5, 2.0, 3.5, 4.25].sliced;
auto y = [2.0, 7.5, 5.0, 1.0, 1.5, 0.0].sliced;

enum PopulationTrueCT = true;
enum PopulationFalseCT = false;
bool PopulationTrueRT = true;
bool PopulationFalseRT = false;

VarianceAccumulator!(double, VarianceAlgo.online, Summation.naive) v;
v.put(x);
assert(v.variance(PopulationTrueRT).approxEqual(12.55208 / 6));
assert(v.variance(PopulationTrueCT).approxEqual(12.55208 / 6));
assert(v.variance(PopulationFalseRT).approxEqual(12.55208 / 5));
assert(v.variance(PopulationFalseCT).approxEqual(12.55208 / 5));

v.put(y);
assert(v.variance(PopulationTrueRT).approxEqual(54.76562 / 12));
assert(v.variance(PopulationTrueCT).approxEqual(54.76562 / 12));
assert(v.variance(PopulationFalseRT).approxEqual(54.76562 / 11));
assert(v.variance(PopulationFalseCT).approxEqual(54.76562 / 11));
```
this(Range)(Range `r`)
if (isIterable!Range);
this()(T `x`);
MeanAccumulator!(T, summation) `meanAccumulator`;
@property size_t `count`();
@property F `mean`(F = T)();
Summator!(T, summation) `centeredSumOfSquares`;
void `put`(Range)(Range `r`)
if (isIterable!Range);
void `put`()(T `x`);
void `put`()(VarianceAccumulator!(T, varianceAlgo, summation) `v`);
@property F `variance`(F = T)(bool `isPopulation`);
struct `VarianceAccumulator`(T, VarianceAlgo varianceAlgo, Summation summation) if (isMutable!T && (varianceAlgo == VarianceAlgo.twoPass));
Examples:
```import mir.math.common: approxEqual;
import mir.ndslice.slice: sliced;

auto x = [0.0, 1.0, 1.5, 2.0, 3.5, 4.25,
2.0, 7.5, 5.0, 1.0, 1.5, 0.0].sliced;

enum PopulationTrueCT = true;
enum PopulationFalseCT = false;
bool PopulationTrueRT = true;
bool PopulationFalseRT = false;

auto v = VarianceAccumulator!(double, VarianceAlgo.twoPass, Summation.naive)(x);
assert(v.variance(PopulationTrueRT).approxEqual(54.76562 / 12));
assert(v.variance(PopulationTrueCT).approxEqual(54.76562 / 12));
assert(v.variance(PopulationFalseRT).approxEqual(54.76562 / 11));
assert(v.variance(PopulationFalseCT).approxEqual(54.76562 / 11));
```
MeanAccumulator!(T, summation) `meanAccumulator`;
@property size_t `count`();
@property F `mean`(F = T)();
Summator!(T, summation) `centeredSumOfSquares`;
this(Iterator, size_t N, SliceKind kind)(Slice!(Iterator, N, kind) `slice`);
this(U)(U[] `array`);
this(T)(T `withAsSlice`)
if (hasAsSlice!T);
this()(T `x`);
@property F `variance`(F = T)(bool `isPopulation`);
struct `VarianceAccumulator`(T, VarianceAlgo varianceAlgo, Summation summation) if (isMutable!T && (varianceAlgo == VarianceAlgo.assumeZeroMean));
Examples:
```import mir.math.common: approxEqual;
import mir.ndslice.slice: sliced;

auto a = [0.0, 1.0, 1.5, 2.0, 3.5, 4.25,
2.0, 7.5, 5.0, 1.0, 1.5, 0.0].sliced;
auto x = a.center;

enum PopulationTrueCT = true;
enum PopulationFalseCT = false;
bool PopulationTrueRT = true;
bool PopulationFalseRT = false;

VarianceAccumulator!(double, VarianceAlgo.assumeZeroMean, Summation.naive) v;
v.put(x);

assert(v.variance(PopulationTrueRT).approxEqual(54.76562 / 12));
assert(v.variance(PopulationTrueCT).approxEqual(54.76562 / 12));
assert(v.variance(PopulationFalseRT).approxEqual(54.76562 / 11));
assert(v.variance(PopulationFalseCT).approxEqual(54.76562 / 11));

v.put(4.0);
assert(v.variance(PopulationTrueRT).approxEqual(70.76562 / 13));
assert(v.variance(PopulationTrueCT).approxEqual(70.76562 / 13));
assert(v.variance(PopulationFalseRT).approxEqual(70.76562 / 12));
assert(v.variance(PopulationFalseCT).approxEqual(70.76562 / 12));
```
Examples:
```import mir.math.common: approxEqual;
import mir.ndslice.slice: sliced;

auto a = [0.0, 1.0, 1.5, 2.0, 3.5, 4.25,
2.0, 7.5, 5.0, 1.0, 1.5, 0.0].sliced;
auto b = a.center;
auto x = b[0 .. 6];
auto y = b[6 .. \$];

enum PopulationTrueCT = true;
enum PopulationFalseCT = false;
bool PopulationTrueRT = true;
bool PopulationFalseRT = false;

VarianceAccumulator!(double, VarianceAlgo.assumeZeroMean, Summation.naive) v;
v.put(x);
assert(v.variance(PopulationTrueRT).approxEqual(13.492188 / 6));
assert(v.variance(PopulationTrueCT).approxEqual(13.492188 / 6));
assert(v.variance(PopulationFalseRT).approxEqual(13.492188 / 5));
assert(v.variance(PopulationFalseCT).approxEqual(13.492188 / 5));

v.put(y);
assert(v.variance(PopulationTrueRT).approxEqual(54.76562 / 12));
assert(v.variance(PopulationTrueCT).approxEqual(54.76562 / 12));
assert(v.variance(PopulationFalseRT).approxEqual(54.76562 / 11));
assert(v.variance(PopulationFalseCT).approxEqual(54.76562 / 11));
```
@property size_t `count`();
@property F `mean`(F = T)();
Summator!(T, summation) `centeredSumOfSquares`;
this(Range)(Range `r`)
if (isIterable!Range);
this()(T `x`);
void `put`(Range)(Range `r`)
if (isIterable!Range);
void `put`()(T `x`);
void `put`()(VarianceAccumulator!(T, varianceAlgo, summation) `v`);
@property F `variance`(F = T)(bool `isPopulation`);
template `variance`(F, VarianceAlgo varianceAlgo = VarianceAlgo.online, Summation summation = Summation.appropriate)

template `variance`(VarianceAlgo varianceAlgo = VarianceAlgo.online, Summation summation = Summation.appropriate)

template `variance`(F, string varianceAlgo, string summation = "appropriate")

template `variance`(string varianceAlgo, string summation = "appropriate")
Calculates the variance of the input
By default, if F is not floating point type or complex type, then the result will have a double type if F is implicitly convertible to a floating point type or a type for which isComplex!F is true.
Parameters:
 F controls type of output varianceAlgo algorithm for calculating variance (default: VarianceAlgo.online) summation algorithm for calculating sums (default: Summation.appropriate)
Returns:
The variance of the input, must be floating point or complex type
Examples:
```import mir.math.common: approxEqual;
import mir.ndslice.slice: sliced;
import mir.complex;
alias C = Complex!double;

assert(variance([1.0, 2, 3]).approxEqual(2.0 / 2));
assert(variance([1.0, 2, 3], true).approxEqual(2.0 / 3));

assert(variance([C(1, 3), C(2), C(3)]).approxEqual(C(-4, -6) / 2));

assert(variance!float([0, 1, 2, 3, 4, 5].sliced(3, 2)).approxEqual(17.5 / 5));

static assert(is(typeof(variance!float([1, 2, 3])) == float));
```
Examples:
Variance of vector
```import mir.math.common: approxEqual;
import mir.ndslice.slice: sliced;

auto x = [0.0, 1.0, 1.5, 2.0, 3.5, 4.25,
2.0, 7.5, 5.0, 1.0, 1.5, 0.0].sliced;

assert(x.variance.approxEqual(54.76562 / 11));
```
Examples:
Variance of matrix
```import mir.math.common: approxEqual;
import mir.ndslice.fuse: fuse;

auto x = [
[0.0, 1.0, 1.5, 2.0, 3.5, 4.25],
[2.0, 7.5, 5.0, 1.0, 1.5, 0.0]
].fuse;

assert(x.variance.approxEqual(54.76562 / 11));
```
Examples:
Column variance of matrix
```import mir.algorithm.iteration: all;
import mir.math.common: approxEqual;
import mir.ndslice.fuse: fuse;
import mir.ndslice.topology: alongDim, byDim, map;

auto x = [
[0.0,  1.0, 1.5, 2.0],
[3.5, 4.25, 2.0, 7.5],
[5.0,  1.0, 1.5, 0.0]
].fuse;
auto result = [13.16667 / 2, 7.041667 / 2, 0.1666667 / 2, 30.16667 / 2];

// Use byDim or alongDim with map to compute variance of row/column.
assert(x.byDim!1.map!variance.all!approxEqual(result));
assert(x.alongDim!0.map!variance.all!approxEqual(result));

// FIXME
// Without using map, computes the variance of the whole slice
// assert(x.byDim!1.variance == x.sliced.variance);
// assert(x.alongDim!0.variance == x.sliced.variance);
```
Examples:
Can also set algorithm type
```import mir.math.common: approxEqual;
import mir.ndslice.slice: sliced;

auto a = [0.0, 1.0, 1.5, 2.0, 3.5, 4.25,
2.0, 7.5, 5.0, 1.0, 1.5, 0.0].sliced;

auto x = a + 1_000_000_000;

auto y = x.variance;
assert(y.approxEqual(54.76562 / 11));

// The naive algorithm is numerically unstable in this case
auto z0 = x.variance!"naive";
assert(!z0.approxEqual(y));

// But the two-pass algorithm provides a consistent answer
auto z1 = x.variance!"twoPass";
assert(z1.approxEqual(y));

// And the assumeZeroMean algorithm is way off
auto z2 = x.variance!"assumeZeroMean";
assert(z2.approxEqual(1.2e19 / 11));
```
Examples:
Can also set algorithm or output type
```import mir.math.common: approxEqual;
import mir.ndslice.slice: sliced;
import mir.ndslice.topology: repeat;

//Set population variance, variance algorithm, sum algorithm or output type

auto a = [1.0, 1e100, 1, -1e100].sliced;
auto x = a * 10_000;

bool populationTrueRT = true;
bool populationFalseRT = false;
enum PopulationTrueCT = true;

/++
Due to Floating Point precision, when centering `x`, subtracting the mean
from the second and fourth numbers has no effect. Further, after centering
and squaring `x`, the first and third numbers in the slice have precision
too low to be included in the centered sum of squares.
+/
assert(x.variance(populationFalseRT).approxEqual(2.0e208 / 3));
assert(x.variance(populationTrueRT).approxEqual(2.0e208 / 4));
assert(x.variance(PopulationTrueCT).approxEqual(2.0e208 / 4));

assert(x.variance!("online").approxEqual(2.0e208 / 3));
assert(x.variance!("online", "kbn").approxEqual(2.0e208 / 3));
assert(x.variance!("online", "kb2").approxEqual(2.0e208 / 3));
assert(x.variance!("online", "precise").approxEqual(2.0e208 / 3));
assert(x.variance!(double, "online", "precise").approxEqual(2.0e208 / 3));
assert(x.variance!(double, "online", "precise")(populationTrueRT).approxEqual(2.0e208 / 4));

auto y = uint.max.repeat(3);
auto z = y.variance!ulong;
assert(z == 0.0);
static assert(is(typeof(z) == double));
```
Examples:
For integral slices, pass output type as template parameter to ensure output type is correct.
```import mir.math.common: approxEqual;
import mir.ndslice.slice: sliced;

auto x = [0, 1, 1, 2, 4, 4,
2, 7, 5, 1, 2, 0].sliced;

auto y = x.variance;
assert(y.approxEqual(50.91667 / 11));
static assert(is(typeof(y) == double));

assert(x.variance!float.approxEqual(50.91667 / 11));
```
Examples:
Variance works for complex numbers and other user-defined types (provided they can be converted to a floating point or complex type)
```import mir.math.common: approxEqual;
import mir.ndslice.slice: sliced;
import mir.complex;
alias C = Complex!double;

auto x = [C(1, 2), C(2, 3), C(3, 4), C(4, 5)].sliced;
assert(x.variance.approxEqual((C(0, 10)) / 3));
```
Examples:
Compute variance along specified dimention of tensors
```import mir.algorithm.iteration: all;
import mir.math.common: approxEqual;
import mir.ndslice.fuse: fuse;
import mir.ndslice.topology: as, iota, alongDim, map, repeat;

auto x = [
[0.0, 1, 2],
[3.0, 4, 5]
].fuse;

assert(x.variance.approxEqual(17.5 / 5));

auto m0 = [4.5, 4.5, 4.5];
assert(x.alongDim!0.map!variance.all!approxEqual(m0));
assert(x.alongDim!(-2).map!variance.all!approxEqual(m0));

auto m1 = [1.0, 1.0];
assert(x.alongDim!1.map!variance.all!approxEqual(m1));
assert(x.alongDim!(-1).map!variance.all!approxEqual(m1));

assert(iota(2, 3, 4, 5).as!double.alongDim!0.map!variance.all!approxEqual(repeat(3600.0 / 2, 3, 4, 5)));
```
Examples:
Arbitrary variance
```assert(variance(1.0, 2, 3) == 1.0);
assert(variance!float(1, 2, 3) == 1f);
```
meanType!F `variance`(Range)(Range `r`, bool `isPopulation` = false)
if (isIterable!Range);
Parameters:
 Range `r` range, must be finite iterable bool `isPopulation` true if population variance, false if sample variance (default)
meanType!F `variance`(scope const F[] `ar`...);
Parameters:
 F[] `ar` values
template `stdevType`(T)
template `standardDeviation`(F, VarianceAlgo varianceAlgo = VarianceAlgo.online, Summation summation = Summation.appropriate)

template `standardDeviation`(VarianceAlgo varianceAlgo = VarianceAlgo.online, Summation summation = Summation.appropriate)

template `standardDeviation`(F, string varianceAlgo, string summation = "appropriate")

template `standardDeviation`(string varianceAlgo, string summation = "appropriate")
Calculates the standard deviation of the input
By default, if F is not floating point type, then the result will have a double type if F is implicitly convertible to a floating point type.
Parameters:
 F controls type of output varianceAlgo algorithm for calculating variance (default: VarianceAlgo.online) summation algorithm for calculating sums (default: Summation.appropriate)
Returns:
The standard deviation of the input, must be floating point type type
Examples:
```import mir.math.common: approxEqual, sqrt;
import mir.ndslice.slice: sliced;

assert(standardDeviation([1.0, 2, 3]).approxEqual(sqrt(2.0 / 2)));
assert(standardDeviation([1.0, 2, 3], true).approxEqual(sqrt(2.0 / 3)));

assert(standardDeviation!float([0, 1, 2, 3, 4, 5].sliced(3, 2)).approxEqual(sqrt(17.5 / 5)));

static assert(is(typeof(standardDeviation!float([1, 2, 3])) == float));
```
Examples:
Standard deviation of vector
```import mir.math.common: approxEqual, sqrt;
import mir.ndslice.slice: sliced;

auto x = [0.0, 1.0, 1.5, 2.0, 3.5, 4.25,
2.0, 7.5, 5.0, 1.0, 1.5, 0.0].sliced;

assert(x.standardDeviation.approxEqual(sqrt(54.76562 / 11)));
```
Examples:
Standard deviation of matrix
```import mir.math.common: approxEqual, sqrt;
import mir.ndslice.fuse: fuse;

auto x = [
[0.0, 1.0, 1.5, 2.0, 3.5, 4.25],
[2.0, 7.5, 5.0, 1.0, 1.5, 0.0]
].fuse;

assert(x.standardDeviation.approxEqual(sqrt(54.76562 / 11)));
```
Examples:
Column standard deviation of matrix
```import mir.algorithm.iteration: all;
import mir.math.common: approxEqual, sqrt;
import mir.ndslice.fuse: fuse;
import mir.ndslice.topology: alongDim, byDim, map;

auto x = [
[0.0,  1.0, 1.5, 2.0],
[3.5, 4.25, 2.0, 7.5],
[5.0,  1.0, 1.5, 0.0]
].fuse;
auto result = [13.16667 / 2, 7.041667 / 2, 0.1666667 / 2, 30.16667 / 2].map!sqrt;

// Use byDim or alongDim with map to compute standardDeviation of row/column.
assert(x.byDim!1.map!standardDeviation.all!approxEqual(result));
assert(x.alongDim!0.map!standardDeviation.all!approxEqual(result));

// FIXME
// Without using map, computes the standardDeviation of the whole slice
// assert(x.byDim!1.standardDeviation == x.sliced.standardDeviation);
// assert(x.alongDim!0.standardDeviation == x.sliced.standardDeviation);
```
Examples:
Can also set algorithm type
```import mir.math.common: approxEqual, sqrt;
import mir.ndslice.slice: sliced;

auto a = [0.0, 1.0, 1.5, 2.0, 3.5, 4.25,
2.0, 7.5, 5.0, 1.0, 1.5, 0.0].sliced;

auto x = a + 1_000_000_000;

auto y = x.standardDeviation;
assert(y.approxEqual(sqrt(54.76562 / 11)));

// The naive algorithm is numerically unstable in this case
auto z0 = x.standardDeviation!"naive";
assert(!z0.approxEqual(y));

// But the two-pass algorithm provides a consistent answer
auto z1 = x.standardDeviation!"twoPass";
assert(z1.approxEqual(y));
```
Examples:
Can also set algorithm or output type
```import mir.math.common: approxEqual, sqrt;
import mir.ndslice.slice: sliced;
import mir.ndslice.topology: repeat;

//Set population standard deviation, standardDeviation algorithm, sum algorithm or output type

auto a = [1.0, 1e100, 1, -1e100].sliced;
auto x = a * 10_000;

bool populationTrueRT = true;
bool populationFalseRT = false;
enum PopulationTrueCT = true;

/++
Due to Floating Point precision, when centering `x`, subtracting the mean
from the second and fourth numbers has no effect. Further, after centering
and squaring `x`, the first and third numbers in the slice have precision
too low to be included in the centered sum of squares.
+/
assert(x.standardDeviation(populationFalseRT).approxEqual(sqrt(2.0e208 / 3)));
assert(x.standardDeviation(populationTrueRT).approxEqual(sqrt(2.0e208 / 4)));
assert(x.standardDeviation(PopulationTrueCT).approxEqual(sqrt(2.0e208 / 4)));

assert(x.standardDeviation!("online").approxEqual(sqrt(2.0e208 / 3)));
assert(x.standardDeviation!("online", "kbn").approxEqual(sqrt(2.0e208 / 3)));
assert(x.standardDeviation!("online", "kb2").approxEqual(sqrt(2.0e208 / 3)));
assert(x.standardDeviation!("online", "precise").approxEqual(sqrt(2.0e208 / 3)));
assert(x.standardDeviation!(double, "online", "precise").approxEqual(sqrt(2.0e208 / 3)));
assert(x.standardDeviation!(double, "online", "precise")(populationTrueRT).approxEqual(sqrt(2.0e208 / 4)));

auto y = uint.max.repeat(3);
auto z = y.standardDeviation!ulong;
assert(z == 0.0);
static assert(is(typeof(z) == double));
```
Examples:
For integral slices, pass output type as template parameter to ensure output type is correct.
```import mir.math.common: approxEqual, sqrt;
import mir.ndslice.slice: sliced;

auto x = [0, 1, 1, 2, 4, 4,
2, 7, 5, 1, 2, 0].sliced;

auto y = x.standardDeviation;
assert(y.approxEqual(sqrt(50.91667 / 11)));
static assert(is(typeof(y) == double));

assert(x.standardDeviation!float.approxEqual(sqrt(50.91667 / 11)));
```
Examples:
Variance works for other user-defined types (provided they can be converted to a floating point)
```import mir.ndslice.slice: sliced;

static struct Foo {
float x;
alias x this;
}

Foo[] foo = [Foo(1f), Foo(2f), Foo(3f)];
assert(foo.standardDeviation == 1f);
```
Examples:
Compute standard deviation along specified dimention of tensors
```import mir.algorithm.iteration: all;
import mir.math.common: approxEqual, sqrt;
import mir.ndslice.fuse: fuse;
import mir.ndslice.topology: as, iota, alongDim, map, repeat;

auto x = [
[0.0, 1, 2],
[3.0, 4, 5]
].fuse;

assert(x.standardDeviation.approxEqual(sqrt(17.5 / 5)));

auto m0 = repeat(sqrt(4.5), 3);
assert(x.alongDim!0.map!standardDeviation.all!approxEqual(m0));
assert(x.alongDim!(-2).map!standardDeviation.all!approxEqual(m0));

auto m1 = [1.0, 1.0];
assert(x.alongDim!1.map!standardDeviation.all!approxEqual(m1));
assert(x.alongDim!(-1).map!standardDeviation.all!approxEqual(m1));

assert(iota(2, 3, 4, 5).as!double.alongDim!0.map!standardDeviation.all!approxEqual(repeat(sqrt(3600.0 / 2), 3, 4, 5)));
```
Examples:
Arbitrary standard deviation
```import mir.math.common: sqrt;

assert(standardDeviation(1.0, 2, 3) == 1.0);
assert(standardDeviation!float(1, 2, 3) == 1f);
```
stdevType!F `standardDeviation`(Range)(Range `r`, bool `isPopulation` = false)
if (isIterable!Range);
Parameters:
 Range `r` range, must be finite iterable bool `isPopulation` true if population standard deviation, false if sample standard deviation (default)
stdevType!F `standardDeviation`(scope const F[] `ar`...);
Parameters:
 F[] `ar` values
template `simpleLinearRegression`(Summation summation = Summation.kbn)

template `simpleLinearRegression`(string summation)
A linear regression model with a single explanatory variable.
Examples:
```import mir.math.common: approxEqual;
static immutable x = [0, 1, 2, 3];
static immutable y = [-1, 0.2, 0.9, 2.1];
auto params = x.simpleLinearRegression(y);
assert(params[0].approxEqual(-0.95)); // shift
assert(params[1].approxEqual(1)); // slope
```
@safe sumType!YRange[2] `simpleLinearRegression`(XRange, YRange)(XRange `x`, YRange `y`)
if (isInputRange!XRange && isInputRange!YRange && !(isArray!XRange && isArray!YRange) && isFloatingPoint!(sumType!YRange));

@safe sumType!(Y[])[2] `simpleLinearRegression`(X, Y)(scope const X[] `x`, scope const Y[] `y`);
Parameters:
 XRange `x` `x`[i] points YRange `y` f(`x`[i]) values
Returns:
The pair of shift and slope of the linear curve.