1 package yawn.nn.fuzzyartmap.fuzzyart;
2
3 import org.apache.commons.logging.Log;
4 import org.apache.commons.logging.LogFactory;
5
6 import yawn.nn.mlp.MultiLayerPerceptron;
7
8 /***
9 * This is yawn.nn.fuzzyartmap.fuzzyart.FuzzyArt, part of the yawn project.
10 *
11 * <p>$Id: FuzzyArt.java,v 1.11 2005/05/09 11:04:58 supermarti Exp $</p>
12 *
13 * @author Luis Martí (luis dot marti at uc3m dot es)
14 * @version $Revision: 1.11 $
15 */
16 public class FuzzyArt {
17 private static final Log log = LogFactory.getLog(MultiLayerPerceptron.class);
18
19 private static final int ARRAY_INCREMENT = 10;
20
21 private double alpha;
22
23 private double beta;
24
25 public boolean complementCoding;
26
27 public boolean currentUncommitted;
28
29 private boolean eligible[];
30
31 /***
32 *
33 * @uml.property name="hasIncreased"
34 */
35 public boolean hasIncreased;
36
37 /***
38 *
39 * @uml.property name="i"
40 */
41 private double I[];
42
43
44 private int maxEpochs;
45
46 private double maxY;
47
48 /***
49 *
50 * @uml.property name="numberOfInputs"
51 */
52 private int numberOfInputs;
53
54
55 public int numberUsedNodes;
56
57 private int numReset;
58
59 public double sumInputs;
60
61 public double sumIW[];
62
63 private double sumWeights;
64
65 public double vigilance;
66
67 private double weights[][];
68
69 public int winner;
70
71 /***
72 *
73 * @uml.property name="y"
74 */
75 private double Y[];
76
77
78 public double getMatchCritetionValue() {
79 return sumIW[winner] / sumInputs;
80 }
81
82 public FuzzyArt() {
83 numberUsedNodes = 0;
84 currentUncommitted = true;
85 winner = -1;
86 complementCoding = false;
87 maxEpochs = 0;
88 alpha = beta = vigilance = 0.0;
89 numberOfInputs = 0;
90 Y = null;
91 I = null;
92 eligible = null;
93 weights = null;
94 maxY = 0.0;
95
96 sumWeights = 0.0;
97 sumIW = null;
98 sumInputs = 0.0;
99
100 numReset = 0;
101
102 hasIncreased = false;
103 }
104
105 public FuzzyArt(double alpha, double beta, double vigilance, int numberInputs, int maxEpochs,
106 boolean complementCoding) {
107 numberUsedNodes = 0;
108 currentUncommitted = true;
109 winner = -1;
110 this.complementCoding = complementCoding;
111 this.maxEpochs = maxEpochs;
112 this.alpha = alpha;
113 this.beta = beta;
114 this.vigilance = vigilance;
115
116 if (complementCoding)
117 this.numberOfInputs = numberInputs * 2;
118 else
119 this.numberOfInputs = numberInputs;
120
121 Y = new double[ARRAY_INCREMENT];
122 I = new double[this.numberOfInputs];
123 eligible = new boolean[ARRAY_INCREMENT];
124 weights = new double[ARRAY_INCREMENT][this.numberOfInputs];
125
126 sumWeights = 0.0;
127 sumIW = new double[ARRAY_INCREMENT];
128 sumInputs = 0.0;
129
130 for (int i = 0; i < ARRAY_INCREMENT; i++) {
131 eligible[i] = true;
132 for (int j = 0; j < this.numberOfInputs; j++)
133 weights[i][j] = 1.0;
134 }
135
136 numReset = 0;
137 hasIncreased = false;
138 }
139
140 public boolean activate() {
141 winner = -1;
142
143 int i, j;
144
145 if (numberUsedNodes == 0) {
146 currentUncommitted = true;
147 return true;
148 }
149
150 numReset = 0;
151
152 sumInputs = 0.0;
153 for (i = 0; i < numberOfInputs; i++)
154 sumInputs += I[i];
155
156 maxY = java.lang.Double.NEGATIVE_INFINITY;
157 for (i = 0; i < numberUsedNodes; i++) {
158
159 eligible[i] = true;
160
161 sumWeights = 0.0;
162 sumIW[i] = 0.0;
163 for (j = 0; j < numberOfInputs; j++) {
164 sumWeights += weights[i][j];
165 sumIW[i] += (weights[i][j] < I[j]) ? weights[i][j] : I[j];
166 }
167
168 Y[i] = sumIW[i] / (alpha + sumWeights);
169
170 if ((sumIW[i] >= vigilance * sumInputs) && maxY < Y[i]) {
171 winner = i;
172 maxY = Y[i];
173 }
174 }
175
176 if (winner != -1) {
177 currentUncommitted = false;
178 return false;
179 }
180
181 if (numberUsedNodes + 1 == Y.length)
182 increaseSize();
183 currentUncommitted = true;
184 return true;
185 }
186
187 public void binaryTest(int numPatterns, int patLength) {
188 double pattern[] = new double[patLength];
189
190 for (int i = 0; i < numPatterns; i++) {
191 for (int j = 0; j < patLength; j++) {
192 pattern[j] = Math.round(Math.random());
193 }
194 setInputPattern(pattern);
195 trainCurrentPattern();
196 log.debug("Categories used: " + numberUsedNodes);
197 }
198 }
199
200 public double[] complementCode(double[] in) {
201 double[] res = new double[in.length * 2];
202
203 for (int i = 0; i < in.length; i++) {
204 res[i] = in[i];
205 res[i + in.length] = 1 - in[i];
206 }
207 return res;
208 }
209
210 public void doubleTest(int numPatterns, int patLength) {
211 double pattern[] = new double[patLength];
212
213 for (int i = 0; i < numPatterns; i++) {
214 for (int j = 0; j < patLength; j++) {
215 pattern[j] = Math.random();
216 }
217 setInputPattern(pattern);
218 trainCurrentPattern();
219 log.debug("Categories used: " + numberUsedNodes);
220 }
221 }
222
223 public double getF2NodeActivation(int nodeIndex) {
224 return Y[nodeIndex];
225 }
226
227 /***
228 *
229 * @uml.property name="i"
230 */
231 public double[] getI() {
232 return I;
233 }
234
235
236 public int getNumberOfCommitedNodes() {
237 int res = 0;
238 for (int k = 0; k < eligible.length; k++)
239 if (eligible[k])
240 res++;
241 return res;
242 }
243
244 /***
245 *
246 * @uml.property name="numberOfInputs"
247 */
248 public int getNumberOfInputs() {
249 return numberOfInputs;
250 }
251
252
253 public double[] getWeightVector(int index) {
254 return weights[index];
255 }
256
257 /***
258 *
259 * @uml.property name="y"
260 */
261 public double[] getY() {
262 return Y;
263 }
264
265
266 public boolean hasIncreased() {
267 return hasIncreased;
268 }
269
270 private void increaseSize() {
271 int i, j;
272
273 double newY[] = new double[Y.length + ARRAY_INCREMENT];
274 System.arraycopy(Y, 0, newY, 0, Y.length);
275 for (i = Y.length; i < newY.length; i++)
276 newY[i] = 0.0;
277 Y = newY;
278
279 double newSumIW[] = new double[sumIW.length + ARRAY_INCREMENT];
280 System.arraycopy(sumIW, 0, newSumIW, 0, sumIW.length);
281 for (i = sumIW.length; i < newSumIW.length; i++)
282 newSumIW[i] = 0.0;
283 sumIW = newSumIW;
284
285 boolean newCatOff[] = new boolean[eligible.length + ARRAY_INCREMENT];
286 System.arraycopy(eligible, 0, newCatOff, 0, eligible.length);
287 for (i = eligible.length; i < newCatOff.length; i++)
288 newCatOff[i] = false;
289 eligible = newCatOff;
290
291 double newWeights[][] = new double[weights.length + ARRAY_INCREMENT][numberOfInputs];
292 for (i = 0; i < weights.length; i++)
293 System.arraycopy(weights[i], 0, newWeights[i], 0, numberOfInputs);
294 for (; i < newWeights.length; i++)
295 for (j = 0; j < numberOfInputs; j++)
296 newWeights[i][j] = 1.0;
297 weights = newWeights;
298
299 hasIncreased = true;
300 }
301
302 public void learn() {
303 int i;
304
305 if (currentUncommitted) {
306 winner = numberUsedNodes++;
307
308
309 System.arraycopy(I, 0, weights[winner], 0, numberOfInputs);
310
311
312 currentUncommitted = false;
313 } else
314
315 for (i = 0; i < numberOfInputs; i++)
316 weights[winner][i] = beta
317 * ((weights[winner][i] > I[i]) ? I[i] : weights[winner][i]) + (1.0 - beta)
318 * weights[winner][i];
319
320
321
322
323
324
325 }
326
327 public void resetCategory(int index) {
328 for (int i = 0; i < numberOfInputs; i++)
329 weights[index][i] = 1.0;
330 }
331
332 /***
333 *
334 * @uml.property name="hasIncreased"
335 */
336 public void setIncreasedFlag(boolean value) {
337 hasIncreased = value;
338 }
339
340
341 public void setInputPattern(double pattern[]) {
342 int i, j;
343
344 if (!complementCoding) {
345 System.arraycopy(pattern, 0, I, 0, numberOfInputs);
346 } else {
347 System.arraycopy(pattern, 0, I, 0, numberOfInputs / 2);
348 for (i = 0, j = numberOfInputs / 2; i < numberOfInputs / 2; i++, j++) {
349 I[j] = 1.0 - I[i];
350 }
351 }
352 }
353
354 /***
355 *
356 * @uml.property name="numberOfInputs"
357 */
358 public void setNumberOfInputs(int numberOfInputs) {
359 this.numberOfInputs = numberOfInputs;
360 }
361
362 public void train(double dataset[][]) {
363 int i, k;
364 boolean done = false;
365
366 for (k = 0; !done && k < maxEpochs; k++) {
367 log.debug("Epoch: " + (k + 1));
368 done = true;
369 for (i = 0; i < dataset.length; i++) {
370 setInputPattern(dataset[i]);
371 trainCurrentPattern();
372
373 if (numReset != 0)
374 done = false;
375 }
376 log.debug("Categories used: " + numberUsedNodes);
377 }
378 }
379
380 public void trainCurrentPattern() {
381 activate();
382 learn();
383 log.debug(winner + "; " + numReset);
384 }
385
386 public void trainRandom(double dataset[][]) {
387 int i, k, toTrain;
388 boolean done = false;
389
390 for (k = 0; !done && k < maxEpochs; k++) {
391 log.debug("\nEpoch: " + (k + 1));
392 done = true;
393 for (i = 0; i < dataset.length; i++) {
394 toTrain = (int) (Math.random() * (dataset.length - 1));
395 setInputPattern(dataset[toTrain]);
396 trainCurrentPattern();
397
398 if (numReset != 0)
399 done = false;
400 }
401 log.debug("Categories used: " + numberUsedNodes);
402 }
403 }
404
405 public double[] unComplementCode(double[] in) {
406 double[] res = new double[in.length / 2];
407 for (int i = 0; i < res.length; i++) {
408 res[i] = in[i];
409 }
410 return res;
411 }
412 }