View Javadoc

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&iacute; (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             // reset category nodes off flag
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             // F2 activation
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             // fast learning
309             System.arraycopy(I, 0, weights[winner], 0, numberOfInputs);
310             // for(i = 0; i < numberOfInputs; i++)
311             // weights[winner][i] = I[i];
312             currentUncommitted = false;
313         } else
314             // slow recoding
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         // if (log.isDebugEnabled()) {
320         // log.debug("------- Learning -------");
321         // log.debug("Input = " + I);
322         // log.debug("Winner = " + weights[winner]);
323         // log.debug("--------");
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 }