The OpenD Programming Language

covariance

Calculates the covariance of the inputs.

If x and y are both slices or convertible to slices, then they must be one-dimensional.

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.

  1. CommonType!(meanType!RangeX, meanType!RangeY) covariance(RangeX x, RangeY y, bool isPopulation)
    template covariance(CovarianceAlgo covarianceAlgo = CovarianceAlgo.hybrid, Summation summation = Summation.appropriate)
    CommonType!(meanType!RangeX, meanType!RangeY)
    covariance
    (
    RangeX
    RangeY
    )
    (
    RangeX x
    ,
    RangeY y
    ,
    bool isPopulation = false
    )
    if (
    isInputRange!RangeX &&
    )
  2. template covariance(F, CovarianceAlgo covarianceAlgo = CovarianceAlgo.hybrid, Summation summation = Summation.appropriate)
  3. template covariance(F, string covarianceAlgo, string summation = "appropriate")
  4. template covariance(string covarianceAlgo, string summation = "appropriate")

Members

Functions

covariance
CommonType!(meanType!RangeX, meanType!RangeY) covariance(RangeX x, RangeY y, bool isPopulation)

Parameters

covarianceAlgo

algorithm for calculating covariance (default: CovarianceAlgo.hybrid)

summation

algorithm for calculating sums (default: Summation.appropriate)

Return Value

The covariance of the inputs

Examples

Covariance of vectors

import mir.ndslice.slice: sliced;
import mir.test: shouldApprox;

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;
auto y = [-0.75,   6.0, -0.25, 8.25, 5.75,  3.5,
           9.25, -0.75,   2.5, 1.25,   -1, 2.25].sliced;

x.covariance(y, true).shouldApprox == -5.5 / 12;
x.covariance(y).shouldApprox == -5.5 / 11;

Can also set algorithm type

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

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 = [-0.75,   6.0, -0.25, 8.25, 5.75,  3.5,
           9.25, -0.75,   2.5, 1.25,   -1, 2.25].sliced;

auto x = a + 10.0 ^^ 9;
auto y = b + 10.0 ^^ 9;

x.covariance(y).shouldApprox == -5.5 / 11;

// The naive algorithm is numerically unstable in this case
assert(!x.covariance!"naive"(y).approxEqual(-5.5 / 11));

// The two-pass algorithm provides the same answer as hybrid
x.covariance!"twoPass"(y).shouldApprox == -5.5 / 11;

// And the assumeZeroMean algorithm is way off
assert(!x.covariance!"assumeZeroMean"(y).approxEqual(-5.5 / 11));

Can also set algorithm or output type

import mir.ndslice.slice: sliced;
import mir.ndslice.topology: repeat;
import mir.test: shouldApprox;

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

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

/++
Due to Floating Point precision, when centering `x`, subtracting the mean
from the second and fourth numbers has no effect (for `y` the same is true
for the first and fourth). Further, after centering and multiplying `x` and
`y`, the third numbers in the slice has precision too low to be included in
the centered sum of the products.
+/
x.covariance(y).shouldApprox == 1.0e208 / 3;
x.covariance(y, true).shouldApprox == 1.0e208 / 4;

x.covariance!("online")(y).shouldApprox == 1.0e208 / 3;
x.covariance!("online", "kbn")(y).shouldApprox == 1.0e208 / 3;
x.covariance!("online", "kb2")(y).shouldApprox == 1.0e208 / 3;
x.covariance!("online", "precise")(y).shouldApprox == 1.0e208 / 3;
x.covariance!(double, "online", "precise")(y).shouldApprox == 1.0e208 / 3;

auto z = uint.max.repeat(3);
z.covariance!float(z).shouldApprox == 0.0;
static assert(is(typeof(z.covariance!float(z)) == float));

For integral slices, pass output type as template parameter to ensure output type is correct.

import mir.ndslice.slice: sliced;
import mir.test: shouldApprox;

auto x = [0, 1, 1, 2, 4, 4,
          2, 7, 5, 1, 2, 0].sliced;
auto y = [6, 3, 7, 1, 1, 1,
          9, 5, 3, 1, 3, 7].sliced;

x.covariance(y).shouldApprox == -18.583333 / 11;
static assert(is(typeof(x.covariance(y)) == double));

x.covariance!float(y).shouldApprox == -18.583333 / 11;
static assert(is(typeof(x.covariance!float(y)) == float));

Works with @nogc

import mir.ndslice.allocation: mininitRcslice;
import mir.test: shouldApprox;

static immutable 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];
static immutable b = [-0.75,   6.0, -0.25, 8.25, 5.75,  3.5,
                       9.25, -0.75,   2.5, 1.25,   -1, 2.25];
auto x = mininitRcslice!double(12);
auto y = mininitRcslice!double(12);
x[] = a;
y[] = b;

x.covariance(y, true).shouldApprox == -5.5 / 12;
x.covariance(y).shouldApprox == -5.5 / 11;

Meta