001 /*
002 * SimuCS - Simulator to use with Classifier Systems
003 * MSc project - Oxford University
004 * by Benoit Isaac - Summer 2005
005 */
006
007 package simuLCS;
008 import java.io.PrintWriter;
009 import java.io.Serializable;
010
011 /**
012 * Implements the ZClassifier, ie. a Classifier with a strength.
013 * A few lines of code (mutation, crossover) below draw inspiration from the freely available XCSJava
014 * by Martin V. Butz
015 * @author Benoit, Martin V. Butz
016 */
017 public class ZClassifier extends Classifier implements Serializable,Comparable {
018
019 /**
020 * The Strength of the classifier.
021 */
022 private double strength = ZCSConfig.strengthIni;
023
024 /**
025 * Constructs a classifier with specified condition and specified action.
026 *
027 * @param cond The condition of the .
028 * @param act The action of the new classifier.
029 */
030 public ZClassifier(String cond, String act) {
031 super(cond,act);
032 }
033
034 /**
035 * Construct matching classifier with random action.
036 *
037 * @param setSize The size of the current set which the new classifier matches.
038 * @param time The actual number of instances the XCS learned from so far.
039 * (This should be set to the number of actions possible in the problem).
040 * @param situation The current problem instance/perception.
041 */
042 public ZClassifier(int actionLength, String situation) {
043 createMatchingCondition(situation);
044 createRandomAction(actionLength);
045 }
046
047 /**
048 * @param strength
049 * @param state
050 * @param act
051 */
052 public ZClassifier(double strength, String state, String act) {
053 createMatchingCondition(state);
054 action = act;
055 setStrength(strength);
056 }
057
058 /**
059 * Construct a classifier with random condition and random action.
060 *
061 * @param setSize The size of the current set which the new classifier matches.
062 * @param time The actual number of instances the XCS learned from so far.
063 * @param condLength The length of the condition of the new classifier.
064 * @param numberOfActions The number of different actions to chose from
065 */
066 public ZClassifier(int condLength, int actionLength) {
067 createRandomCondition(condLength);
068 createRandomAction(actionLength);
069 }
070
071 /**
072 * Constructs an identical XClassifier.
073 * However, the experience of the copy is set to 0 and the numerosity is set to 1
074 * since this is indeed a new individual in a population.
075 *
076 * @param clOld The to be copied classifier.
077 */
078 public ZClassifier(ZClassifier clOld) {
079 condition = new String(clOld.condition);
080 action = new String(clOld.action);
081 }
082
083 /**
084 * Creates a condition randomly considering the constant <code>P_dontcare<\code>.
085 * @param condLength The number of bits in the condition to be created
086 * @see XCSConstants#P_dontcare
087 */
088 private void createRandomCondition(int condLength) {
089 char condArray[] = new char[condLength];
090 for (int i = 0; i < condLength; i++) {
091 if (ZCSConfig.drand() < ZCSConfig.P_dontcare)
092 condArray[i] = ZCSConfig.dontCare;
093 else if (ZCSConfig.drand() < 0.5)
094 condArray[i] = '0';
095 else
096 condArray[i] = '1';
097 }
098 condition = new String(condArray);
099 }
100
101 /**
102 * Creates a matching condition considering the constant <code>P_dontcare<\code>.
103 * @param situation The situation which must satisfy the condition created.
104 * @see XCSConstants#P_dontcare
105 */
106 private void createMatchingCondition(String situation) {
107 int condLength = situation.length();
108 char condArray[] = new char[condLength];
109
110 for (int i = 0; i < condLength; i++) {
111 if (ZCSConfig.drand() < ZCSConfig.P_dontcare)
112 condArray[i] = ZCSConfig.dontCare;
113 else
114 condArray[i] = situation.charAt(i);
115 }
116 condition = new String(condArray);
117 }
118
119 /**
120 * Creates a random action.
121 * <b>While XCSJava use an <code>int</code> to describe the action, my actions
122 * are described by a <code>String</code> which defines the vector of the
123 * response.</b>
124 * @param actionLength The number of bits in the action to be created
125 */
126 private void createRandomAction(int actionLength) {
127 char actArray[] = new char[actionLength];
128
129 for (int i = 0; i < actionLength; i++) {
130 if (ZCSConfig.drand() < 0.5)
131 actArray[i] = '0';
132 else
133 actArray[i] = '1';
134 }
135 action = new String(actArray);
136 }
137
138 /**
139 * Applies one point crossover and returns if the classifiers changed.
140 *
141 * @see XCSConstants#pX
142 * @param cl The second classifier for the crossover application.
143 */
144 // TODO apply the crossover for the action as well ?
145 public boolean onePointCrossover(ZClassifier cl) {
146 boolean changed = false;
147 if (ZCSConfig.drand() < ZCSConfig.pX) {
148 int length = condition.length();
149 int sep1 = (int) (ZCSConfig.drand() * (length));
150 char[] cond1 = condition.toCharArray();
151 char[] cond2 = cl.condition.toCharArray();
152 for (int i = 0; i < sep1; i++) {
153 if (cond1[i] != cond2[i]) {
154 changed = true;
155 char tmp = cond1[i];
156 cond1[i] = cond2[i];
157 cond2[i] = tmp;
158 }
159 }
160 if (changed) {
161 condition = new String(cond1);
162 cl.condition = new String(cond2);
163
164 }
165 }
166
167 return changed;
168 }
169
170 /**
171 * Applies a niche mutation to the classifier.
172 * This method calls mutateCondition(state) and mutateAction(numberOfActions) and returns
173 * if at least one bit or the action was mutated.
174 *
175 * @param state The current situation/problem instance
176 */
177 public boolean applyMutation(String state, int actionLength) {
178 boolean changed = mutateCondition(state);
179 if (mutateAction(actionLength))
180 changed = true;
181 return changed;
182 }
183
184 /**
185 * Applies a NON niche mutation to the classifier.
186 * This method calls mutateCondition() and mutateAction(numberOfActions) and returns
187 * if at least one bit or the action was mutated.
188 *
189 */
190 public boolean applyMutation(int actionLength) {
191 boolean changed = mutateCondition();
192 if (mutateAction(actionLength))
193 changed = true;
194 return changed;
195 }
196
197 /**
198 * Mutates the condition of the classifier.
199 * If one allele is mutated depends on the constant pM.
200 * This mutation is a niche mutation. It assures that the resulting classifier
201 * still matches the current situation.
202 *
203 * @see XCSConstants#pM
204 * @param state The current situation/problem instance.
205 */
206 private boolean mutateCondition(String state) {
207 boolean changed = false;
208 int condLength = condition.length();
209
210 char[] cond = condition.toCharArray();
211 char[] stateC = state.toCharArray();
212
213 for (int i = 0; i < condLength; i++) {
214 if (ZCSConfig.drand() < ZCSConfig.pM) {
215 changed = true;
216 if (cond[i] == ZCSConfig.dontCare) {
217 cond[i] = stateC[i];
218 } else {
219 cond[i] = ZCSConfig.dontCare;
220 }
221
222 }
223 }
224 condition = new String(cond);
225 return changed;
226 }
227
228 /**
229 * Mutates the condition of the classifier.
230 * If one allele is mutated depends on the constant pM.
231 * This mutation is NOT a niche mutation.
232 * Once the allele is selected for mutation, a character (either '0','1',or '#')
233 * is selected randomly (using an uniform disctribution).
234 *
235 * @see XCSConstants#pM
236 */
237 private boolean mutateCondition() {
238 boolean changed = false;
239 int condLength = condition.length();
240
241 char[] cond = condition.toCharArray();
242 for (int i = 0; i < condLength; i++) {
243 if (ZCSConfig.drand() < ZCSConfig.pM) {
244 changed = true;
245 double randChar = ZCSConfig.drand();
246 switch (cond[i]) {
247 case '0' :
248 cond[i] =
249 (randChar < 0.5) ? '1' : ZCSConfig.dontCare;
250 break;
251 case '1' :
252 cond[i] =
253 (randChar < 0.5) ? '0' : ZCSConfig.dontCare;
254 break;
255 case ZCSConfig.dontCare :
256 if(Config.PRINT_MODE > 9)
257 System.out.println("Don't care mutated into 0 or 1.");
258 cond[i] = (randChar < 0.5) ? '1' : '0';
259 break;
260 }
261 }
262 }
263 condition = new String(cond);
264 return changed;
265 }
266
267 /**
268 * Mutates the action of the classifier.
269 * <i>Since my actions are <code>String</code>, the mutation is applied for
270 * each allele depending on the constant pM.</i>
271 * @see XCSConstants#pM
272 * @author Benoit Isaac
273 */
274 private boolean mutateAction(int actionLength) {
275 boolean changed = false;
276 char[] act = action.toCharArray();
277
278 for (int i = 0; i < actionLength; i++) {
279 if (ZCSConfig.drand() < ZCSConfig.pM) {
280 // this bit of the action has to change
281 changed = true;
282 if (act[i] == '0') {
283 act[i] = '1';
284 } else {
285 act[i] = '0';
286 }
287 }
288 }
289 if (changed && Config.PRINT_MODE > 4) {
290 System.out.println(
291 "Mutation ! Before:" + action + " After:" + (new String(act)));
292 }
293 action = new String(act);
294
295 return changed;
296 }
297
298 /**
299 * Returns true if the two classifiers are identical in condition and action.
300 *
301 * @param cl The classifier to be compared.
302 */
303 public boolean isIdentical(ZClassifier cl) {
304 if (cl.condition.equals(condition) && cl.action.equals(action))
305 return true;
306 return false;
307 }
308
309
310
311 /**
312 * Prints the classifier to the control panel.
313 * The method prints condition action prediction predictionError fitness numerosity experience actionSetSize timeStamp.
314 */
315 public void printClassifier() {
316 System.out.println(this);
317 }
318
319 /**
320 * Prints the classifier to the print writer (normally referencing a file).
321 * The method prints condition action prediction predictionError fitness numerosity experience actionSetSize timeStamp.
322 *
323 * @param pW The writer to which the classifier is written.
324 */
325 public void printClassifier(PrintWriter pW) {
326 pW.println(this);
327 }
328
329 /**
330 * Return a <code>String</code> describing the XClassifier.
331 * used to show the classifier in the listPanel.
332 */
333 public String toString() {
334 return (super.toString() + "\t Strength:" + (float) strength);
335 }
336 /**
337 * @return
338 */
339 public double getStrength() {
340 return strength;
341 }
342
343 public double getValue(){
344 return getStrength();
345 }
346
347 /**
348 * @param d
349 */
350 public void setStrength(double d) {
351 strength = d;
352 }
353
354 /**
355 * @param d
356 */
357 public void addStrength(double d) {
358 strength += d;
359 }
360
361 /**
362 * Used to build a Comparator to sort the Classifier in order
363 * to show them ranked to the user
364 */
365 public int compareTo(Object o) {
366 ZClassifier z = (ZClassifier) o;
367 if(this.equals(z))
368 return 0;
369 double diff = this.getStrength() - z.getStrength();
370 if(diff != 0)
371 return (diff >0)?1:-1;
372
373 return 1; // by default
374 }
375 }