Function Objects

## Example 2: Aggregation

Aggregation is a generalized form of summation or integration. Aggregation functions visit all cells of a matrix and derive a single number as "summary information". Number of elements, mean, maximum, minimum, variance, root-mean-square are classic aggregation functions, but there are many more. Floods of data are too difficult to understand - a single number sells better to management. More seriously, the scientific process takes observations and tries to find patterns, the essentials of knowledge, which are more compact and easier to internalize than the observations itself. The most compact representation of knowledge is, of course, a single number.

We will use the prefabricated `plus` and `square` function objects to compute the sum of squares of a 1-d matrix, but first, let's get prepared.

    double[] v1 = {0, 1, 2, 3};
    DoubleMatrix1D matrix = new DenseDoubleMatrix1D(v1);

    // the naming shortcut (alias) saves some keystrokes:
    cern.jet.math.Functions F = cern.jet.math.Functions.functions;

## Aggregation over one matrix

    // Sum( x[i]*x[i] )
    System.out.println(matrix.aggregate(F.plus,F.square));
    // --> 14

    // Sum( x[i]*x[i]*x[i] )
    System.out.println(matrix.aggregate(F.plus,F.pow(3)));
    // --> 36

    // Sum( x[i] )
    System.out.println(matrix.aggregate(F.plus,F.identity));
    // or the specialized version
    System.out.println(matrix.zSum());
    // --> 6

    // Min( x[i] )
    System.out.println(matrix.aggregate(F.min,F.identity));
    // --> 0

    // Max( Sqrt(x[i]) / 2 )
    System.out.println(matrix.aggregate(F.max,F.chain(F.div(2),F.sqrt)));
    // --> 0.8660254037844386

    // Number of all cells with 0 <= value <= 2
    System.out.println(matrix.aggregate(F.plus,F.between(0,2)));
    // --> 3

    // Number of all cells with 0.8 <= Log2(value) <= 1.2
    System.out.println(matrix.aggregate(F.plus,F.chain(F.between(0.8,1.2),F.log2)));
    // --> 1

    // Product( x[i] )
    System.out.println(matrix.aggregate(F.mult,F.identity));
    // --> 0

    // Product( x[i] ) of all x[i] > limit
    final double limit = 1;
    DoubleFunction f = new DoubleFunction() {
    	public final double apply(double a) { return a>limit ? a : 1; }
    };
    System.out.println(matrix.aggregate(F.mult,f));
    // --> 6

    // RMS (Root-Mean-Square) is a measure of the average "size" of the elements of a data sequence.
    double rms = Math.sqrt(matrix.aggregate(F.plus,F.square) / matrix.size());

## Aggregation over two matrices

    DoubleMatrix1D x = matrix.copy();
    DoubleMatrix1D y = matrix.copy();
    // x is 0 1 2 3
    // y is 0 1 2 3

    // Sum( x[i]*y[i] )
    System.out.println(x.aggregate(y, F.plus, F.mult));
    // --> 14

    // Sum( (x[i]+y[i])^2 )
    System.out.println(x.aggregate(y, F.plus, F.chain(F.square,F.plus)));
    // --> 56

    // Sum(Math.PI * Math.log(y[i] / x[i]))
    x.aggregate(y, F.plus, F.chain(F.mult(Math.PI),F.chain(F.log,F.swapArgs(F.div))));

    // equivalent, but perhaps less error prone and more readable:
    x.aggregate(y, F.plus,
       new DoubleDoubleFunction() {
          public double apply(double a, double b) { return Math.PI*Math.log(b/a); }
       }
    );

Try the examples on 2-d or 3-d matrices. They work without changes (except, of course, that construction of the source matrix need to be modified).