1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 package org.openimaj.math.matrix.algorithm.ica;
31
32 import java.util.Arrays;
33
34 import org.openimaj.math.matrix.MatrixUtils;
35 import org.openimaj.util.array.ArrayUtils;
36
37 import Jama.Matrix;
38
39 public class SymmetricFastICA extends IndependentComponentAnalysis {
40 enum NonlinearFunction {
41 tanh, pow3, rat1, rat2, gaus
42 }
43
44 double epsilon = 0.0001;
45 double MaxIt = 100;
46 NonlinearFunction g;
47
48 Matrix W;
49 private Matrix icasig;
50
51 @Override
52 public Matrix getSignalToInterferenceMatrix() {
53
54 return null;
55 }
56
57 @Override
58 public Matrix getDemixingMatrix() {
59
60 return null;
61 }
62
63 @Override
64 public Matrix getIndependentComponentMatrix() {
65
66 return null;
67 }
68
69 @Override
70 protected void estimateComponentsWhitened(Matrix Z, double[] mean, Matrix X, Matrix CC) {
71 final int dim = X.getRowDimension();
72 final int N = X.getColumnDimension();
73
74 final double[] crit = new double[dim];
75 int NumIt = 0;
76 Matrix WOld = W;
77
78 while (1 - ArrayUtils.minValue(crit) > epsilon && NumIt < MaxIt) {
79 NumIt = NumIt + 1;
80
81 switch (g) {
82 case tanh:
83 final Matrix hypTan = MatrixUtils.tanh(Z.transpose().times(W));
84
85
86 final double[] sumv = new double[hypTan.getColumnDimension()];
87 for (int r = 0; r < hypTan.getRowDimension(); r++) {
88 for (int c = 0; c < hypTan.getColumnDimension(); c++) {
89 sumv[c] += 1 - hypTan.get(r, c) * hypTan.get(r, c);
90 }
91 }
92 final Matrix weight = new Matrix(W.getRowDimension(), W.getColumnDimension());
93 for (int r = 0; r < weight.getRowDimension(); r++) {
94 for (int c = 0; c < weight.getColumnDimension(); c++) {
95 weight.set(r, c, W.get(r, c) * sumv[c] / N);
96 }
97 }
98
99 W = MatrixUtils.times(Z.times(hypTan), 1.0 / N).minus(weight);
100
101 break;
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135 }
136
137
138
139 final Matrix WtW = W.transpose().times(W);
140 W = W.times(MatrixUtils.invSqrtSym(WtW));
141
142 for (int c = 0; c < W.getColumnDimension(); c++) {
143 crit[c] = 0;
144 for (int r = 0; r < W.getRowDimension(); r++) {
145 crit[r] += W.get(r, c) * WOld.get(r, c);
146 }
147 crit[c] = Math.abs(crit[c]);
148 }
149
150 WOld = W;
151 }
152
153
154
155
156
157 W = W.transpose().times(CC);
158
159
160 final Matrix WXmean = W.times(new Matrix(new double[][] { mean }).transpose());
161 final Matrix delta = WXmean.times(MatrixUtils.ones(1, N));
162 icasig = W.times(X).plus(delta);
163 }
164
165 public static void main(String[] args) {
166 final int dim = 1000;
167 final double[] signal1 = new double[dim];
168 final double[] signal2 = new double[dim];
169 for (int i = 0; i < dim; i++) {
170 signal1[i] = Math.cos(i);
171 signal2[i] = Math.tan(i);
172 }
173
174 final double[] mix1 = new double[dim];
175 final double[] mix2 = new double[dim];
176 for (int i = 0; i < dim; i++) {
177 mix1[i] = signal1[i] + 0.8 * signal2[i];
178 mix2[i] = signal2[i] + 0.5 * signal1[i];
179 }
180
181 System.out.println("a=" + Arrays.toString(signal1));
182 System.out.println("b=" + Arrays.toString(signal2));
183 System.out.println("mixa=" + Arrays.toString(mix1));
184 System.out.println("mixb=" + Arrays.toString(mix2));
185
186 final Matrix data = new Matrix(new double[][] { mix1, mix2 });
187 final SymmetricFastICA symfica = new SymmetricFastICA();
188 symfica.g = NonlinearFunction.tanh;
189 symfica.W = Matrix.identity(2, 2);
190
191 symfica.estimateComponents(data);
192
193 symfica.W.print(5, 5);
194 symfica.icasig.print(5, 5);
195 }
196 }