source: src/main/java/weka/associations/tertius/Rule.java @ 9

Last change on this file since 9 was 4, checked in by gnappo, 14 years ago

Import di weka.

File size: 24.6 KB
Line 
1/*
2 *    This program is free software; you can redistribute it and/or modify
3 *    it under the terms of the GNU General Public License as published by
4 *    the Free Software Foundation; either version 2 of the License, or
5 *    (at your option) any later version.
6 *
7 *    This program is distributed in the hope that it will be useful,
8 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
9 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 *    GNU General Public License for more details.
11 *
12 *    You should have received a copy of the GNU General Public License
13 *    along with this program; if not, write to the Free Software
14 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
15 */
16
17/*
18 *    Rule.java
19 *    Copyright (C) 2003 Peter A. Flach, Nicolas Lachiche
20 *
21 *    Thanks to Amelie Deltour for porting the original C code to Java
22 *    and integrating it into Weka.
23 */
24
25package weka.associations.tertius;
26
27import weka.core.Instance;
28import weka.core.Instances;
29import weka.core.RevisionHandler;
30import weka.core.RevisionUtils;
31
32import java.io.Serializable;
33import java.text.DecimalFormat;
34import java.util.ArrayList;
35import java.util.Comparator;
36import java.util.Enumeration;
37
38/**
39 * Class representing a rule with a body and a head.
40 *
41 * @author  <a href="mailto:adeltour@netcourrier.com">Amelie Deltour</a>
42 * @version $Revision: 1.7 $
43 */
44
45public class Rule
46  implements Serializable, Cloneable, RevisionHandler {
47
48  /** for serialization */
49  private static final long serialVersionUID = -7763378359090435505L;
50
51  /** The body of the rule. */
52  private Body m_body;
53
54  /** The head of the rule. */
55  private Head m_head;
56
57  /** Can repeat predicates in the rule ? */
58  private boolean m_repeatPredicate;
59
60  /** Maximal number of literals in the rule. */
61  private int m_maxLiterals;
62
63  /** Can there be negations in the body ? */
64  private boolean m_negBody;
65
66  /** Can there be negations in the head ? */
67  private boolean m_negHead;
68
69  /** Is this rule a classification rule ? */
70  private boolean m_classRule;
71
72  /** Can there be only one literal in the head ? */
73  private boolean m_singleHead;
74
75  /** Number of instances in the data this rule deals with. */
76  private int m_numInstances;
77
78  /** Set of counter-instances of this rule. */
79  private ArrayList m_counterInstances;
80
81  /** Counter for the counter-instances of this rule. */
82  private int m_counter;
83
84  /** Confirmation of this rule. */
85  private double m_confirmation;
86
87  /** Optimistic estimate of this rule. */
88  private double m_optimistic;
89
90  /**
91   * Constructor for a rule when the counter-instances are not stored,
92   * giving all the constraints applied to this rule.
93   *
94   * @param repeatPredicate True if predicates can be repeated.
95   * @param maxLiterals Maximum number of literals.
96   * @param negBody True if negation is allowed in the body.
97   * @param negHead True if negation is allowed in the head.
98   * @param classRule True if the rule is a classification rule.
99   * @param horn True if the rule is a horn clause.
100   */
101  public Rule(boolean repeatPredicate, int maxLiterals, boolean negBody, 
102      boolean negHead, boolean classRule, boolean horn) {
103
104    m_body = new Body();
105    m_head = new Head();
106    m_repeatPredicate = repeatPredicate;
107    m_maxLiterals = maxLiterals;
108    m_negBody = negBody && !horn;
109    m_negHead = negHead && !horn;
110    m_classRule = classRule;
111    m_singleHead = classRule || horn;
112  }
113
114  /**
115   * Constructor for a rule when the counter-instances are stored,
116   * giving all the constraints applied to this rule.
117   * The counter-instances are initialized to all the instances in the dataset.
118   *
119   * @param instances The dataset.
120   * @param repeatPredicate True if predicates can be repeated.
121   * @param maxLiterals Maximum number of literals.
122   * @param negBody True if negation is allowed in the body.
123   * @param negHead True if negation is allowed in the head.
124   * @param classRule True if the rule is a classification rule.
125   * @param horn True if the rule is a horn clause.
126   */
127  public Rule(Instances instances,
128      boolean repeatPredicate, int maxLiterals, boolean negBody, 
129      boolean negHead, boolean classRule, boolean horn) {
130
131    m_body = new Body(instances);
132    m_head = new Head(instances);
133    m_repeatPredicate = repeatPredicate;
134    m_maxLiterals = maxLiterals;
135    m_negBody = negBody && !horn;
136    m_negHead = negHead && !horn;
137    m_classRule = classRule;
138    m_singleHead = classRule || horn;
139    m_numInstances = instances.numInstances();
140    m_counterInstances = new ArrayList(m_numInstances);
141    Enumeration enu = instances.enumerateInstances();
142    while (enu.hasMoreElements()) {
143      m_counterInstances.add(enu.nextElement());
144    }
145  }
146
147  /**
148   * Returns a shallow copy of this rule.
149   * The structured is copied but the literals themselves are not copied.
150   *
151   * @return A copy of this Rule.
152   */
153  public Object clone() {
154
155    Object result = null;
156    try {
157      result = super.clone();
158      /* Clone the body and the head. */
159      ((Rule) result).m_body = (Body) m_body.clone();
160      ((Rule) result).m_head = (Head) m_head.clone();
161      /* Clone the set of counter-instances. */
162      if (m_counterInstances != null) {
163        ((Rule) result).m_counterInstances
164        = (ArrayList) m_counterInstances.clone();
165      }
166    } catch (Exception e) {
167      /* An exception is not supposed to happen here. */
168      e.printStackTrace();
169      System.exit(0);
170    }
171    return result;
172  }
173
174  /**
175   * Test if an instance is a counter-instance of this rule.
176   *
177   * @param instance The instance to test.
178   * @return True if the instance is a counter-instance.
179   */
180  public boolean counterInstance(Instance instance) {
181
182    return ((m_body.counterInstance(instance) 
183        && m_head.counterInstance(instance)));
184  }
185
186  /**
187   * Update the number of counter-instances of this rule in the dataset.
188   * This method should be used is the rule does not store its counter-instances.
189   *
190   * @param instances The dataset.
191   */
192  public void upDate(Instances instances) {
193
194    Enumeration enu = instances.enumerateInstances();
195    m_numInstances = instances.numInstances();
196    m_counter = 0;
197    while (enu.hasMoreElements()) {
198      if (this.counterInstance((Instance) enu.nextElement())) {
199        m_counter++;
200      }
201    }
202    m_head.upDate(instances);
203    m_body.upDate(instances);
204  }
205
206  /**
207   * Get the confirmation value of this rule.
208   *
209   * @return The confirmation.
210   */
211  public double getConfirmation() {
212
213    return m_confirmation;
214  }
215
216  /**
217   * Get the optimistic estimate of the confirmation obtained by refining
218   * this rule.
219   *
220   * @return The optimistic estimate.
221   */
222  public double getOptimistic() {
223
224    return m_optimistic;
225  }
226
227  /*
228   * Get the expected number of counter-instances of this rule,
229   * calculated from the number of instances satisfying the body and
230   * the number of instances satisfying the negation of the head.
231   *
232   * @return The expected number of counter-instances.
233   */
234  public double getExpectedNumber() {
235
236    return (double) m_body.getCounterInstancesNumber() 
237    * (double) m_head.getCounterInstancesNumber() 
238    / (double) m_numInstances;
239  }
240
241  /**
242   * Get the expected frequency of counter-instances of this rule.
243   *
244   * @return The expected frequency of counter-instances.
245   */
246  public double getExpectedFrequency() {
247
248    return getExpectedNumber() / (double) m_numInstances;
249  }
250
251  /**
252   * Get the observed number of counter-instances of this rule in the dataset.
253   *
254   * @return The observed number of counter-instances.
255   */
256  public int getObservedNumber() {
257
258    if (m_counterInstances != null) {
259      return m_counterInstances.size();
260    } else {
261      return m_counter;
262    }
263  }
264
265  /**
266   * Get the observed frequency of counter-instances of this rule in the dataset.
267   *
268   * @return The expected frequency of counter-instances.
269   */
270  public double getObservedFrequency() {
271
272    return (double) getObservedNumber() / (double) m_numInstances;
273  }
274
275  /**
276   * Get the rate of True Positive instances of this rule.
277   *
278   * @return The TP-rate.
279   */
280  public double getTPRate() {
281
282    int tp = m_body.getCounterInstancesNumber() - getObservedNumber();
283    int fn = m_numInstances - m_head.getCounterInstancesNumber() - tp;
284    return ((double) tp / (double) (tp + fn));
285  }
286
287  /**
288   * Get the rate of False Positive instances of this rule.
289   *
290   * @return The FP-rate.
291   */
292  public double getFPRate() {
293
294    int fp = getObservedNumber();
295    int tn = m_head.getCounterInstancesNumber() - fp;
296    return ((double) fp / (double) (fp + tn));
297  }
298
299  /**
300   * Calculate the confirmation of this rule.
301   */
302  public void calculateConfirmation() {
303
304    double expected = getExpectedFrequency();
305    double observed = getObservedFrequency();
306    if ((expected == 0) || (expected == 1)) {
307      m_confirmation = 0;
308    } else {
309      m_confirmation = (expected - observed) / (Math.sqrt(expected) - expected);
310    }
311  }
312
313  /**
314   * Calculate the optimistic estimate of this rule.
315   */
316  public void calculateOptimistic() {
317
318    int counterInstances = this.getObservedNumber();
319    int body = m_body.getCounterInstancesNumber();
320    int notHead = m_head.getCounterInstancesNumber();
321    int n = m_numInstances;
322    double expectedOptimistic;
323    /* optimistic expected number of counter-instances */
324    if (counterInstances <= body - notHead) {
325      expectedOptimistic = (double) (notHead * (body - counterInstances)) 
326      / (double) (n * n);
327    } else if (counterInstances <= notHead - body) {
328      expectedOptimistic = (double) (body * (notHead - counterInstances)) 
329      / (double) (n * n);
330    } else {
331      expectedOptimistic = (double) ((notHead + body - counterInstances)
332          * (notHead + body - counterInstances)) 
333          / (double) (4 * n * n);
334    }
335    if ((expectedOptimistic == 0) || (expectedOptimistic == 1)) {
336      m_optimistic = 0;
337    } else {
338      m_optimistic = expectedOptimistic
339      / (Math.sqrt(expectedOptimistic) - expectedOptimistic);
340    }
341  }
342
343  /**
344   * Test if this rule is empty.
345   *
346   * @return True if it is the empty rule.
347   */
348  public boolean isEmpty() {
349
350    return (m_head.isEmpty() && m_body.isEmpty());
351  }
352
353  /**
354   * Give the number of literals in this rule.
355   *
356   * @return The number of literals.
357   */
358  public int numLiterals() {
359
360    return m_body.numLiterals() + m_head.numLiterals();
361  }
362
363  /**
364   * Add a literal to the body of the rule.
365   *
366   * @param newLit The literal to add.
367   * @return The rule obtained by adding the literal, null if the literal can
368   * not be added because of the constraints on the rule.
369   */
370  private Rule addTermToBody(Literal newLit) {
371
372    if (!m_negBody && newLit.negative()
373        || (m_classRule && newLit.getPredicate().isClass())
374        || (newLit instanceof IndividualLiteral
375            && (((IndividualLiteral) newLit).getType() 
376                - m_body.getType()) > 1
377                && (((IndividualLiteral) newLit).getType() 
378                    - m_head.getType()) > 1)) {
379      return null;
380    } else {
381      Rule result = (Rule) this.clone();
382      result.m_body.addElement(newLit);
383      /* Update the counter-instances. */
384      if (m_counterInstances != null) {
385        for (int i = result.m_counterInstances.size() - 1; i >= 0; i--) {
386          Instance current = (Instance) result.m_counterInstances.get(i);
387          if (!result.m_body.canKeep(current, newLit)) {
388            result.m_counterInstances.remove(i);
389          }
390        }
391      }
392      return result;
393    }
394  }
395
396  /**
397   * Add a literal to the head of the rule.
398   *
399   * @param newLit The literal to add.
400   * @return The rule obtained by adding the literal, null if the literal can
401   * not be added because of the constraints on the rule.
402   */
403  private Rule addTermToHead(Literal newLit) {
404    if ((!m_negHead && newLit.negative())
405        || (m_classRule && !newLit.getPredicate().isClass()) 
406        || (m_singleHead && !m_head.isEmpty())
407        || (newLit instanceof IndividualLiteral
408            && ((IndividualLiteral) newLit).getType() 
409            != IndividualLiteral.INDIVIDUAL_PROPERTY)) {
410      return null;
411    } else { 
412      Rule result = (Rule) this.clone();
413      result.m_head.addElement(newLit);
414      /* Update counter-instances. */
415      if (m_counterInstances != null) {
416        for (int i = result.m_counterInstances.size() - 1; i >= 0; i--) {
417          Instance current = (Instance) result.m_counterInstances.get(i);
418          if (!result.m_head.canKeep(current, newLit)) {
419            result.m_counterInstances.remove(i);
420          }
421        }
422      }
423      return result;
424    }
425  }
426
427  /**
428   * Refine a rule by adding a range of literals of a predicate, either to
429   * the head or to the body of the rule.
430   *
431   * @param pred The predicate to consider.
432   * @param firstIndex The index of the first literal of the predicate to add.
433   * @param lastIndex The index of the last literal of the predicate to add.
434   * @param addTobody True if the literals should be added to the body.
435   * @param addToHead True if the literals should be added to the head.
436   * @return A list of rules obtained by refinement.
437   */
438  private SimpleLinkedList refine(Predicate pred, int firstIndex, int lastIndex, 
439      boolean addToBody, boolean addToHead) {
440
441    SimpleLinkedList result = new SimpleLinkedList();
442    Literal currentLit;
443    Literal negation;
444    Rule refinement;
445    for (int i = firstIndex; i < lastIndex; i++) {
446      currentLit = pred.getLiteral(i);
447      if (addToBody) {
448        refinement = addTermToBody(currentLit);
449        if (refinement != null) {
450          result.add(refinement);
451        }
452      }
453      if (addToHead) {
454        refinement = addTermToHead(currentLit);
455        if (refinement != null) {
456          result.add(refinement);
457        }
458      }
459      negation = currentLit.getNegation();
460      if (negation != null) {
461        if (addToBody) {
462          refinement = addTermToBody(negation);
463          if (refinement != null) {
464            result.add(refinement);
465          }
466        }
467        if (addToHead) {
468          refinement = addTermToHead(negation);
469          if (refinement != null) {
470            result.add(refinement);
471          }
472        }
473      }
474    }
475    return result;
476  }
477
478  /**
479   * Refine a rule by adding literal from a set of predictes.
480   *
481   * @param predicates The predicates available.
482   * @return The list of the children obtained by refining the rule.
483   */
484  public SimpleLinkedList refine(ArrayList predicates) {
485
486    SimpleLinkedList result = new SimpleLinkedList();
487    Predicate currentPred;
488    boolean addToBody;
489    boolean addToHead;
490
491    if (this.numLiterals() == m_maxLiterals) {
492      return result;
493    }
494
495    if (this.isEmpty()) {
496      /* Literals can be added on both sides of the rule. */
497      for (int i = 0; i < predicates.size(); i++) {
498        currentPred = (Predicate) predicates.get(i);
499        result.addAll(refine(currentPred,
500            0, currentPred.numLiterals(),
501            true, true));
502      }
503    } else if (m_body.isEmpty() || m_head.isEmpty()) {
504      /* Literals can be added to the empty side only. */
505      LiteralSet side;
506      Literal last;
507      if (m_body.isEmpty()) {
508        side = m_head;
509        addToBody = true;
510        addToHead = false;
511      } else { // m_head.isEmpty()
512        side = m_body;
513        addToBody = false;
514        addToHead = true;
515      }
516      last = side.getLastLiteral();
517      currentPred = last.getPredicate();
518      if (m_repeatPredicate) {
519        result.addAll(refine(currentPred,
520            currentPred.indexOf(last) + 1, 
521            currentPred.numLiterals(),
522            addToBody, addToHead));
523      }
524      for (int i = predicates.indexOf(currentPred) + 1; i < predicates.size(); 
525      i++) {
526        currentPred = (Predicate) predicates.get(i);
527        result.addAll(refine(currentPred,
528            0, currentPred.numLiterals(),
529            addToBody, addToHead));             
530      }
531    } else {
532      Literal lastLitBody = m_body.getLastLiteral();
533      Literal lastLitHead = m_head.getLastLiteral();
534      Predicate lastPredBody = lastLitBody.getPredicate();
535      Predicate lastPredHead = lastLitHead.getPredicate();
536      int lastLitBodyIndex = lastPredBody.indexOf(lastLitBody);
537      int lastLitHeadIndex = lastPredHead.indexOf(lastLitHead);
538      int lastPredBodyIndex = predicates.indexOf(lastPredBody);
539      int lastPredHeadIndex = predicates.indexOf(lastPredHead);
540      Predicate inferiorPred;
541      Predicate superiorPred;
542      int inferiorLit;
543      int superiorLit;
544      addToBody = (m_head.numLiterals() == 1
545          && (lastPredBodyIndex < lastPredHeadIndex
546              || (lastPredBodyIndex == lastPredHeadIndex
547                  && lastLitBodyIndex < lastLitHeadIndex)));
548      addToHead = (m_body.numLiterals() == 1
549          && (lastPredHeadIndex < lastPredBodyIndex
550              || (lastPredHeadIndex == lastPredBodyIndex
551                  && lastLitHeadIndex < lastLitBodyIndex)));     
552      if (addToBody || addToHead) {
553        /* Add literals in the gap between the body and the head. */
554        if (addToBody) {
555          inferiorPred = lastPredBody;
556          inferiorLit = lastLitBodyIndex;
557          superiorPred = lastPredHead;
558          superiorLit = lastLitHeadIndex;
559        } else { // addToHead
560          inferiorPred = lastPredHead;
561          inferiorLit = lastLitHeadIndex;
562          superiorPred = lastPredBody;
563          superiorLit = lastLitBodyIndex;
564        }
565        if (predicates.indexOf(inferiorPred) 
566            < predicates.indexOf(superiorPred)) {
567          if (m_repeatPredicate) {
568            result.addAll(refine(inferiorPred, 
569                inferiorLit + 1, inferiorPred.numLiterals(),
570                addToBody, addToHead));
571          }
572          for (int j = predicates.indexOf(inferiorPred) + 1; 
573          j < predicates.indexOf(superiorPred); j++) {
574            currentPred = (Predicate) predicates.get(j);
575            result.addAll(refine(currentPred,
576                0, currentPred.numLiterals(),
577                addToBody, addToHead));
578          }
579          if (m_repeatPredicate) {
580            result.addAll(refine(superiorPred,
581                0, superiorLit,
582                addToBody, addToHead));
583          }
584        } else { 
585          //((inferiorPred.getIndex() == superiorPred.getIndex())
586          //&& (inferiorLit < superiorLit))
587          if (m_repeatPredicate) {
588            result.addAll(refine(inferiorPred,
589                inferiorLit + 1, superiorLit,
590                addToBody, addToHead));
591          }
592        }       
593      } 
594      /* Add other literals. */
595      if (predicates.indexOf(lastPredBody) > predicates.indexOf(lastPredHead)) {
596        superiorPred = lastPredBody;
597        superiorLit = lastPredBody.indexOf(lastLitBody);
598      } else if (predicates.indexOf(lastPredBody) 
599          < predicates.indexOf(lastPredHead)) {
600        superiorPred = lastPredHead;
601        superiorLit = lastPredHead.indexOf(lastLitHead);
602      } else {
603        superiorPred = lastPredBody;
604        if (lastLitBodyIndex > lastLitHeadIndex) {
605          superiorLit = lastPredBody.indexOf(lastLitBody);
606        } else {
607          superiorLit = lastPredHead.indexOf(lastLitHead);
608        }
609      }
610      if (m_repeatPredicate) {
611        result.addAll(refine(superiorPred,
612            superiorLit + 1, superiorPred.numLiterals(),
613            true, true));
614      }
615      for (int j = predicates.indexOf(superiorPred) + 1; j < predicates.size(); 
616      j++) {
617        currentPred = (Predicate) predicates.get(j);
618        result.addAll(refine(currentPred,
619            0, currentPred.numLiterals(),
620            true, true));
621      }
622    }
623    return result;
624  }
625
626  /**
627   * Test if this rule subsumes another rule.
628   *
629   * @param otherRule The other rule.
630   * @return True if the other rule is subsumed.
631   */
632  public boolean subsumes(Rule otherRule) {   
633
634    if (this.numLiterals() > otherRule.numLiterals()) {
635      return false;
636    }
637    return (m_body.isIncludedIn(otherRule) && m_head.isIncludedIn(otherRule));
638  }
639
640  /**
641   * Test if this rule and another rule correspond to the same clause.
642   *
643   * @param otherRule The other rule.
644   * @return True if both rules correspond to the same clause.
645   */
646  public boolean sameClauseAs(Rule otherRule) {
647
648    return (this.numLiterals() == otherRule.numLiterals()
649        && this.subsumes(otherRule));
650  }
651
652  /**
653   * Test if this rule is equivalent to another rule.
654   *
655   * @param otherRule The other rule.
656   * @return True if both rules are equivalent.
657   */
658  public boolean equivalentTo(Rule otherRule) {
659
660    return (this.numLiterals() == otherRule.numLiterals()
661        && m_head.negationIncludedIn(otherRule.m_body)
662        && m_body.negationIncludedIn(otherRule.m_head));
663  }
664
665  /**
666   * Test if the body of the rule contains a literal.
667   *
668   * @param lit The literal to look for.
669   * @return True if the literal is contained in the body of the rule.
670   */
671  public boolean bodyContains(Literal lit) {
672
673    return m_body.contains(lit);
674  }
675
676  /**
677   * Test if the head of the rule contains a literal.
678   *
679   * @param lit The literal to look for.
680   * @return True if the literal is contained in the head of the rule.
681   */
682  public boolean headContains(Literal lit) {
683
684    return m_head.contains(lit);
685  }
686
687  /**
688   * Test if this rule is over the frequency threshold.
689   *
690   * @param minFrequency The frequency threshold.
691   * @return True if the rule is over the threshold.
692   */
693  public boolean overFrequencyThreshold(double minFrequency) {
694
695    return (m_body.overFrequencyThreshold(minFrequency) 
696        && m_head.overFrequencyThreshold(minFrequency));
697  }
698
699  /**
700   * Test if the body of the rule is true.
701   *
702   * @return True if the body is always satisfied.
703   */
704  public boolean hasTrueBody() {
705
706    return (!m_body.isEmpty()
707        && m_body.hasMaxCounterInstances());
708  }
709
710  /**
711   * Test if the head of the rule is false.
712   *
713   * @return True if the body is never satisfied.
714   */
715  public boolean hasFalseHead() {
716
717    return (!m_head.isEmpty()
718        && m_head.hasMaxCounterInstances());
719  }
720
721  /**
722   * Return a String giving the confirmation and optimistic estimate of
723   * this rule.
724   *
725   * @return A String with the values of the rule.
726   */
727  public String valuesToString() {
728
729    StringBuffer text = new StringBuffer();
730    DecimalFormat decimalFormat = new DecimalFormat("0.000000");
731    text.append(decimalFormat.format(getConfirmation()));
732    text.append(" ");
733    text.append(decimalFormat.format(getObservedFrequency()));
734    return text.toString();
735  }
736
737  /**
738   * Return a String giving the TP-rate and FP-rate of
739   * this rule.
740   *
741   * @return A String with the values of the rule.
742   */
743  public String rocToString() {
744
745    StringBuffer text = new StringBuffer();
746    DecimalFormat decimalFormat = new DecimalFormat("0.000000");
747    text.append(decimalFormat.format(getConfirmation()));
748    text.append(" ");
749    text.append(decimalFormat.format(getTPRate()));
750    text.append(" ");
751    text.append(decimalFormat.format(getFPRate()));
752    return text.toString();
753  }
754
755  /**
756   * Retrun a String for this rule.
757   *
758   * @return The String describing this rule.
759   */
760  public String toString() {
761
762    StringBuffer text = new StringBuffer();
763    text.append(m_body.toString());
764    text.append(" ==> ");
765    text.append(m_head.toString());
766    return text.toString();
767  }
768
769  /**
770   * Comparator used to compare two rules according to their confirmation value.
771   */
772  public static Comparator confirmationComparator = new Comparator() {
773
774    public int compare(Object o1, Object o2) {
775
776      Rule r1 = (Rule) o1;
777      Rule r2 = (Rule) o2;
778      double conf1 = r1.getConfirmation();
779      double conf2 = r2.getConfirmation();
780      if (conf1 > conf2) {
781        return -1;
782      } else if (conf1 < conf2) {
783        return 1;
784      } else {
785        return 0;
786      }
787    }
788  };
789
790  /**
791   * Comparator used to compare two rules according to their observed number
792   * of counter-instances.
793   */
794  public static Comparator observedComparator = new Comparator() {
795
796    public int compare(Object o1, Object o2) {
797
798      Rule r1 = (Rule) o1;
799      Rule r2 = (Rule) o2;
800      double obs1 = r1.getObservedFrequency();
801      double obs2 = r2.getObservedFrequency();
802      if (obs1 < obs2) {
803        return -1;
804      } else if (obs1 > obs2) {
805        return 1;
806      } else {
807        return 0;
808      }
809    }
810  };
811
812  /**
813   * Comparator used to compare two rules according to their optimistic estimate.
814   */
815  public static Comparator optimisticComparator = new Comparator() {
816
817    public int compare(Object o1, Object o2) {
818
819      Rule r1 = (Rule) o1;
820      Rule r2 = (Rule) o2;
821      double opt1 = r1.getOptimistic();
822      double opt2 = r2.getOptimistic();
823      if (opt1 > opt2) {
824        return -1;
825      } else if (opt1 < opt2) {
826        return 1;
827      } else {
828        return 0;
829      }
830    }
831  };
832
833  /**
834   * Comparator used to compare two rules according to their confirmation and
835   * then their observed number of counter-instances.
836   */
837  public static Comparator confirmationThenObservedComparator = new Comparator() {
838    public int compare(Object o1, Object o2) {
839
840      int confirmationComparison = confirmationComparator.compare(o1, o2);
841      if (confirmationComparison != 0) {
842        return confirmationComparison;
843      } else {
844        return observedComparator.compare(o1, o2);
845      }
846    }
847  };
848
849  /**
850   * Comparator used to compare two rules according to their optimistic estimate
851   * and then their observed number of counter-instances.
852   */
853  public static Comparator optimisticThenObservedComparator = new Comparator() {
854    public int compare(Object o1, Object o2) {
855      int optimisticComparison = optimisticComparator.compare(o1, o2);
856      if (optimisticComparison != 0) {
857        return optimisticComparison;
858      } else {
859        return observedComparator.compare(o1, o2);
860      }
861    }
862  };
863
864  /**
865   * Returns the revision string.
866   *
867   * @return            the revision
868   */
869  public String getRevision() {
870    return RevisionUtils.extract("$Revision: 1.7 $");
871  }
872}
Note: See TracBrowser for help on using the repository browser.