content: /*
   *    This program is free software; you can redistribute it and/or modify
   *    it under the terms of the GNU General Public License as published by
   *    the Free Software Foundation; either version 2 of the License, or
   *    (at your option) any later version.
   *
   *    This program is distributed in the hope that it will be useful,
   *    but WITHOUT ANY WARRANTY; without even the implied warranty of
   *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *    GNU General Public License for more details.
   *
   *    You should have received a copy of the GNU General Public License
   *    along with this program; if not, write to the Free Software
   *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   */
  
  /*
   * ClusterGenerator.java
   * Copyright (C) 2000 University of Waikato, Hamilton, New Zealand
   *
   */
  
  package weka.datagenerators;
  
  import weka.core.Option;
  import weka.core.Range;
  import weka.core.Utils;
  import weka.datagenerators.DataGenerator;
  
  import java.util.Enumeration;
  import java.util.Vector;
  
  /** 
   * Abstract class for cluster data generators. <p/>
   *
   * Example usage as the main of a datagenerator called RandomGenerator:
   * <pre>
   * public static void main(String[] args) {
   *   try {
   *     DataGenerator.makeData(new RandomGenerator(), args);
   *   } 
   *   catch (Exception e) {
   *     e.printStackTrace();
   *     System.err.println(e.getMessage());
   *   }
   * }
   * </pre>
   * <p/>
   *
   * @author Gabi Schmidberger (gabi@cs.waikato.ac.nz)
   * @author FracPete (fracpete at waikato dot ac dot nz)
   * @version $Revision: 1.6 $
   */
  public abstract class ClusterGenerator 
    extends DataGenerator {
  
    /** for serialization */
    private static final long serialVersionUID = 6131722618472046365L;
  
    /** Number of attribute the dataset should have */
    protected int m_NumAttributes;
  
    /** class flag  */
    protected boolean m_ClassFlag = false;
  
    /** Stores which columns are boolean (default numeric) */
    protected Range m_booleanCols;
  
    /** Stores which columns are nominal (default numeric)  */
    protected Range m_nominalCols;
  
    /**
     * initializes the generator 
     */
    public ClusterGenerator() {
      super();
  
      setNumAttributes(defaultNumAttributes());
    }
    
    /**
     * Returns an enumeration describing the available options.
     *
     * @return an enumeration of all the available options.
     */
    public Enumeration listOptions() {
      Vector result = enumToVector(super.listOptions());
  
      result.addElement(new Option(
            "\tThe number of attributes (default " 
            + defaultNumAttributes() + ").",
            "a", 1, "-a <num>"));
  
      result.addElement(new Option(
          "\tClass Flag, if set, the cluster is listed in extra attribute.",
          "c", 0, "-c"));
      
      result.addElement(new Option(
          "\tThe indices for boolean attributes.",
          "b", 1, "-b <range>"));
      
      result.addElement(new Option(
          "\tThe indices for nominal attributes.",
          "m", 1, "-m <range>"));
      
      return result.elements();
    }
  
    /**
     * Sets the options.
     *
     * @param options the options 
     * @throws Exception if invalid option
     */
    public void setOptions(String[] options) throws Exception { 
      String        tmpStr;
     
      super.setOptions(options);
  
      tmpStr = Utils.getOption('a', options);
      if (tmpStr.length() != 0)
        setNumAttributes(Integer.parseInt(tmpStr));
      else
        setNumAttributes(defaultNumAttributes());
  
      setClassFlag(Utils.getFlag('c', options));
  
      tmpStr = Utils.getOption('b', options);
      setBooleanIndices(tmpStr);
      m_booleanCols.setUpper(getNumAttributes());
  
      tmpStr = Utils.getOption('m', options);
      setNominalIndices(tmpStr);
      m_nominalCols.setUpper(getNumAttributes());
  
      // check indices
      tmpStr = checkIndices();
      if (tmpStr.length() > 0)
        throw new IllegalArgumentException(tmpStr);
    }
    
    /**
     * Gets the current settings of the classifier.
     *
     * @return an array of strings suitable for passing to setOptions
     */
    public String[] getOptions() {
      Vector        result;
      String[]      options;
      int           i;
      
      result  = new Vector();
      options = super.getOptions();
      for (i = 0; i < options.length; i++)
        result.add(options[i]);
      
      result.add("-a");
      result.add("" + getNumAttributes());
  
      if (getClassFlag())
        result.add("-c");
      
      if (!getBooleanCols().toString().equalsIgnoreCase("empty")) {
        result.add("-b");
        result.add("" + getBooleanCols());
      }
      
      if (!getNominalCols().toString().equalsIgnoreCase("empty")) {
        result.add("-m");
        result.add("" + getNominalCols());
      }
      
      return (String[]) result.toArray(new String[result.size()]);
    }
  
    /**
     * returns the default number of attributes
     * 
     * @return the default number of attributes
     */
    protected int defaultNumAttributes() {
      return 10;
    }
  
    /**
     * Sets the number of attributes the dataset should have.
     * @param numAttributes the new number of attributes
     */
    public void setNumAttributes(int numAttributes) {
      m_NumAttributes = numAttributes;
      getBooleanCols().setUpper(getNumAttributes());
      getNominalCols().setUpper(getNumAttributes());
    }
  
    /**
     * Gets the number of attributes that should be produced.
     * @return the number of attributes that should be produced
     */
    public int getNumAttributes() { 
      return m_NumAttributes; 
    }
    
    /**
     * Returns the tip text for this property
     * 
     * @return tip text for this property suitable for
     *         displaying in the explorer/experimenter gui
     */
    public String numAttributesTipText() {
      return "The number of attributes the generated data will contain.";
    }
  
    /**
     * Sets the class flag, if class flag is set, 
     * the cluster is listed as class atrribute in an extra attribute.
     * @param classFlag the new class flag
     */
    public void setClassFlag(boolean classFlag) { 
      m_ClassFlag = classFlag; 
    }
  
    /**
     * Gets the class flag.
     * @return the class flag 
     */
    public boolean getClassFlag() {
      return m_ClassFlag; 
    }
    
    /**
     * Returns the tip text for this property
     * 
     * @return tip text for this property suitable for
     *         displaying in the explorer/experimenter gui
     */
    public String classFlagTipText() {
      return "If set to TRUE, lists the cluster as an extra attribute.";
    }
  
    /**
     * Sets which attributes are boolean 
     * @param rangeList a string representing the list of attributes. Since
     * the string will typically come from a user, attributes are indexed from
     * 1. <br/>
     * eg: first-3,5,6-last
     * @throws IllegalArgumentException if an invalid range list is supplied 
     */
    public void setBooleanIndices(String rangeList) {
      m_booleanCols.setRanges(rangeList);
    }
  
    /**
     * Sets which attributes are boolean.
     * @param value the range to use
     */
    public void setBooleanCols(Range value) {
      m_booleanCols.setRanges(value.getRanges());
    }
  
    /**
     * returns the range of boolean attributes.
     * 
     * @return the range of boolean attributes
     */
    public Range getBooleanCols() {
      if (m_booleanCols == null)
        m_booleanCols = new Range();
  
      return m_booleanCols;
    }
    
    /**
     * Returns the tip text for this property
     * 
     * @return tip text for this property suitable for
     *         displaying in the explorer/experimenter gui
     */
    public String booleanColsTipText() {
      return "The range of attributes that are generated as boolean ones.";
    }
  
    /**
     * Sets which attributes are nominal
     * @param rangeList a string representing the list of attributes. Since
     * the string will typically come from a user, attributes are indexed from
     * 1. <br/>
     * eg: first-3,5,6-last
     * @throws IllegalArgumentException if an invalid range list is supplied 
     */
    public void setNominalIndices(String rangeList) {
      m_nominalCols.setRanges(rangeList);
    }
  
    /**
     * Sets which attributes are nominal.
     * @param value the range to use
     */
    public void setNominalCols(Range value) {
      m_nominalCols.setRanges(value.getRanges());
    }
  
    /**
     * returns the range of nominal attributes
     * 
     * @return the range of nominal attributes
     */
    public Range getNominalCols() {
      if (m_nominalCols == null)
        m_nominalCols = new Range();
  
      return m_nominalCols;
    }
    
    /**
     * Returns the tip text for this property
     * 
     * @return tip text for this property suitable for
     *         displaying in the explorer/experimenter gui
     */
    public String nominalColsTipText() {
      return "The range of attributes to generate as nominal ones.";
    }
  
    /**
     * check if attribute types are not contradicting
     * 
     * @return empty string if no problem, otherwise error message
     */
    protected String checkIndices() {
      for (int i = 1; i < getNumAttributes() + 1; i++) {
        m_booleanCols.isInRange(i);
        if (m_booleanCols.isInRange(i) && m_nominalCols.isInRange(i)) {
  	return   "Error in attribute type: Attribute " 
                 + i + " is set boolean and nominal.";
        }
      } 
      return "";
    }
  }
  
  
  