001/**
002 * Copyright (c) 2011, The University of Southampton and the individual contributors.
003 * All rights reserved.
004 *
005 * Redistribution and use in source and binary forms, with or without modification,
006 * are permitted provided that the following conditions are met:
007 *
008 *   *  Redistributions of source code must retain the above copyright notice,
009 *      this list of conditions and the following disclaimer.
010 *
011 *   *  Redistributions in binary form must reproduce the above copyright notice,
012 *      this list of conditions and the following disclaimer in the documentation
013 *      and/or other materials provided with the distribution.
014 *
015 *   *  Neither the name of the University of Southampton nor the names of its
016 *      contributors may be used to endorse or promote products derived from this
017 *      software without specific prior written permission.
018 *
019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 */
030package org.openimaj.math.matrix.algorithm.ica;
031
032import org.openimaj.math.matrix.MatrixUtils;
033import org.openimaj.util.pair.IndependentPair;
034
035import Jama.Matrix;
036
037public abstract class IndependentComponentAnalysis {
038        public abstract Matrix getSignalToInterferenceMatrix();
039
040        public abstract Matrix getDemixingMatrix();
041
042        public abstract Matrix getIndependentComponentMatrix();
043
044        /**
045         * Estimate the independent components of the given data array. Each row
046         * corresponds to an observation with the number of dimensions equal to the
047         * number of columns.
048         * 
049         * @param data
050         *            the data
051         */
052        public void estimateComponents(double[][] data) {
053                estimateComponents(new Matrix(data));
054        }
055
056        /**
057         * Estimate the independent components of the given data array. Each row
058         * corresponds to an observation with the number of dimensions equal to the
059         * number of columns.
060         * 
061         * @param data
062         *            the data
063         */
064        public void estimateComponents(Matrix data) {
065                final IndependentPair<Matrix, double[]> p = computeMeanCentre(data);
066                final Matrix meanCentredX = p.firstObject();
067                final double[] mean = p.getSecondObject();
068
069                final IndependentPair<Matrix, Matrix> p2 = decorrelate(meanCentredX);
070                final Matrix Z = p2.firstObject();
071                final Matrix CC = p2.secondObject();
072                estimateComponentsWhitened(Z, mean, meanCentredX, CC);
073        }
074
075        private IndependentPair<Matrix, Matrix> decorrelate(Matrix meanCentredX) {
076                final Matrix C = MatrixUtils.covariance(meanCentredX.transpose());
077                final Matrix CC = MatrixUtils.invSqrtSym(C);
078                return IndependentPair.pair(CC.times(meanCentredX), CC);
079        }
080
081        private IndependentPair<Matrix, double[]> computeMeanCentre(Matrix m) {
082                final double[][] data = m.getArray();
083
084                final double[] mean = new double[data.length];
085
086                for (int j = 0; j < data.length; j++)
087                        for (int i = 0; i < data[0].length; i++)
088                                mean[j] += data[j][i];
089
090                for (int i = 0; i < data.length; i++)
091                        mean[i] /= data[0].length;
092
093                final Matrix mat = new Matrix(data.length, data[0].length);
094                final double[][] matdat = mat.getArray();
095
096                for (int j = 0; j < data.length; j++)
097                        for (int i = 0; i < data[0].length; i++)
098                                matdat[j][i] = (data[j][i] - mean[j]);
099
100                return IndependentPair.pair(mat, mean);
101        }
102
103        /**
104         * Estimate the IC's from the given decorrelated (mean-centred and whitened)
105         * data matrix, Z.
106         * 
107         * @param Z
108         *            the whitened data; one observation per row
109         * @param mean
110         *            the mean of each dimension
111         * @param X
112         *            the mean-centered data; one observation per row
113         */
114        protected abstract void estimateComponentsWhitened(Matrix Z, double[] mean, Matrix X, Matrix CC);
115}