public Object clone() {
    
    ADTree clone = new ADTree();

    if (m_root != null) { // check for initialization first
      clone.m_root = (PredictionNode) m_root.clone(); // deep copy the tree

      clone.m_trainInstances = new Instances(m_trainInstances); // copy training instances
      
      // deep copy the random object
      if (m_random != null) { 
	SerializedObject randomSerial = null;
	try {
	  randomSerial = new SerializedObject(m_random);
	} catch (Exception ignored) {} // we know that Random is serializable
	clone.m_random = (Random) randomSerial.getObject();
      }

      clone.m_lastAddedSplitNum = m_lastAddedSplitNum;
      clone.m_numericAttIndices = m_numericAttIndices;
      clone.m_nominalAttIndices = m_nominalAttIndices;
      clone.m_trainTotalWeight = m_trainTotalWeight;

      // reconstruct pos/negTrainInstances references
      if (m_posTrainInstances != null) { 
	clone.m_posTrainInstances =
	  new ReferenceInstances(m_trainInstances, m_posTrainInstances.numInstances());
	clone.m_negTrainInstances =
	  new ReferenceInstances(m_trainInstances, m_negTrainInstances.numInstances());
	for (Enumeration e = clone.m_trainInstances.enumerateInstances();
	     e.hasMoreElements(); ) {
	  Instance inst = (Instance) e.nextElement();
	  try { // ignore classValue() exception
	    if ((int) inst.classValue() == 0)
	      clone.m_negTrainInstances.addReference(inst); // belongs in negative class
	    else
	      clone.m_posTrainInstances.addReference(inst); // belongs in positive class
	  } catch (Exception ignored) {} 
	}
      }
    }
    clone.m_nodesExpanded = m_nodesExpanded;
    clone.m_examplesCounted = m_examplesCounted;
    clone.m_boostingIterations = m_boostingIterations;
    clone.m_searchPath = m_searchPath;
    clone.m_randomSeed = m_randomSeed;

    return clone;
  }