The OpenD Programming Language

dispersion

Calculates the dispersion of the input.

For an input x, this function first centers x by subtracting each e in x by the result of centralTendency, then it transforms the centered values using the function transform, and then finally summarizes that information using the summarize funcion.

The default functions provided are equivalent to calculating the population variance. The centralTendency default is the mean function, which results in the input being centered about the mean. The default transform function will square the centered values. The default summarize function is mean, which will return the mean of the squared centered values.

  1. auto dispersion(Slice!(Iterator, N, kind) slice)
    template dispersion(alias centralTendency = mean, alias transform = "a * a", alias summarize = mean)
    static if(__traits(isSame, naryFun!transform, transform))
    dispersion
    (
    Iterator
    size_t N
    SliceKind kind
    )
    (
    Slice!(Iterator, N, kind) slice
    )
  2. auto dispersion(T[] ar)
  3. auto dispersion(SliceLike x)

Members

Functions

dispersion
auto dispersion(Slice!(Iterator, N, kind) slice)
auto dispersion(T[] ar)
auto dispersion(SliceLike x)

Parameters

centralTendency

function that will produce the value that the input is centered about, default is mean

transform

function to transform centered values, default squares the centered values

summarize

function to summarize the transformed centered values, default is mean

Return Value

The dispersion of the input

Examples

Simple examples

import mir.complex: Complex;
import mir.complex.math: capproxEqual = approxEqual;
import mir.functional: naryFun;
import mir.math.common: approxEqual;
import mir.ndslice.slice: sliced;

alias C = Complex!double;

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

assert(dispersion([C(1.0, 3), C(2), C(3)]).capproxEqual(C(-4, -6) / 3));

assert(dispersion!(mean!float, "a * a", mean!float)([0, 1, 2, 3, 4, 5].sliced(3, 2)).approxEqual(17.5 / 6));

static assert(is(typeof(dispersion!(mean!float, "a ^^ 2", mean!float)([1, 2, 3])) == float));

Dispersion of vector

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];

assert(x.dispersion.approxEqual(54.76562 / 12));

Dispersion 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.dispersion.approxEqual(54.76562 / 12));

Column dispersion 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 / 3, 7.041667 / 3, 0.1666667 / 3, 30.16667 / 3];

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

// FIXME
// Without using map, computes the dispersion of the whole slice
// assert(x.byDim!1.dispersion == x.sliced.dispersion);
// assert(x.alongDim!0.dispersion == x.sliced.dispersion);

Can also set functions to change type of dispersion that is used

import mir.functional: naryFun;
import mir.math.common: approxEqual, fabs, sqrt;

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];

alias square = naryFun!"a * a";

// Other population variance examples
assert(x.dispersion.approxEqual(54.76562 / 12));
assert(x.dispersion!mean.approxEqual(54.76562 / 12));
assert(x.dispersion!(mean, square).approxEqual(54.76562 / 12));
assert(x.dispersion!(mean, square, mean).approxEqual(54.76562 / 12));

// Population standard deviation
assert(x.dispersion!(mean, square, mean).sqrt.approxEqual(sqrt(54.76562 / 12)));

// Mean absolute deviation about the mean
assert(x.dispersion!(mean, fabs, mean).approxEqual(21.0 / 12));
//Mean absolute deviation about the median
assert(x.dispersion!(median, fabs, mean).approxEqual(19.25000 / 12));
//Median absolute deviation about the mean
assert(x.dispersion!(mean, fabs, median).approxEqual(1.43750));
//Median absolute deviation about the median
assert(x.dispersion!(median, fabs, median).approxEqual(1.25000));

For integral slices, pass output type to centralTendency, transform, and summary functions as template parameter to ensure output type is correct.

import mir.functional: naryFun;
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;

alias square = naryFun!"a * a";

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

assert(x.dispersion!(mean!float, square, mean!float).approxEqual(50.91667 / 12));

Dispersion works for complex numbers and other user-defined types (provided that the centralTendency, transform, and summary functions are defined for those types)

import mir.ndslice.slice: sliced;
import std.complex: Complex;
import std.math.operations: isClose;

auto x = [Complex!double(1, 2), Complex!double(2, 3), Complex!double(3, 4), Complex!double(4, 5)].sliced;
assert(x.dispersion.isClose(Complex!double(0, 10) / 4));

Compute mean 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: as, iota, alongDim, map, repeat;

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

assert(x.dispersion.approxEqual(17.5 / 6));

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

auto m1 = [2.0 / 3, 2.0 / 3];
assert(x.alongDim!1.map!dispersion.all!approxEqual(m1));
assert(x.alongDim!(-1).map!dispersion.all!approxEqual(m1));

assert(iota(2, 3, 4, 5).as!double.alongDim!0.map!dispersion.all!approxEqual(repeat(1800.0 / 2, 3, 4, 5)));

Arbitrary dispersion

import mir.functional: naryFun;
import mir.math.common: approxEqual;

alias square = naryFun!"a * a";

assert(dispersion(1.0, 2, 3).approxEqual(2.0 / 3));
assert(dispersion!(mean!float, square, mean!float)(1, 2, 3).approxEqual(2f / 3));

Meta