http://git-wip-us.apache.org/repos/asf/incubator-samoa/blob/23a35dbe/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/LearningRule.java
----------------------------------------------------------------------
diff --git 
a/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/LearningRule.java
 
b/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/LearningRule.java
index 4c05632..b380ae8 100644
--- 
a/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/LearningRule.java
+++ 
b/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/LearningRule.java
@@ -28,95 +28,95 @@ import com.yahoo.labs.samoa.moa.core.StringUtils;
  * Rule with LearningNode (statistical data).
  * 
  * @author Anh Thu Vu
- *
+ * 
  */
 public abstract class LearningRule extends Rule {
 
-       /**
+  /**
         * 
         */
-       private static final long serialVersionUID = 1L;
-       
-       /*
-        * Constructor
-        */
-       public LearningRule() {
-               super();
-       }
-       
-       /*
-        * LearningNode
-        */
-       public abstract RuleRegressionNode getLearningNode();
+  private static final long serialVersionUID = 1L;
 
-       public abstract void setLearningNode(RuleRegressionNode learningNode);
-       
-       /*
-        * No. of instances seen
-        */
-       public long getInstancesSeen() {
-               return this.getLearningNode().getInstancesSeen();
-       }
+  /*
+   * Constructor
+   */
+  public LearningRule() {
+    super();
+  }
 
-       /*
-        * Error and change detection
-        */
-       public double computeError(Instance instance) {
-               return this.getLearningNode().computeError(instance);
-       }
+  /*
+   * LearningNode
+   */
+  public abstract RuleRegressionNode getLearningNode();
 
+  public abstract void setLearningNode(RuleRegressionNode learningNode);
 
-       /*
-        * Prediction
-        */
-       public double[] getPrediction(Instance instance, int mode) {
-               return this.getLearningNode().getPrediction(instance, mode);
-       }
-
-       public double[] getPrediction(Instance instance) {
-               return this.getLearningNode().getPrediction(instance);
-       }
-       
-       public double getCurrentError() {
-               return this.getLearningNode().getCurrentError();
-       }
-       
-       /*
-        * Anomaly detection
-        */
-       public boolean isAnomaly(Instance instance,
-                       double uniVariateAnomalyProbabilityThreshold,
-                       double multiVariateAnomalyProbabilityThreshold,
-                       int numberOfInstanceesForAnomaly) {
-               return this.getLearningNode().isAnomaly(instance, 
uniVariateAnomalyProbabilityThreshold,
-                               multiVariateAnomalyProbabilityThreshold,
-                               numberOfInstanceesForAnomaly);
-       }
-       
-       /*
-        * Update
-        */
-       public void updateStatistics(Instance instance) {
-               this.getLearningNode().updateStatistics(instance);
-       }
-       
-       public String printRule() {
-               StringBuilder out = new StringBuilder();
-               int indent = 1;
-               StringUtils.appendIndented(out, indent, "Rule Nr." + 
this.ruleNumberID + " Instances seen:" + 
this.getLearningNode().getInstancesSeen() + "\n"); // AC
-               for (RuleSplitNode node : nodeList) {
-                       StringUtils.appendIndented(out, indent, 
node.getSplitTest().toString());
-                       StringUtils.appendIndented(out, indent, " ");
-                       StringUtils.appendIndented(out, indent, 
node.toString());
-               }
-               DoubleVector pred = new 
DoubleVector(this.getLearningNode().getSimplePrediction());
-               StringUtils.appendIndented(out, 0, " --> y: " + 
pred.toString());
-               StringUtils.appendNewline(out);
-
-               if(getLearningNode().perceptron!=null){
-                       
((RuleActiveRegressionNode)this.getLearningNode()).perceptron.getModelDescription(out,0);
-                       StringUtils.appendNewline(out);
-               }
-               return(out.toString());
-       }
+  /*
+   * No. of instances seen
+   */
+  public long getInstancesSeen() {
+    return this.getLearningNode().getInstancesSeen();
+  }
+
+  /*
+   * Error and change detection
+   */
+  public double computeError(Instance instance) {
+    return this.getLearningNode().computeError(instance);
+  }
+
+  /*
+   * Prediction
+   */
+  public double[] getPrediction(Instance instance, int mode) {
+    return this.getLearningNode().getPrediction(instance, mode);
+  }
+
+  public double[] getPrediction(Instance instance) {
+    return this.getLearningNode().getPrediction(instance);
+  }
+
+  public double getCurrentError() {
+    return this.getLearningNode().getCurrentError();
+  }
+
+  /*
+   * Anomaly detection
+   */
+  public boolean isAnomaly(Instance instance,
+      double uniVariateAnomalyProbabilityThreshold,
+      double multiVariateAnomalyProbabilityThreshold,
+      int numberOfInstanceesForAnomaly) {
+    return this.getLearningNode().isAnomaly(instance, 
uniVariateAnomalyProbabilityThreshold,
+        multiVariateAnomalyProbabilityThreshold,
+        numberOfInstanceesForAnomaly);
+  }
+
+  /*
+   * Update
+   */
+  public void updateStatistics(Instance instance) {
+    this.getLearningNode().updateStatistics(instance);
+  }
+
+  public String printRule() {
+    StringBuilder out = new StringBuilder();
+    int indent = 1;
+    StringUtils.appendIndented(out, indent, "Rule Nr." + this.ruleNumberID + " 
Instances seen:"
+        + this.getLearningNode().getInstancesSeen() + "\n"); // AC
+    for (RuleSplitNode node : nodeList) {
+      StringUtils.appendIndented(out, indent, node.getSplitTest().toString());
+      StringUtils.appendIndented(out, indent, " ");
+      StringUtils.appendIndented(out, indent, node.toString());
+    }
+    DoubleVector pred = new 
DoubleVector(this.getLearningNode().getSimplePrediction());
+    StringUtils.appendIndented(out, 0, " --> y: " + pred.toString());
+    StringUtils.appendNewline(out);
+
+    if (getLearningNode().perceptron != null) {
+      ((RuleActiveRegressionNode) 
this.getLearningNode()).perceptron.getModelDescription(out, 0);
+      StringUtils.appendNewline(out);
+    }
+    return (out.toString());
+  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-samoa/blob/23a35dbe/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/NonLearningRule.java
----------------------------------------------------------------------
diff --git 
a/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/NonLearningRule.java
 
b/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/NonLearningRule.java
index df5b9f9..7679dc3 100644
--- 
a/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/NonLearningRule.java
+++ 
b/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/NonLearningRule.java
@@ -24,28 +24,28 @@ package 
com.yahoo.labs.samoa.learners.classifiers.rules.common;
  * The most basic rule: inherit from Rule the ID and list of features.
  * 
  * @author Anh Thu Vu
- *
+ * 
  */
 /*
  * This branch (Non-learning rule) was created for an old implementation.
- * Probably should remove None-Learning and Learning Rule classes,
- * merge Rule with LearningRule.
+ * Probably should remove None-Learning and Learning Rule classes, merge Rule
+ * with LearningRule.
  */
 public class NonLearningRule extends Rule {
 
-       /**
+  /**
         * 
         */
-       private static final long serialVersionUID = -1210907339230307784L;
+  private static final long serialVersionUID = -1210907339230307784L;
 
-       public NonLearningRule(ActiveRule rule) {
-               this.nodeList = rule.nodeList;
-               this.ruleNumberID = rule.ruleNumberID;
-       }
+  public NonLearningRule(ActiveRule rule) {
+    this.nodeList = rule.nodeList;
+    this.ruleNumberID = rule.ruleNumberID;
+  }
 
-       @Override
-       public void getDescription(StringBuilder sb, int indent) {
-               // do nothing
-       }
+  @Override
+  public void getDescription(StringBuilder sb, int indent) {
+    // do nothing
+  }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-samoa/blob/23a35dbe/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/PassiveRule.java
----------------------------------------------------------------------
diff --git 
a/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/PassiveRule.java
 
b/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/PassiveRule.java
index 8281d45..f49d0d9 100644
--- 
a/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/PassiveRule.java
+++ 
b/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/PassiveRule.java
@@ -23,49 +23,49 @@ package 
com.yahoo.labs.samoa.learners.classifiers.rules.common;
 import java.util.LinkedList;
 
 /**
- * PassiveRule is a LearningRule that update its LearningNode
- * with the received new LearningNode.
+ * PassiveRule is a LearningRule that update its LearningNode with the received
+ * new LearningNode.
  * 
  * @author Anh Thu Vu
- *
+ * 
  */
 public class PassiveRule extends LearningRule {
 
-       /**
+  /**
         * 
         */
-       private static final long serialVersionUID = -5551571895910530275L;
-       
-       private RulePassiveRegressionNode learningNode;
+  private static final long serialVersionUID = -5551571895910530275L;
 
-       /*
-        * Constructor to turn an ActiveRule into a PassiveRule
-        */
-       public PassiveRule(ActiveRule rule) {
-               this.nodeList = new LinkedList<>();
-               for (RuleSplitNode node:rule.nodeList) {
-                       this.nodeList.add(node.getACopy());
-               }
-               
-               this.learningNode = new 
RulePassiveRegressionNode(rule.getLearningNode());
-               this.ruleNumberID = rule.ruleNumberID;
-       }
-       
-       @Override
-       public RuleRegressionNode getLearningNode() {
-               return this.learningNode;
-       }
+  private RulePassiveRegressionNode learningNode;
 
-       @Override
-       public void setLearningNode(RuleRegressionNode learningNode) {
-               this.learningNode = (RulePassiveRegressionNode) learningNode;
-       }
-       
-       /*
-        * MOA GUI
-        */
-       @Override
-       public void getDescription(StringBuilder sb, int indent) {
-               // TODO Auto-generated method stub
-       }
+  /*
+   * Constructor to turn an ActiveRule into a PassiveRule
+   */
+  public PassiveRule(ActiveRule rule) {
+    this.nodeList = new LinkedList<>();
+    for (RuleSplitNode node : rule.nodeList) {
+      this.nodeList.add(node.getACopy());
+    }
+
+    this.learningNode = new RulePassiveRegressionNode(rule.getLearningNode());
+    this.ruleNumberID = rule.ruleNumberID;
+  }
+
+  @Override
+  public RuleRegressionNode getLearningNode() {
+    return this.learningNode;
+  }
+
+  @Override
+  public void setLearningNode(RuleRegressionNode learningNode) {
+    this.learningNode = (RulePassiveRegressionNode) learningNode;
+  }
+
+  /*
+   * MOA GUI
+   */
+  @Override
+  public void getDescription(StringBuilder sb, int indent) {
+    // TODO Auto-generated method stub
+  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-samoa/blob/23a35dbe/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/Perceptron.java
----------------------------------------------------------------------
diff --git 
a/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/Perceptron.java
 
b/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/Perceptron.java
index 53583ed..463dcdf 100644
--- 
a/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/Perceptron.java
+++ 
b/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/Perceptron.java
@@ -33,455 +33,458 @@ import com.yahoo.labs.samoa.moa.core.DoubleVector;
 import com.yahoo.labs.samoa.moa.core.Measurement;
 
 /**
- * Prediction scheme using Perceptron:
- * Predictions are computed according to a linear function of the attributes.
+ * Prediction scheme using Perceptron: Predictions are computed according to a
+ * linear function of the attributes.
  * 
  * @author Anh Thu Vu
- *
+ * 
  */
 public class Perceptron extends AbstractClassifier implements Regressor {
 
-       private final double SD_THRESHOLD = 0.0000001; //THRESHOLD for 
normalizing attribute and target values
-
-       private static final long serialVersionUID = 1L;
-
-       //      public FlagOption constantLearningRatioDecayOption = new 
FlagOption(
-       //                      "learningRatio_Decay_set_constant", 'd',
-       //                      "Learning Ratio Decay in Perceptron set to be 
constant. (The next parameter).");
-       //
-       //      public FloatOption learningRatioOption = new FloatOption(
-       //                      "learningRatio", 'l', 
-       //                      "Constante Learning Ratio to use for training 
the Perceptrons in the leaves.", 0.01);
-       //
-       //      public FloatOption learningRateDecayOption = new FloatOption(
-       //                      "learningRateDecay", 'm', 
-       //                      " Learning Rate decay to use for training the 
Perceptron.", 0.001);
-       //
-       //      public FloatOption fadingFactorOption = new FloatOption(
-       //                      "fadingFactor", 'e', 
-       //                      "Fading factor for the Perceptron accumulated 
error", 0.99, 0, 1);
-
-       protected boolean constantLearningRatioDecay;
-       protected double originalLearningRatio;
-
-       private double nError;
-       protected double fadingFactor = 0.99;
-       private double learningRatio;
-       protected double learningRateDecay = 0.001;
-
-       // The Perception weights 
-       protected double[] weightAttribute; 
-
-       // Statistics used for error calculations
-       public DoubleVector perceptronattributeStatistics = new DoubleVector();
-       public DoubleVector squaredperceptronattributeStatistics = new 
DoubleVector();
-
-       // The number of instances contributing to this model
-       protected int perceptronInstancesSeen;
-       protected int perceptronYSeen;
-
-       protected double accumulatedError;
-
-       // If the model  (weights) should be reset or not
-       protected boolean initialisePerceptron; 
-
-       protected double perceptronsumY;
-       protected double squaredperceptronsumY;
-
-
-       public Perceptron() {
-               this.initialisePerceptron = true;
-       }
-
-       /*
-        * Perceptron
-        */
-       public Perceptron(Perceptron p) {
-               this(p,false);
-       }
-       
-       public Perceptron(Perceptron p, boolean copyAccumulatedError) {
-               super();
-               //              this.constantLearningRatioDecayOption = 
p.constantLearningRatioDecayOption;
-               //        this.learningRatioOption = p.learningRatioOption;
-               //        
this.learningRateDecayOption=p.learningRateDecayOption;
-               //        this.fadingFactorOption = p.fadingFactorOption;
-               this.constantLearningRatioDecay = p.constantLearningRatioDecay;
-               this.originalLearningRatio = p.originalLearningRatio;
-               if (copyAccumulatedError)
-                       this.accumulatedError = p.accumulatedError;
-               this.nError = p.nError;
-               this.fadingFactor = p.fadingFactor;
-               this.learningRatio = p.learningRatio;
-               this.learningRateDecay = p.learningRateDecay;
-               if (p.weightAttribute!=null)
-                       this.weightAttribute = p.weightAttribute.clone();
-
-               this.perceptronattributeStatistics = new 
DoubleVector(p.perceptronattributeStatistics);
-               this.squaredperceptronattributeStatistics = new 
DoubleVector(p.squaredperceptronattributeStatistics);
-               this.perceptronInstancesSeen = p.perceptronInstancesSeen;
-
-               this.initialisePerceptron = p.initialisePerceptron;
-               this.perceptronsumY = p.perceptronsumY;
-               this.squaredperceptronsumY = p.squaredperceptronsumY;
-               this.perceptronYSeen=p.perceptronYSeen;
-       }
-       
-       public Perceptron(PerceptronData p) {
-               super();
-               this.constantLearningRatioDecay = p.constantLearningRatioDecay;
-               this.originalLearningRatio = p.originalLearningRatio;
-               this.nError = p.nError;
-               this.fadingFactor = p.fadingFactor;
-               this.learningRatio = p.learningRatio;
-               this.learningRateDecay = p.learningRateDecay;
-               if (p.weightAttribute!=null)
-                       this.weightAttribute = p.weightAttribute.clone();
-
-               this.perceptronattributeStatistics = new 
DoubleVector(p.perceptronattributeStatistics);
-               this.squaredperceptronattributeStatistics = new 
DoubleVector(p.squaredperceptronattributeStatistics);
-               this.perceptronInstancesSeen = p.perceptronInstancesSeen;
-
-               this.initialisePerceptron = p.initialisePerceptron;
-               this.perceptronsumY = p.perceptronsumY;
-               this.squaredperceptronsumY = p.squaredperceptronsumY;
-               this.perceptronYSeen=p.perceptronYSeen;
-               this.accumulatedError = p.accumulatedError;
-       }
-
-       //      private void printPerceptron() {
-       //              System.out.println("Learning 
Ratio:"+this.learningRatio+" ("+this.originalLearningRatio+")");
-       //              System.out.println("Constant Learning Ratio 
Decay:"+this.constantLearningRatioDecay+" ("+this.learningRateDecay+")");
-       //              
System.out.println("Error:"+this.accumulatedError+"/"+this.nError);
-       //              System.out.println("Fading factor:"+this.fadingFactor);
-       //              System.out.println("Perceptron 
Y:"+this.perceptronsumY+"/"+this.squaredperceptronsumY+"/"+this.perceptronYSeen);
-       //      }
-
-       /*
-        * Weights
-        */
-       public void setWeights(double[] w) {
-               this.weightAttribute = w;           
-       }
-
-       public double[] getWeights() {
-               return this.weightAttribute;        
-       }
-
-       /*
-        * No. of instances seen
-        */
-       public int getInstancesSeen() {
-               return perceptronInstancesSeen;
-       }
-
-       public void setInstancesSeen(int pInstancesSeen) {
-               this.perceptronInstancesSeen = pInstancesSeen;
-       }
-
-       /**
-        * A method to reset the model
-        */
-       public void resetLearningImpl() {
-               this.initialisePerceptron = true; 
-               this.reset(); 
-       }
-
-       public void reset(){
-               this.nError=0.0;
-               this.accumulatedError = 0.0;
-               this.perceptronInstancesSeen = 0;       
-               this.perceptronattributeStatistics = new DoubleVector();
-               this.squaredperceptronattributeStatistics = new DoubleVector();
-               this.perceptronsumY = 0.0;
-               this.squaredperceptronsumY = 0.0;
-               this.perceptronYSeen=0;
-       }
-
-       public void resetError(){
-               this.nError=0.0;
-               this.accumulatedError = 0.0;
-       }
-
-       /**
-        * Update the model using the provided instance
-        */
-       public void trainOnInstanceImpl(Instance inst) {
-               accumulatedError= 
Math.abs(this.prediction(inst)-inst.classValue()) + 
fadingFactor*accumulatedError;
-               nError=1+fadingFactor*nError;
-               // Initialise Perceptron if necessary   
-               if (this.initialisePerceptron) {
-                       //this.fadingFactor=this.fadingFactorOption.getValue();
-                       
//this.classifierRandom.setSeed(randomSeedOption.getValue());
-                       this.classifierRandom.setSeed(randomSeed);
-                       this.initialisePerceptron = false; // not in 
resetLearningImpl() because it needs Instance!
-                       this.weightAttribute = new double[inst.numAttributes()];
-                       for (int j = 0; j < inst.numAttributes(); j++) {
-                               weightAttribute[j] = 2 * 
this.classifierRandom.nextDouble() - 1;
-                       }
-                       // Update Learning Rate
-                       learningRatio = originalLearningRatio;
-                       //this.learningRateDecay = 
learningRateDecayOption.getValue();
-
-               }
-
-               // Update attribute statistics
-               this.perceptronInstancesSeen++;
-               this.perceptronYSeen++;
-
-
-               for(int j = 0; j < inst.numAttributes() -1; j++)
-               {
-                       perceptronattributeStatistics.addToValue(j, 
inst.value(j));     
-                       squaredperceptronattributeStatistics.addToValue(j, 
inst.value(j)*inst.value(j));
-               }
-               this.perceptronsumY += inst.classValue();
-               this.squaredperceptronsumY += inst.classValue() * 
inst.classValue();
-
-               if(!constantLearningRatioDecay){
-                       learningRatio = originalLearningRatio / (1+ 
perceptronInstancesSeen*learningRateDecay); 
-               }
-
-               this.updateWeights(inst,learningRatio);
-               //this.printPerceptron();
-       }
-
-       /**
-        * Output the prediction made by this perceptron on the given instance
-        */
-       private double prediction(Instance inst)
-       {
-               double[] normalizedInstance = normalizedInstance(inst); 
-               double normalizedPrediction = prediction(normalizedInstance);
-               return denormalizedPrediction(normalizedPrediction);
-       }
-
-       public double normalizedPrediction(Instance inst)
-       {
-               double[] normalizedInstance = normalizedInstance(inst);
-               return prediction(normalizedInstance);
-       }
-
-       private double denormalizedPrediction(double normalizedPrediction) {
-               if (!this.initialisePerceptron){
-                       double meanY = perceptronsumY / perceptronYSeen;
-                       double sdY = computeSD(squaredperceptronsumY, 
perceptronsumY, perceptronYSeen);
-                       if (sdY > SD_THRESHOLD) 
-                               return normalizedPrediction * sdY + meanY;
-                       else
-                               return normalizedPrediction + meanY;
-               }
-               else
-                       return normalizedPrediction; //Perceptron may have been 
"reseted". Use old weights to predict
-
-       }
-
-       public double prediction(double[] instanceValues)
-       {
-               double prediction = 0.0;
-               if(!this.initialisePerceptron)
-               {
-                       for (int j = 0; j < instanceValues.length - 1; j++) {
-                               prediction += this.weightAttribute[j] * 
instanceValues[j];
-                       } 
-                       prediction += 
this.weightAttribute[instanceValues.length - 1];
-               }       
-               return prediction;
-       }
-
-       public double[] normalizedInstance(Instance inst){
-               // Normalize Instance
-               double[] normalizedInstance = new double[inst.numAttributes()];
-               for(int j = 0; j < inst.numAttributes() -1; j++) {
-                       int instAttIndex = modelAttIndexToInstanceAttIndex(j);
-                       double mean = perceptronattributeStatistics.getValue(j) 
/ perceptronYSeen;
-                       double sd = 
computeSD(squaredperceptronattributeStatistics.getValue(j), 
perceptronattributeStatistics.getValue(j), perceptronYSeen);
-                       if (sd > SD_THRESHOLD) 
-                               normalizedInstance[j] = 
(inst.value(instAttIndex) - mean)/ sd; 
-                       else
-                               normalizedInstance[j] = 
inst.value(instAttIndex) - mean;
-               }
-               return normalizedInstance;
-       }
-
-       public  double computeSD(double squaredVal, double val, int size) {
-               if (size > 1) {
-                       return  Math.sqrt((squaredVal - ((val * val) / size)) / 
(size - 1.0));
-               }
-               return 0.0;
-       }
-
-       public double updateWeights(Instance inst, double learningRatio ){
-               // Normalize Instance
-               double[] normalizedInstance = normalizedInstance(inst); 
-               // Compute the Normalized Prediction of Perceptron
-               double normalizedPredict= prediction(normalizedInstance);
-               double normalizedY = normalizeActualClassValue(inst);
-               double sumWeights = 0.0;                
-               double delta = normalizedY - normalizedPredict;
-
-               for (int j = 0; j < inst.numAttributes() - 1; j++) {
-                       int instAttIndex = modelAttIndexToInstanceAttIndex(j);
-                       if(inst.attribute(instAttIndex).isNumeric()) {
-                               this.weightAttribute[j] += learningRatio * 
delta * normalizedInstance[j];
-                               sumWeights += Math.abs(this.weightAttribute[j]);
-                       }
-               }
-               this.weightAttribute[inst.numAttributes() - 1] += learningRatio 
* delta;
-               sumWeights += 
Math.abs(this.weightAttribute[inst.numAttributes() - 1]);
-               if (sumWeights > inst.numAttributes()) { // Lasso regression
-                       for (int j = 0; j < inst.numAttributes() - 1; j++) {
-                               int instAttIndex = 
modelAttIndexToInstanceAttIndex(j);
-                               if(inst.attribute(instAttIndex).isNumeric()) {
-                                       this.weightAttribute[j] = 
this.weightAttribute[j] / sumWeights;
-                               }
-                       }
-                       this.weightAttribute[inst.numAttributes() - 1]  = 
this.weightAttribute[inst.numAttributes() - 1] / sumWeights;
-               }
-
-               return denormalizedPrediction(normalizedPredict);
-       }
-
-       public void normalizeWeights(){
-               double sumWeights = 0.0;
-
-               for (double aWeightAttribute : this.weightAttribute) {
-                       sumWeights += Math.abs(aWeightAttribute);
-               }
-               for (int j = 0; j < this.weightAttribute.length; j++) {
-                       this.weightAttribute[j] = this.weightAttribute[j] / 
sumWeights;
-               }       
-       }
-
-       private double normalizeActualClassValue(Instance inst) {
-               double meanY = perceptronsumY / perceptronYSeen;
-               double sdY = computeSD(squaredperceptronsumY, perceptronsumY, 
perceptronYSeen);
-
-               double normalizedY;
-               if (sdY > SD_THRESHOLD){
-                       normalizedY = (inst.classValue() - meanY) / sdY;
-               }else{
-                       normalizedY = inst.classValue() - meanY;
-               }
-               return normalizedY;
-       }
-
-       @Override
-       public boolean isRandomizable() {
-               return true;
-       }
-
-       @Override
-       public double[] getVotesForInstance(Instance inst) {
-               return new double[]{this.prediction(inst)};
-       }
-
-       @Override
-       protected Measurement[] getModelMeasurementsImpl() {
-               return null;
-       }
-
-       @Override
-       public void getModelDescription(StringBuilder out, int indent) {
-               if(this.weightAttribute!=null){
-                       for(int i=0; i< this.weightAttribute.length-1; ++i)
-                       {
-                               if(this.weightAttribute[i]>=0 && i>0)
-                                       out.append(" +" + 
Math.round(this.weightAttribute[i]*1000)/1000.0 + " X" + i );
-                               else
-                                       out.append(" " + 
Math.round(this.weightAttribute[i]*1000)/1000.0 + " X" + i );
-                       }
-                       
if(this.weightAttribute[this.weightAttribute.length-1]>=0 )
-                               out.append(" +" + 
Math.round(this.weightAttribute[this.weightAttribute.length-1]*1000)/1000.0);
-                       else
-                               out.append(" " + 
Math.round(this.weightAttribute[this.weightAttribute.length-1]*1000)/1000.0);
-               }       
-       }
-
-       public void setLearningRatio(double learningRatio) {
-               this.learningRatio=learningRatio;
-
-       }
-
-       public double getCurrentError()
-       {
-               if (nError>0)
-                       return accumulatedError/nError;
-               else 
-                       return Double.MAX_VALUE;
-       }
-       
-       public static class PerceptronData implements Serializable {
-               /**
+  private final double SD_THRESHOLD = 0.0000001; // THRESHOLD for normalizing
+                                                 // attribute and target values
+
+  private static final long serialVersionUID = 1L;
+
+  // public FlagOption constantLearningRatioDecayOption = new FlagOption(
+  // "learningRatio_Decay_set_constant", 'd',
+  // "Learning Ratio Decay in Perceptron set to be constant. (The next 
parameter).");
+  //
+  // public FloatOption learningRatioOption = new FloatOption(
+  // "learningRatio", 'l',
+  // "Constante Learning Ratio to use for training the Perceptrons in the 
leaves.",
+  // 0.01);
+  //
+  // public FloatOption learningRateDecayOption = new FloatOption(
+  // "learningRateDecay", 'm',
+  // " Learning Rate decay to use for training the Perceptron.", 0.001);
+  //
+  // public FloatOption fadingFactorOption = new FloatOption(
+  // "fadingFactor", 'e',
+  // "Fading factor for the Perceptron accumulated error", 0.99, 0, 1);
+
+  protected boolean constantLearningRatioDecay;
+  protected double originalLearningRatio;
+
+  private double nError;
+  protected double fadingFactor = 0.99;
+  private double learningRatio;
+  protected double learningRateDecay = 0.001;
+
+  // The Perception weights
+  protected double[] weightAttribute;
+
+  // Statistics used for error calculations
+  public DoubleVector perceptronattributeStatistics = new DoubleVector();
+  public DoubleVector squaredperceptronattributeStatistics = new 
DoubleVector();
+
+  // The number of instances contributing to this model
+  protected int perceptronInstancesSeen;
+  protected int perceptronYSeen;
+
+  protected double accumulatedError;
+
+  // If the model (weights) should be reset or not
+  protected boolean initialisePerceptron;
+
+  protected double perceptronsumY;
+  protected double squaredperceptronsumY;
+
+  public Perceptron() {
+    this.initialisePerceptron = true;
+  }
+
+  /*
+   * Perceptron
+   */
+  public Perceptron(Perceptron p) {
+    this(p, false);
+  }
+
+  public Perceptron(Perceptron p, boolean copyAccumulatedError) {
+    super();
+    // this.constantLearningRatioDecayOption =
+    // p.constantLearningRatioDecayOption;
+    // this.learningRatioOption = p.learningRatioOption;
+    // this.learningRateDecayOption=p.learningRateDecayOption;
+    // this.fadingFactorOption = p.fadingFactorOption;
+    this.constantLearningRatioDecay = p.constantLearningRatioDecay;
+    this.originalLearningRatio = p.originalLearningRatio;
+    if (copyAccumulatedError)
+      this.accumulatedError = p.accumulatedError;
+    this.nError = p.nError;
+    this.fadingFactor = p.fadingFactor;
+    this.learningRatio = p.learningRatio;
+    this.learningRateDecay = p.learningRateDecay;
+    if (p.weightAttribute != null)
+      this.weightAttribute = p.weightAttribute.clone();
+
+    this.perceptronattributeStatistics = new 
DoubleVector(p.perceptronattributeStatistics);
+    this.squaredperceptronattributeStatistics = new 
DoubleVector(p.squaredperceptronattributeStatistics);
+    this.perceptronInstancesSeen = p.perceptronInstancesSeen;
+
+    this.initialisePerceptron = p.initialisePerceptron;
+    this.perceptronsumY = p.perceptronsumY;
+    this.squaredperceptronsumY = p.squaredperceptronsumY;
+    this.perceptronYSeen = p.perceptronYSeen;
+  }
+
+  public Perceptron(PerceptronData p) {
+    super();
+    this.constantLearningRatioDecay = p.constantLearningRatioDecay;
+    this.originalLearningRatio = p.originalLearningRatio;
+    this.nError = p.nError;
+    this.fadingFactor = p.fadingFactor;
+    this.learningRatio = p.learningRatio;
+    this.learningRateDecay = p.learningRateDecay;
+    if (p.weightAttribute != null)
+      this.weightAttribute = p.weightAttribute.clone();
+
+    this.perceptronattributeStatistics = new 
DoubleVector(p.perceptronattributeStatistics);
+    this.squaredperceptronattributeStatistics = new 
DoubleVector(p.squaredperceptronattributeStatistics);
+    this.perceptronInstancesSeen = p.perceptronInstancesSeen;
+
+    this.initialisePerceptron = p.initialisePerceptron;
+    this.perceptronsumY = p.perceptronsumY;
+    this.squaredperceptronsumY = p.squaredperceptronsumY;
+    this.perceptronYSeen = p.perceptronYSeen;
+    this.accumulatedError = p.accumulatedError;
+  }
+
+  // private void printPerceptron() {
+  // System.out.println("Learning Ratio:"+this.learningRatio+" 
("+this.originalLearningRatio+")");
+  // System.out.println("Constant Learning Ratio 
Decay:"+this.constantLearningRatioDecay+" ("+this.learningRateDecay+")");
+  // System.out.println("Error:"+this.accumulatedError+"/"+this.nError);
+  // System.out.println("Fading factor:"+this.fadingFactor);
+  // System.out.println("Perceptron 
Y:"+this.perceptronsumY+"/"+this.squaredperceptronsumY+"/"+this.perceptronYSeen);
+  // }
+
+  /*
+   * Weights
+   */
+  public void setWeights(double[] w) {
+    this.weightAttribute = w;
+  }
+
+  public double[] getWeights() {
+    return this.weightAttribute;
+  }
+
+  /*
+   * No. of instances seen
+   */
+  public int getInstancesSeen() {
+    return perceptronInstancesSeen;
+  }
+
+  public void setInstancesSeen(int pInstancesSeen) {
+    this.perceptronInstancesSeen = pInstancesSeen;
+  }
+
+  /**
+   * A method to reset the model
+   */
+  public void resetLearningImpl() {
+    this.initialisePerceptron = true;
+    this.reset();
+  }
+
+  public void reset() {
+    this.nError = 0.0;
+    this.accumulatedError = 0.0;
+    this.perceptronInstancesSeen = 0;
+    this.perceptronattributeStatistics = new DoubleVector();
+    this.squaredperceptronattributeStatistics = new DoubleVector();
+    this.perceptronsumY = 0.0;
+    this.squaredperceptronsumY = 0.0;
+    this.perceptronYSeen = 0;
+  }
+
+  public void resetError() {
+    this.nError = 0.0;
+    this.accumulatedError = 0.0;
+  }
+
+  /**
+   * Update the model using the provided instance
+   */
+  public void trainOnInstanceImpl(Instance inst) {
+    accumulatedError = Math.abs(this.prediction(inst) - inst.classValue()) + 
fadingFactor * accumulatedError;
+    nError = 1 + fadingFactor * nError;
+    // Initialise Perceptron if necessary
+    if (this.initialisePerceptron) {
+      // this.fadingFactor=this.fadingFactorOption.getValue();
+      // this.classifierRandom.setSeed(randomSeedOption.getValue());
+      this.classifierRandom.setSeed(randomSeed);
+      this.initialisePerceptron = false; // not in resetLearningImpl() because
+                                         // it needs Instance!
+      this.weightAttribute = new double[inst.numAttributes()];
+      for (int j = 0; j < inst.numAttributes(); j++) {
+        weightAttribute[j] = 2 * this.classifierRandom.nextDouble() - 1;
+      }
+      // Update Learning Rate
+      learningRatio = originalLearningRatio;
+      // this.learningRateDecay = learningRateDecayOption.getValue();
+
+    }
+
+    // Update attribute statistics
+    this.perceptronInstancesSeen++;
+    this.perceptronYSeen++;
+
+    for (int j = 0; j < inst.numAttributes() - 1; j++)
+    {
+      perceptronattributeStatistics.addToValue(j, inst.value(j));
+      squaredperceptronattributeStatistics.addToValue(j, inst.value(j) * 
inst.value(j));
+    }
+    this.perceptronsumY += inst.classValue();
+    this.squaredperceptronsumY += inst.classValue() * inst.classValue();
+
+    if (!constantLearningRatioDecay) {
+      learningRatio = originalLearningRatio / (1 + perceptronInstancesSeen * 
learningRateDecay);
+    }
+
+    this.updateWeights(inst, learningRatio);
+    // this.printPerceptron();
+  }
+
+  /**
+   * Output the prediction made by this perceptron on the given instance
+   */
+  private double prediction(Instance inst)
+  {
+    double[] normalizedInstance = normalizedInstance(inst);
+    double normalizedPrediction = prediction(normalizedInstance);
+    return denormalizedPrediction(normalizedPrediction);
+  }
+
+  public double normalizedPrediction(Instance inst)
+  {
+    double[] normalizedInstance = normalizedInstance(inst);
+    return prediction(normalizedInstance);
+  }
+
+  private double denormalizedPrediction(double normalizedPrediction) {
+    if (!this.initialisePerceptron) {
+      double meanY = perceptronsumY / perceptronYSeen;
+      double sdY = computeSD(squaredperceptronsumY, perceptronsumY, 
perceptronYSeen);
+      if (sdY > SD_THRESHOLD)
+        return normalizedPrediction * sdY + meanY;
+      else
+        return normalizedPrediction + meanY;
+    }
+    else
+      return normalizedPrediction; // Perceptron may have been "reseted". Use
+                                   // old weights to predict
+
+  }
+
+  public double prediction(double[] instanceValues)
+  {
+    double prediction = 0.0;
+    if (!this.initialisePerceptron)
+    {
+      for (int j = 0; j < instanceValues.length - 1; j++) {
+        prediction += this.weightAttribute[j] * instanceValues[j];
+      }
+      prediction += this.weightAttribute[instanceValues.length - 1];
+    }
+    return prediction;
+  }
+
+  public double[] normalizedInstance(Instance inst) {
+    // Normalize Instance
+    double[] normalizedInstance = new double[inst.numAttributes()];
+    for (int j = 0; j < inst.numAttributes() - 1; j++) {
+      int instAttIndex = modelAttIndexToInstanceAttIndex(j);
+      double mean = perceptronattributeStatistics.getValue(j) / 
perceptronYSeen;
+      double sd = computeSD(squaredperceptronattributeStatistics.getValue(j),
+          perceptronattributeStatistics.getValue(j), perceptronYSeen);
+      if (sd > SD_THRESHOLD)
+        normalizedInstance[j] = (inst.value(instAttIndex) - mean) / sd;
+      else
+        normalizedInstance[j] = inst.value(instAttIndex) - mean;
+    }
+    return normalizedInstance;
+  }
+
+  public double computeSD(double squaredVal, double val, int size) {
+    if (size > 1) {
+      return Math.sqrt((squaredVal - ((val * val) / size)) / (size - 1.0));
+    }
+    return 0.0;
+  }
+
+  public double updateWeights(Instance inst, double learningRatio) {
+    // Normalize Instance
+    double[] normalizedInstance = normalizedInstance(inst);
+    // Compute the Normalized Prediction of Perceptron
+    double normalizedPredict = prediction(normalizedInstance);
+    double normalizedY = normalizeActualClassValue(inst);
+    double sumWeights = 0.0;
+    double delta = normalizedY - normalizedPredict;
+
+    for (int j = 0; j < inst.numAttributes() - 1; j++) {
+      int instAttIndex = modelAttIndexToInstanceAttIndex(j);
+      if (inst.attribute(instAttIndex).isNumeric()) {
+        this.weightAttribute[j] += learningRatio * delta * 
normalizedInstance[j];
+        sumWeights += Math.abs(this.weightAttribute[j]);
+      }
+    }
+    this.weightAttribute[inst.numAttributes() - 1] += learningRatio * delta;
+    sumWeights += Math.abs(this.weightAttribute[inst.numAttributes() - 1]);
+    if (sumWeights > inst.numAttributes()) { // Lasso regression
+      for (int j = 0; j < inst.numAttributes() - 1; j++) {
+        int instAttIndex = modelAttIndexToInstanceAttIndex(j);
+        if (inst.attribute(instAttIndex).isNumeric()) {
+          this.weightAttribute[j] = this.weightAttribute[j] / sumWeights;
+        }
+      }
+      this.weightAttribute[inst.numAttributes() - 1] = 
this.weightAttribute[inst.numAttributes() - 1] / sumWeights;
+    }
+
+    return denormalizedPrediction(normalizedPredict);
+  }
+
+  public void normalizeWeights() {
+    double sumWeights = 0.0;
+
+    for (double aWeightAttribute : this.weightAttribute) {
+      sumWeights += Math.abs(aWeightAttribute);
+    }
+    for (int j = 0; j < this.weightAttribute.length; j++) {
+      this.weightAttribute[j] = this.weightAttribute[j] / sumWeights;
+    }
+  }
+
+  private double normalizeActualClassValue(Instance inst) {
+    double meanY = perceptronsumY / perceptronYSeen;
+    double sdY = computeSD(squaredperceptronsumY, perceptronsumY, 
perceptronYSeen);
+
+    double normalizedY;
+    if (sdY > SD_THRESHOLD) {
+      normalizedY = (inst.classValue() - meanY) / sdY;
+    } else {
+      normalizedY = inst.classValue() - meanY;
+    }
+    return normalizedY;
+  }
+
+  @Override
+  public boolean isRandomizable() {
+    return true;
+  }
+
+  @Override
+  public double[] getVotesForInstance(Instance inst) {
+    return new double[] { this.prediction(inst) };
+  }
+
+  @Override
+  protected Measurement[] getModelMeasurementsImpl() {
+    return null;
+  }
+
+  @Override
+  public void getModelDescription(StringBuilder out, int indent) {
+    if (this.weightAttribute != null) {
+      for (int i = 0; i < this.weightAttribute.length - 1; ++i)
+      {
+        if (this.weightAttribute[i] >= 0 && i > 0)
+          out.append(" +" + Math.round(this.weightAttribute[i] * 1000) / 
1000.0 + " X" + i);
+        else
+          out.append(" " + Math.round(this.weightAttribute[i] * 1000) / 1000.0 
+ " X" + i);
+      }
+      if (this.weightAttribute[this.weightAttribute.length - 1] >= 0)
+        out.append(" +" + 
Math.round(this.weightAttribute[this.weightAttribute.length - 1] * 1000) / 
1000.0);
+      else
+        out.append(" " + 
Math.round(this.weightAttribute[this.weightAttribute.length - 1] * 1000) / 
1000.0);
+    }
+  }
+
+  public void setLearningRatio(double learningRatio) {
+    this.learningRatio = learningRatio;
+
+  }
+
+  public double getCurrentError()
+  {
+    if (nError > 0)
+      return accumulatedError / nError;
+    else
+      return Double.MAX_VALUE;
+  }
+
+  public static class PerceptronData implements Serializable {
+    /**
                 * 
                 */
-               private static final long serialVersionUID = 
6727623208744105082L;
-               
-               private boolean constantLearningRatioDecay;
-               // If the model  (weights) should be reset or not
-               private boolean initialisePerceptron; 
-               
-               private double nError;
-               private double fadingFactor;
-               private double originalLearningRatio;
-               private double learningRatio;
-               private double learningRateDecay;
-               private double accumulatedError;
-               private double perceptronsumY;
-               private double squaredperceptronsumY;
-
-               // The Perception weights 
-               private double[] weightAttribute; 
-
-               // Statistics used for error calculations
-               private DoubleVector perceptronattributeStatistics;
-               private DoubleVector squaredperceptronattributeStatistics;
-
-               // The number of instances contributing to this model
-               private int perceptronInstancesSeen;
-               private int perceptronYSeen;
-
-               public PerceptronData() {
-                       
-               }
-               
-               public PerceptronData(Perceptron p) {
-                       this.constantLearningRatioDecay = 
p.constantLearningRatioDecay;
-                       this.initialisePerceptron = p.initialisePerceptron;
-                       this.nError = p.nError;
-                       this.fadingFactor = p.fadingFactor;
-                       this.originalLearningRatio = p.originalLearningRatio;
-                       this.learningRatio = p.learningRatio;
-                       this.learningRateDecay = p.learningRateDecay;
-                       this.accumulatedError = p.accumulatedError;
-                       this.perceptronsumY = p.perceptronsumY;
-                       this.squaredperceptronsumY = p.squaredperceptronsumY;
-                       this.weightAttribute = p.weightAttribute;
-                       this.perceptronattributeStatistics = 
p.perceptronattributeStatistics;
-                       this.squaredperceptronattributeStatistics = 
p.squaredperceptronattributeStatistics;
-                       this.perceptronInstancesSeen = 
p.perceptronInstancesSeen;
-                       this.perceptronYSeen = p.perceptronYSeen;
-               }
-               
-               public Perceptron build() {
-                       return new Perceptron(this);
-               }
-               
-       }
-       
-       
-       public static final class PerceptronSerializer extends 
Serializer<Perceptron>{
-
-               @Override
-               public void write(Kryo kryo, Output output, Perceptron p) {
-                       kryo.writeObjectOrNull(output, new PerceptronData(p), 
PerceptronData.class);
-               }
-
-               @Override
-               public Perceptron read(Kryo kryo, Input input, 
Class<Perceptron> type) {
-                       PerceptronData perceptronData = 
kryo.readObjectOrNull(input, PerceptronData.class);
-                       return perceptronData.build();
-               }
-       }
+    private static final long serialVersionUID = 6727623208744105082L;
+
+    private boolean constantLearningRatioDecay;
+    // If the model (weights) should be reset or not
+    private boolean initialisePerceptron;
+
+    private double nError;
+    private double fadingFactor;
+    private double originalLearningRatio;
+    private double learningRatio;
+    private double learningRateDecay;
+    private double accumulatedError;
+    private double perceptronsumY;
+    private double squaredperceptronsumY;
+
+    // The Perception weights
+    private double[] weightAttribute;
+
+    // Statistics used for error calculations
+    private DoubleVector perceptronattributeStatistics;
+    private DoubleVector squaredperceptronattributeStatistics;
+
+    // The number of instances contributing to this model
+    private int perceptronInstancesSeen;
+    private int perceptronYSeen;
+
+    public PerceptronData() {
+
+    }
+
+    public PerceptronData(Perceptron p) {
+      this.constantLearningRatioDecay = p.constantLearningRatioDecay;
+      this.initialisePerceptron = p.initialisePerceptron;
+      this.nError = p.nError;
+      this.fadingFactor = p.fadingFactor;
+      this.originalLearningRatio = p.originalLearningRatio;
+      this.learningRatio = p.learningRatio;
+      this.learningRateDecay = p.learningRateDecay;
+      this.accumulatedError = p.accumulatedError;
+      this.perceptronsumY = p.perceptronsumY;
+      this.squaredperceptronsumY = p.squaredperceptronsumY;
+      this.weightAttribute = p.weightAttribute;
+      this.perceptronattributeStatistics = p.perceptronattributeStatistics;
+      this.squaredperceptronattributeStatistics = 
p.squaredperceptronattributeStatistics;
+      this.perceptronInstancesSeen = p.perceptronInstancesSeen;
+      this.perceptronYSeen = p.perceptronYSeen;
+    }
+
+    public Perceptron build() {
+      return new Perceptron(this);
+    }
+
+  }
+
+  public static final class PerceptronSerializer extends 
Serializer<Perceptron> {
+
+    @Override
+    public void write(Kryo kryo, Output output, Perceptron p) {
+      kryo.writeObjectOrNull(output, new PerceptronData(p), 
PerceptronData.class);
+    }
+
+    @Override
+    public Perceptron read(Kryo kryo, Input input, Class<Perceptron> type) {
+      PerceptronData perceptronData = kryo.readObjectOrNull(input, 
PerceptronData.class);
+      return perceptronData.build();
+    }
+  }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-samoa/blob/23a35dbe/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/Rule.java
----------------------------------------------------------------------
diff --git 
a/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/Rule.java
 
b/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/Rule.java
index b85cf10..0f58559 100644
--- 
a/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/Rule.java
+++ 
b/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/Rule.java
@@ -28,84 +28,95 @@ import com.yahoo.labs.samoa.moa.AbstractMOAObject;
 import 
com.yahoo.labs.samoa.moa.classifiers.rules.core.conditionaltests.NumericAttributeBinaryRulePredicate;
 
 /**
- * The base class for "rule".
- * Represents the most basic rule with and ID and a list of features 
(nodeList).
+ * The base class for "rule". Represents the most basic rule with and ID and a
+ * list of features (nodeList).
  * 
  * @author Anh Thu Vu
- *
+ * 
  */
 public abstract class Rule extends AbstractMOAObject {
-       private static final long serialVersionUID = 1L;
+  private static final long serialVersionUID = 1L;
+
+  protected int ruleNumberID;
+
+  protected List<RuleSplitNode> nodeList;
+
+  /*
+   * Constructor
+   */
+  public Rule() {
+    this.nodeList = new LinkedList<RuleSplitNode>();
+  }
+
+  /*
+   * Rule ID
+   */
+  public int getRuleNumberID() {
+    return ruleNumberID;
+  }
+
+  public void setRuleNumberID(int ruleNumberID) {
+    this.ruleNumberID = ruleNumberID;
+  }
+
+  /*
+   * RuleSplitNode list
+   */
+  public List<RuleSplitNode> getNodeList() {
+    return nodeList;
+  }
 
-       protected int ruleNumberID;
-       
-       protected List<RuleSplitNode> nodeList;
-       
-       /*
-        * Constructor
-        */
-       public Rule() {
-               this.nodeList = new LinkedList<RuleSplitNode>();
-       }
-       
-       /*
-        * Rule ID
-        */
-       public int getRuleNumberID() {
-               return ruleNumberID;
-       }
+  public void setNodeList(List<RuleSplitNode> nodeList) {
+    this.nodeList = nodeList;
+  }
 
-       public void setRuleNumberID(int ruleNumberID) {
-               this.ruleNumberID = ruleNumberID;
-       }
-       
-       /*
-        * RuleSplitNode list
-        */
-       public List<RuleSplitNode> getNodeList() {
-               return nodeList;
-       }
+  /*
+   * Covering
+   */
+  public boolean isCovering(Instance inst) {
+    boolean isCovering = true;
+    for (RuleSplitNode node : nodeList) {
+      if (node.evaluate(inst) == false) {
+        isCovering = false;
+        break;
+      }
+    }
+    return isCovering;
+  }
 
-       public void setNodeList(List<RuleSplitNode> nodeList) {
-               this.nodeList = nodeList;
-       }
-       
-       /*
-        * Covering
-        */
-       public boolean isCovering(Instance inst) {
-               boolean isCovering = true;
-               for (RuleSplitNode node : nodeList) {
-                       if (node.evaluate(inst) == false) {
-                               isCovering = false;
-                               break;
-                       }
-               }
-               return isCovering;
-       }
-       
-       /*
-        * Add RuleSplitNode
-        */
-       public boolean nodeListAdd(RuleSplitNode ruleSplitNode) {
-               //Check that the node is not already in the list
-               boolean isIncludedInNodeList = false;
-               boolean isUpdated=false;
-               for (RuleSplitNode node : nodeList) {
-                       NumericAttributeBinaryRulePredicate nodeTest = 
(NumericAttributeBinaryRulePredicate) node.getSplitTest();
-                       NumericAttributeBinaryRulePredicate ruleSplitNodeTest = 
(NumericAttributeBinaryRulePredicate) ruleSplitNode.getSplitTest();
-                       if (nodeTest.isUsingSameAttribute(ruleSplitNodeTest)) {
-                               isIncludedInNodeList = true;
-                               if 
(nodeTest.isIncludedInRuleNode(ruleSplitNodeTest) == true) { //remove this line 
to keep the most recent attribute value
-                                       //replace the value
-                                       
nodeTest.setAttributeValue(ruleSplitNodeTest);
-                                       isUpdated=true; //if is updated (i.e. 
an expansion happened) a new learning node should be created
-                               }
-                       }
-               }
-               if (isIncludedInNodeList == false) {
-                       this.nodeList.add(ruleSplitNode);
-               }
-               return (!isIncludedInNodeList || isUpdated); 
-       }
+  /*
+   * Add RuleSplitNode
+   */
+  public boolean nodeListAdd(RuleSplitNode ruleSplitNode) {
+    // Check that the node is not already in the list
+    boolean isIncludedInNodeList = false;
+    boolean isUpdated = false;
+    for (RuleSplitNode node : nodeList) {
+      NumericAttributeBinaryRulePredicate nodeTest = 
(NumericAttributeBinaryRulePredicate) node.getSplitTest();
+      NumericAttributeBinaryRulePredicate ruleSplitNodeTest = 
(NumericAttributeBinaryRulePredicate) ruleSplitNode
+          .getSplitTest();
+      if (nodeTest.isUsingSameAttribute(ruleSplitNodeTest)) {
+        isIncludedInNodeList = true;
+        if (nodeTest.isIncludedInRuleNode(ruleSplitNodeTest) == true) { // 
remove
+                                                                        // this
+                                                                        // line
+                                                                        // to
+                                                                        // keep
+                                                                        // the
+                                                                        // most
+                                                                        // 
recent
+                                                                        // 
attribute
+                                                                        // 
value
+          // replace the value
+          nodeTest.setAttributeValue(ruleSplitNodeTest);
+          isUpdated = true; // if is updated (i.e. an expansion happened) a new
+                            // learning node should be created
+        }
+      }
+    }
+    if (isIncludedInNodeList == false) {
+      this.nodeList.add(ruleSplitNode);
+    }
+    return (!isIncludedInNodeList || isUpdated);
+  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-samoa/blob/23a35dbe/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RuleActiveLearningNode.java
----------------------------------------------------------------------
diff --git 
a/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RuleActiveLearningNode.java
 
b/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RuleActiveLearningNode.java
index f52ac32..513340e 100644
--- 
a/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RuleActiveLearningNode.java
+++ 
b/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RuleActiveLearningNode.java
@@ -21,14 +21,14 @@ package 
com.yahoo.labs.samoa.learners.classifiers.rules.common;
  */
 
 /**
- * Interface for Rule's LearningNode that updates both statistics 
- * for expanding rule and computing predictions.
+ * Interface for Rule's LearningNode that updates both statistics for expanding
+ * rule and computing predictions.
  * 
  * @author Anh Thu Vu
- *
+ * 
  */
 public interface RuleActiveLearningNode extends RulePassiveLearningNode {
 
-       public boolean tryToExpand(double splitConfidence, double tieThreshold);
-       
+  public boolean tryToExpand(double splitConfidence, double tieThreshold);
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-samoa/blob/23a35dbe/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RuleActiveRegressionNode.java
----------------------------------------------------------------------
diff --git 
a/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RuleActiveRegressionNode.java
 
b/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RuleActiveRegressionNode.java
index 05079ed..48daf7a 100644
--- 
a/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RuleActiveRegressionNode.java
+++ 
b/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RuleActiveRegressionNode.java
@@ -37,282 +37,297 @@ import 
com.yahoo.labs.samoa.moa.classifiers.rules.driftdetection.PageHinkleyFadi
 import 
com.yahoo.labs.samoa.moa.classifiers.rules.driftdetection.PageHinkleyTest;
 
 /**
- * LearningNode for regression rule that updates both statistics for
- * expanding rule and computing predictions.
+ * LearningNode for regression rule that updates both statistics for expanding
+ * rule and computing predictions.
  * 
  * @author Anh Thu Vu
- *
+ * 
  */
 public class RuleActiveRegressionNode extends RuleRegressionNode implements 
RuleActiveLearningNode {
 
-       /**
+  /**
         * 
         */
-       private static final long serialVersionUID = 519854943188168546L;
-
-       protected int splitIndex = 0;
-       
-       protected PageHinkleyTest pageHinckleyTest;
-       protected boolean changeDetection;
-       
-       protected double[] statisticsNewRuleActiveLearningNode = null;
-       protected double[] statisticsBranchSplit = null;
-       protected double[] statisticsOtherBranchSplit;
-       
-       protected AttributeSplitSuggestion bestSuggestion = null;
-       
-       protected AutoExpandVector<AttributeClassObserver> attributeObservers = 
new AutoExpandVector<>();
-       private FIMTDDNumericAttributeClassLimitObserver numericObserver;
-       
-       /*
-        * Simple setters & getters
-        */
-       public int getSplitIndex() {
-               return splitIndex;
-       }
-
-       public void setSplitIndex(int splitIndex) {
-               this.splitIndex = splitIndex;
-       }
-       
-       public double[] getStatisticsOtherBranchSplit() {
-               return statisticsOtherBranchSplit;
-       }
-
-       public void setStatisticsOtherBranchSplit(double[] 
statisticsOtherBranchSplit) {
-               this.statisticsOtherBranchSplit = statisticsOtherBranchSplit;
-       }
-
-       public double[] getStatisticsBranchSplit() {
-               return statisticsBranchSplit;
-       }
-
-       public void setStatisticsBranchSplit(double[] statisticsBranchSplit) {
-               this.statisticsBranchSplit = statisticsBranchSplit;
-       }
-
-       public double[] getStatisticsNewRuleActiveLearningNode() {
-               return statisticsNewRuleActiveLearningNode;
-       }
-
-       public void setStatisticsNewRuleActiveLearningNode(
-                       double[] statisticsNewRuleActiveLearningNode) {
-               this.statisticsNewRuleActiveLearningNode = 
statisticsNewRuleActiveLearningNode;
-       }
-       
-       public AttributeSplitSuggestion getBestSuggestion() {
-               return bestSuggestion;
-       }
-       
-       public void setBestSuggestion(AttributeSplitSuggestion bestSuggestion) {
-               this.bestSuggestion = bestSuggestion;
-       }
-       
-       /*
-        * Constructor with builder
-        */
-       public RuleActiveRegressionNode() {
-               super();
-       }
-       public RuleActiveRegressionNode(ActiveRule.Builder builder) {
-               super(builder.statistics);
-        this.changeDetection = builder.changeDetection;
-        if (!builder.changeDetection) {
-               this.pageHinckleyTest = new 
PageHinkleyFading(builder.threshold, builder.alpha);
+  private static final long serialVersionUID = 519854943188168546L;
+
+  protected int splitIndex = 0;
+
+  protected PageHinkleyTest pageHinckleyTest;
+  protected boolean changeDetection;
+
+  protected double[] statisticsNewRuleActiveLearningNode = null;
+  protected double[] statisticsBranchSplit = null;
+  protected double[] statisticsOtherBranchSplit;
+
+  protected AttributeSplitSuggestion bestSuggestion = null;
+
+  protected AutoExpandVector<AttributeClassObserver> attributeObservers = new 
AutoExpandVector<>();
+  private FIMTDDNumericAttributeClassLimitObserver numericObserver;
+
+  /*
+   * Simple setters & getters
+   */
+  public int getSplitIndex() {
+    return splitIndex;
+  }
+
+  public void setSplitIndex(int splitIndex) {
+    this.splitIndex = splitIndex;
+  }
+
+  public double[] getStatisticsOtherBranchSplit() {
+    return statisticsOtherBranchSplit;
+  }
+
+  public void setStatisticsOtherBranchSplit(double[] 
statisticsOtherBranchSplit) {
+    this.statisticsOtherBranchSplit = statisticsOtherBranchSplit;
+  }
+
+  public double[] getStatisticsBranchSplit() {
+    return statisticsBranchSplit;
+  }
+
+  public void setStatisticsBranchSplit(double[] statisticsBranchSplit) {
+    this.statisticsBranchSplit = statisticsBranchSplit;
+  }
+
+  public double[] getStatisticsNewRuleActiveLearningNode() {
+    return statisticsNewRuleActiveLearningNode;
+  }
+
+  public void setStatisticsNewRuleActiveLearningNode(
+      double[] statisticsNewRuleActiveLearningNode) {
+    this.statisticsNewRuleActiveLearningNode = 
statisticsNewRuleActiveLearningNode;
+  }
+
+  public AttributeSplitSuggestion getBestSuggestion() {
+    return bestSuggestion;
+  }
+
+  public void setBestSuggestion(AttributeSplitSuggestion bestSuggestion) {
+    this.bestSuggestion = bestSuggestion;
+  }
+
+  /*
+   * Constructor with builder
+   */
+  public RuleActiveRegressionNode() {
+    super();
+  }
+
+  public RuleActiveRegressionNode(ActiveRule.Builder builder) {
+    super(builder.statistics);
+    this.changeDetection = builder.changeDetection;
+    if (!builder.changeDetection) {
+      this.pageHinckleyTest = new PageHinkleyFading(builder.threshold, 
builder.alpha);
+    }
+    this.predictionFunction = builder.predictionFunction;
+    this.learningRatio = builder.learningRatio;
+    this.ruleNumberID = builder.id;
+    this.numericObserver = builder.numericObserver;
+
+    this.perceptron = new Perceptron();
+    this.perceptron.prepareForUse();
+    this.perceptron.originalLearningRatio = builder.learningRatio;
+    this.perceptron.constantLearningRatioDecay = 
builder.constantLearningRatioDecay;
+
+    if (this.predictionFunction != 1)
+    {
+      this.targetMean = new TargetMean();
+      if (builder.statistics[0] > 0)
+        this.targetMean.reset(builder.statistics[1] / builder.statistics[0], 
(long) builder.statistics[0]);
+    }
+    this.predictionFunction = builder.predictionFunction;
+    if (builder.statistics != null)
+      this.nodeStatistics = new DoubleVector(builder.statistics);
+  }
+
+  /*
+   * Update with input instance
+   */
+  public boolean updatePageHinckleyTest(double error) {
+    boolean changeDetected = false;
+    if (!this.changeDetection) {
+      changeDetected = pageHinckleyTest.update(error);
+    }
+    return changeDetected;
+  }
+
+  public boolean updateChangeDetection(double error) {
+    return !changeDetection && pageHinckleyTest.update(error);
+  }
+
+  @Override
+  public void updateStatistics(Instance inst) {
+    // Update the statistics for this node
+    // number of instances passing through the node
+    nodeStatistics.addToValue(0, 1);
+    // sum of y values
+    nodeStatistics.addToValue(1, inst.classValue());
+    // sum of squared y values
+    nodeStatistics.addToValue(2, inst.classValue() * inst.classValue());
+
+    for (int i = 0; i < inst.numAttributes() - 1; i++) {
+      int instAttIndex = modelAttIndexToInstanceAttIndex(i, inst);
+
+      AttributeClassObserver obs = this.attributeObservers.get(i);
+      if (obs == null) {
+        // At this stage all nominal attributes are ignored
+        if (inst.attribute(instAttIndex).isNumeric()) // instAttIndex
+        {
+          obs = newNumericClassObserver();
+          this.attributeObservers.set(i, obs);
         }
-        this.predictionFunction = builder.predictionFunction;
-        this.learningRatio = builder.learningRatio;
-        this.ruleNumberID = builder.id;
-        this.numericObserver = builder.numericObserver;
-        
-        this.perceptron = new Perceptron();
-               this.perceptron.prepareForUse();
-               this.perceptron.originalLearningRatio = builder.learningRatio;
-               this.perceptron.constantLearningRatioDecay = 
builder.constantLearningRatioDecay;
-
-
-               if(this.predictionFunction!=1)
-               {
-                       this.targetMean = new TargetMean(); 
-                       if (builder.statistics[0]>0)
-                               
this.targetMean.reset(builder.statistics[1]/builder.statistics[0],(long)builder.statistics[0]);
-               }
-               this.predictionFunction = builder.predictionFunction;
-               if (builder.statistics!=null)
-                       this.nodeStatistics=new 
DoubleVector(builder.statistics);
-       }
-       
-       /*
-        * Update with input instance
-        */
-       public boolean updatePageHinckleyTest(double error) {
-               boolean changeDetected = false;
-               if (!this.changeDetection) {
-                       changeDetected = pageHinckleyTest.update(error);
-               }
-               return changeDetected;
-       }
-       
-       public boolean updateChangeDetection(double error) {
-               return !changeDetection && pageHinckleyTest.update(error);
-       }
-       
-       @Override
-       public void updateStatistics(Instance inst) {
-               // Update the statistics for this node
-               // number of instances passing through the node
-               nodeStatistics.addToValue(0, 1);
-               // sum of y values
-               nodeStatistics.addToValue(1, inst.classValue());
-               // sum of squared y values
-               nodeStatistics.addToValue(2, 
inst.classValue()*inst.classValue());
-                       
-               for (int i = 0; i < inst.numAttributes() - 1; i++) {
-                       int instAttIndex = modelAttIndexToInstanceAttIndex(i, 
inst);
-
-                       AttributeClassObserver obs = 
this.attributeObservers.get(i);
-                       if (obs == null) {
-                               // At this stage all nominal attributes are 
ignored
-                               if (inst.attribute(instAttIndex).isNumeric()) 
//instAttIndex
-                               {
-                                       obs = newNumericClassObserver();
-                                       this.attributeObservers.set(i, obs);
-                               }
-                       }
-                       if (obs != null) {
-                               ((FIMTDDNumericAttributeClassObserver) 
obs).observeAttributeClass(inst.value(instAttIndex), inst.classValue(), 
inst.weight());
-                       }
-               }
-               
-               this.perceptron.trainOnInstance(inst);
-               if (this.predictionFunction != 1) { //Train target mean if 
prediction function is not Perceptron
-                       this.targetMean.trainOnInstance(inst);
-               }
-       }
-       
-    protected AttributeClassObserver newNumericClassObserver() {
-        //return new FIMTDDNumericAttributeClassObserver();
-        //return new FIMTDDNumericAttributeClassLimitObserver();
-        //return 
(AttributeClassObserver)((AttributeClassObserver)this.numericObserverOption.getPreMaterializedObject()).copy();
-       FIMTDDNumericAttributeClassLimitObserver newObserver = new 
FIMTDDNumericAttributeClassLimitObserver();
-       newObserver.setMaxNodes(numericObserver.getMaxNodes());
-       return newObserver;
+      }
+      if (obs != null) {
+        ((FIMTDDNumericAttributeClassObserver) 
obs).observeAttributeClass(inst.value(instAttIndex), inst.classValue(),
+            inst.weight());
+      }
     }
-       
-    /*
-     * Init after being split from oldLearningNode
-     */
-       public void initialize(RuleRegressionNode oldLearningNode) {
-               if(oldLearningNode.perceptron!=null)
-               {
-                       this.perceptron=new 
Perceptron(oldLearningNode.perceptron);
-                       this.perceptron.resetError();
-                       
this.perceptron.setLearningRatio(oldLearningNode.learningRatio);
-               }
-
-               if(oldLearningNode.targetMean!=null)
-               {
-                       this.targetMean= new 
TargetMean(oldLearningNode.targetMean);
-                       this.targetMean.resetError();
-               }
-               //reset statistics
-               this.nodeStatistics.setValue(0, 0);
-               this.nodeStatistics.setValue(1, 0);
-               this.nodeStatistics.setValue(2, 0);
-       }
-
-       /*
-        * Expand
-        */
-       @Override
-       public boolean tryToExpand(double splitConfidence, double tieThreshold) 
{
-
-               // splitConfidence. Hoeffding Bound test parameter.
-               // tieThreshold. Hoeffding Bound test parameter.
-               SplitCriterion splitCriterion = new SDRSplitCriterionAMRules(); 
-               //SplitCriterion splitCriterion = new 
SDRSplitCriterionAMRulesNode();//JD for assessing only best branch
-
-               // Using this criterion, find the best split per attribute and 
rank the results
-               AttributeSplitSuggestion[] bestSplitSuggestions = 
this.getBestSplitSuggestions(splitCriterion);
-               Arrays.sort(bestSplitSuggestions);
-               // Declare a variable to determine if any of the splits should 
be performed
-               boolean shouldSplit = false;
-
-               // If only one split was returned, use it
-               if (bestSplitSuggestions.length < 2) {
-                       shouldSplit = ((bestSplitSuggestions.length > 0) && 
(bestSplitSuggestions[0].merit > 0)); 
-                       bestSuggestion = 
bestSplitSuggestions[bestSplitSuggestions.length - 1];
-               } // Otherwise, consider which of the splits proposed may be 
worth trying
-               else {
-                       // Determine the hoeffding bound value, used to select 
how many instances should be used to make a test decision
-                       // to feel reasonably confident that the test chosen by 
this sample is the same as what would be chosen using infinite examples
-                       double hoeffdingBound = computeHoeffdingBound(1, 
splitConfidence, getInstancesSeen());
-                       // Determine the top two ranked splitting suggestions
-                       bestSuggestion = 
bestSplitSuggestions[bestSplitSuggestions.length - 1];
-                       AttributeSplitSuggestion secondBestSuggestion = 
bestSplitSuggestions[bestSplitSuggestions.length - 2];
-                       
-                       // If the upper bound of the sample mean for the ratio 
of SDR(best suggestion) to SDR(second best suggestion),
-                       // as determined using the hoeffding bound, is less 
than 1, then the true mean is also less than 1, and thus at this
-                       // particular moment of observation the bestSuggestion 
is indeed the best split option with confidence 1-delta, and
-                       // splitting should occur.
-                       // Alternatively, if two or more splits are very 
similar or identical in terms of their splits, then a threshold limit
-                       // (default 0.05) is applied to the hoeffding bound; if 
the hoeffding bound is smaller than this limit then the two
-                       // competing attributes are equally good, and the split 
will be made on the one with the higher SDR value.
-
-                       if (bestSuggestion.merit > 0) {
-                               if ((((secondBestSuggestion.merit / 
bestSuggestion.merit) + hoeffdingBound) < 1)
-                                               || (hoeffdingBound < 
tieThreshold)) {
-                                       shouldSplit = true;
-                               }
-                       }
-               }
-
-               if (shouldSplit) {
-                       AttributeSplitSuggestion splitDecision = 
bestSplitSuggestions[bestSplitSuggestions.length - 1];
-                       double minValue = Double.MAX_VALUE;
-                       double[] branchMerits = 
SDRSplitCriterionAMRules.computeBranchSplitMerits(bestSuggestion.resultingClassDistributions);
-
-                       for (int i = 0; i < bestSuggestion.numSplits(); i++) {
-                               double value = branchMerits[i];
-                               if (value < minValue) {
-                                       minValue = value;
-                                       splitIndex = i;
-                                       statisticsNewRuleActiveLearningNode = 
bestSuggestion.resultingClassDistributionFromSplit(i);
-                               }
-                       }
-                       statisticsBranchSplit = 
splitDecision.resultingClassDistributionFromSplit(splitIndex);
-                       statisticsOtherBranchSplit = 
bestSuggestion.resultingClassDistributionFromSplit(splitIndex == 0 ? 1 : 0);
-
-               }
-               return shouldSplit;
-       }
-       
-       public AutoExpandVector<AttributeClassObserver> getAttributeObservers() 
{
-               return this.attributeObservers;
-       }
-       
-       public AttributeSplitSuggestion[] 
getBestSplitSuggestions(SplitCriterion criterion) {
-
-               List<AttributeSplitSuggestion> bestSuggestions = new 
LinkedList<AttributeSplitSuggestion>();
-
-               // Set the nodeStatistics up as the preSplitDistribution, 
rather than the observedClassDistribution
-               double[] nodeSplitDist = this.nodeStatistics.getArrayCopy();
-               for (int i = 0; i < this.attributeObservers.size(); i++) {
-                       AttributeClassObserver obs = 
this.attributeObservers.get(i);
-                       if (obs != null) {
-
-                               // AT THIS STAGE NON-NUMERIC ATTRIBUTES ARE 
IGNORED
-                               AttributeSplitSuggestion bestSuggestion = null;
-                               if (obs instanceof 
FIMTDDNumericAttributeClassObserver) {
-                                       bestSuggestion = 
obs.getBestEvaluatedSplitSuggestion(criterion, nodeSplitDist, i, true);
-                               }
-
-                               if (bestSuggestion != null) {
-                                       bestSuggestions.add(bestSuggestion);
-                               }
-                       }
-               }
-               return bestSuggestions.toArray(new 
AttributeSplitSuggestion[bestSuggestions.size()]);
-       }
-       
+
+    this.perceptron.trainOnInstance(inst);
+    if (this.predictionFunction != 1) { // Train target mean if prediction
+                                        // function is not Perceptron
+      this.targetMean.trainOnInstance(inst);
+    }
+  }
+
+  protected AttributeClassObserver newNumericClassObserver() {
+    // return new FIMTDDNumericAttributeClassObserver();
+    // return new FIMTDDNumericAttributeClassLimitObserver();
+    // return
+    // 
(AttributeClassObserver)((AttributeClassObserver)this.numericObserverOption.getPreMaterializedObject()).copy();
+    FIMTDDNumericAttributeClassLimitObserver newObserver = new 
FIMTDDNumericAttributeClassLimitObserver();
+    newObserver.setMaxNodes(numericObserver.getMaxNodes());
+    return newObserver;
+  }
+
+  /*
+   * Init after being split from oldLearningNode
+   */
+  public void initialize(RuleRegressionNode oldLearningNode) {
+    if (oldLearningNode.perceptron != null)
+    {
+      this.perceptron = new Perceptron(oldLearningNode.perceptron);
+      this.perceptron.resetError();
+      this.perceptron.setLearningRatio(oldLearningNode.learningRatio);
+    }
+
+    if (oldLearningNode.targetMean != null)
+    {
+      this.targetMean = new TargetMean(oldLearningNode.targetMean);
+      this.targetMean.resetError();
+    }
+    // reset statistics
+    this.nodeStatistics.setValue(0, 0);
+    this.nodeStatistics.setValue(1, 0);
+    this.nodeStatistics.setValue(2, 0);
+  }
+
+  /*
+   * Expand
+   */
+  @Override
+  public boolean tryToExpand(double splitConfidence, double tieThreshold) {
+
+    // splitConfidence. Hoeffding Bound test parameter.
+    // tieThreshold. Hoeffding Bound test parameter.
+    SplitCriterion splitCriterion = new SDRSplitCriterionAMRules();
+    // SplitCriterion splitCriterion = new SDRSplitCriterionAMRulesNode();//JD
+    // for assessing only best branch
+
+    // Using this criterion, find the best split per attribute and rank the
+    // results
+    AttributeSplitSuggestion[] bestSplitSuggestions = 
this.getBestSplitSuggestions(splitCriterion);
+    Arrays.sort(bestSplitSuggestions);
+    // Declare a variable to determine if any of the splits should be performed
+    boolean shouldSplit = false;
+
+    // If only one split was returned, use it
+    if (bestSplitSuggestions.length < 2) {
+      shouldSplit = ((bestSplitSuggestions.length > 0) && 
(bestSplitSuggestions[0].merit > 0));
+      bestSuggestion = bestSplitSuggestions[bestSplitSuggestions.length - 1];
+    } // Otherwise, consider which of the splits proposed may be worth trying
+    else {
+      // Determine the hoeffding bound value, used to select how many instances
+      // should be used to make a test decision
+      // to feel reasonably confident that the test chosen by this sample is 
the
+      // same as what would be chosen using infinite examples
+      double hoeffdingBound = computeHoeffdingBound(1, splitConfidence, 
getInstancesSeen());
+      // Determine the top two ranked splitting suggestions
+      bestSuggestion = bestSplitSuggestions[bestSplitSuggestions.length - 1];
+      AttributeSplitSuggestion secondBestSuggestion = 
bestSplitSuggestions[bestSplitSuggestions.length - 2];
+
+      // If the upper bound of the sample mean for the ratio of SDR(best
+      // suggestion) to SDR(second best suggestion),
+      // as determined using the hoeffding bound, is less than 1, then the true
+      // mean is also less than 1, and thus at this
+      // particular moment of observation the bestSuggestion is indeed the best
+      // split option with confidence 1-delta, and
+      // splitting should occur.
+      // Alternatively, if two or more splits are very similar or identical in
+      // terms of their splits, then a threshold limit
+      // (default 0.05) is applied to the hoeffding bound; if the hoeffding
+      // bound is smaller than this limit then the two
+      // competing attributes are equally good, and the split will be made on
+      // the one with the higher SDR value.
+
+      if (bestSuggestion.merit > 0) {
+        if ((((secondBestSuggestion.merit / bestSuggestion.merit) + 
hoeffdingBound) < 1)
+            || (hoeffdingBound < tieThreshold)) {
+          shouldSplit = true;
+        }
+      }
+    }
+
+    if (shouldSplit) {
+      AttributeSplitSuggestion splitDecision = 
bestSplitSuggestions[bestSplitSuggestions.length - 1];
+      double minValue = Double.MAX_VALUE;
+      double[] branchMerits = SDRSplitCriterionAMRules
+          
.computeBranchSplitMerits(bestSuggestion.resultingClassDistributions);
+
+      for (int i = 0; i < bestSuggestion.numSplits(); i++) {
+        double value = branchMerits[i];
+        if (value < minValue) {
+          minValue = value;
+          splitIndex = i;
+          statisticsNewRuleActiveLearningNode = 
bestSuggestion.resultingClassDistributionFromSplit(i);
+        }
+      }
+      statisticsBranchSplit = 
splitDecision.resultingClassDistributionFromSplit(splitIndex);
+      statisticsOtherBranchSplit = 
bestSuggestion.resultingClassDistributionFromSplit(splitIndex == 0 ? 1 : 0);
+
+    }
+    return shouldSplit;
+  }
+
+  public AutoExpandVector<AttributeClassObserver> getAttributeObservers() {
+    return this.attributeObservers;
+  }
+
+  public AttributeSplitSuggestion[] getBestSplitSuggestions(SplitCriterion 
criterion) {
+
+    List<AttributeSplitSuggestion> bestSuggestions = new 
LinkedList<AttributeSplitSuggestion>();
+
+    // Set the nodeStatistics up as the preSplitDistribution, rather than the
+    // observedClassDistribution
+    double[] nodeSplitDist = this.nodeStatistics.getArrayCopy();
+    for (int i = 0; i < this.attributeObservers.size(); i++) {
+      AttributeClassObserver obs = this.attributeObservers.get(i);
+      if (obs != null) {
+
+        // AT THIS STAGE NON-NUMERIC ATTRIBUTES ARE IGNORED
+        AttributeSplitSuggestion bestSuggestion = null;
+        if (obs instanceof FIMTDDNumericAttributeClassObserver) {
+          bestSuggestion = obs.getBestEvaluatedSplitSuggestion(criterion, 
nodeSplitDist, i, true);
+        }
+
+        if (bestSuggestion != null) {
+          bestSuggestions.add(bestSuggestion);
+        }
+      }
+    }
+    return bestSuggestions.toArray(new 
AttributeSplitSuggestion[bestSuggestions.size()]);
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-samoa/blob/23a35dbe/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RulePassiveLearningNode.java
----------------------------------------------------------------------
diff --git 
a/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RulePassiveLearningNode.java
 
b/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RulePassiveLearningNode.java
index 4934225..5bc47f5 100644
--- 
a/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RulePassiveLearningNode.java
+++ 
b/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RulePassiveLearningNode.java
@@ -21,13 +21,12 @@ package 
com.yahoo.labs.samoa.learners.classifiers.rules.common;
  */
 
 /**
- * Interface for Rule's LearningNode that does not update
- * statistics for expanding rule. It only updates statistics for
- * computing predictions.
+ * Interface for Rule's LearningNode that does not update statistics for
+ * expanding rule. It only updates statistics for computing predictions.
  * 
  * @author Anh Thu Vu
- *
+ * 
  */
-public interface RulePassiveLearningNode  {
+public interface RulePassiveLearningNode {
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-samoa/blob/23a35dbe/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RulePassiveRegressionNode.java
----------------------------------------------------------------------
diff --git 
a/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RulePassiveRegressionNode.java
 
b/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RulePassiveRegressionNode.java
index 674e482..086c9e1 100644
--- 
a/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RulePassiveRegressionNode.java
+++ 
b/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RulePassiveRegressionNode.java
@@ -24,53 +24,53 @@ import com.yahoo.labs.samoa.instances.Instance;
 import com.yahoo.labs.samoa.moa.core.DoubleVector;
 
 /**
- * LearningNode for regression rule that does not update
- * statistics for expanding rule. It only updates statistics for
- * computing predictions.
+ * LearningNode for regression rule that does not update statistics for
+ * expanding rule. It only updates statistics for computing predictions.
  * 
  * @author Anh Thu Vu
- *
+ * 
  */
 public class RulePassiveRegressionNode extends RuleRegressionNode implements 
RulePassiveLearningNode {
 
-       /**
+  /**
         * 
         */
-       private static final long serialVersionUID = 3720878438856489690L;
-       
-       public RulePassiveRegressionNode (double[] statistics) {
-               super(statistics);
-       }
-       
-       public RulePassiveRegressionNode() {
-               super();
-       }
-       
-       public RulePassiveRegressionNode(RuleRegressionNode activeLearningNode) 
{
-               this.predictionFunction = activeLearningNode.predictionFunction;
-               this.ruleNumberID = activeLearningNode.ruleNumberID;
-               this.nodeStatistics = new 
DoubleVector(activeLearningNode.nodeStatistics);
-               this.learningRatio = activeLearningNode.learningRatio;
-               this.perceptron = new Perceptron(activeLearningNode.perceptron, 
true);
-               this.targetMean = new TargetMean(activeLearningNode.targetMean);
-       }
-       
-       /*
-        * Update with input instance
-        */
-       @Override
-       public void updateStatistics(Instance inst) {
-               // Update the statistics for this node
-               // number of instances passing through the node
-               nodeStatistics.addToValue(0, 1);
-               // sum of y values
-               nodeStatistics.addToValue(1, inst.classValue());
-               // sum of squared y values
-               nodeStatistics.addToValue(2, 
inst.classValue()*inst.classValue());
-                               
-               this.perceptron.trainOnInstance(inst);
-               if (this.predictionFunction != 1) { //Train target mean if 
prediction function is not Perceptron
-                       this.targetMean.trainOnInstance(inst);
-               }
-       }
+  private static final long serialVersionUID = 3720878438856489690L;
+
+  public RulePassiveRegressionNode(double[] statistics) {
+    super(statistics);
+  }
+
+  public RulePassiveRegressionNode() {
+    super();
+  }
+
+  public RulePassiveRegressionNode(RuleRegressionNode activeLearningNode) {
+    this.predictionFunction = activeLearningNode.predictionFunction;
+    this.ruleNumberID = activeLearningNode.ruleNumberID;
+    this.nodeStatistics = new DoubleVector(activeLearningNode.nodeStatistics);
+    this.learningRatio = activeLearningNode.learningRatio;
+    this.perceptron = new Perceptron(activeLearningNode.perceptron, true);
+    this.targetMean = new TargetMean(activeLearningNode.targetMean);
+  }
+
+  /*
+   * Update with input instance
+   */
+  @Override
+  public void updateStatistics(Instance inst) {
+    // Update the statistics for this node
+    // number of instances passing through the node
+    nodeStatistics.addToValue(0, 1);
+    // sum of y values
+    nodeStatistics.addToValue(1, inst.classValue());
+    // sum of squared y values
+    nodeStatistics.addToValue(2, inst.classValue() * inst.classValue());
+
+    this.perceptron.trainOnInstance(inst);
+    if (this.predictionFunction != 1) { // Train target mean if prediction
+                                        // function is not Perceptron
+      this.targetMean.trainOnInstance(inst);
+    }
+  }
 }

Reply via email to