All Downloads are FREE. Search and download functionalities are using the official Maven repository.

weka.core.pmml.Array Maven / Gradle / Ivy

/*
 *   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 3 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, see .
 */

/*
 *    Array.java
 *    Copyright (C) 2009-2012 University of Waikato, Hamilton, New Zealand
 *
 */

package weka.core.pmml;

import java.io.Serializable;
import java.io.StreamTokenizer;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;

import org.w3c.dom.Element;

/**
 * Class for encapsulating a PMML Array element.
 * 
 * @author Mark Hall (mhall{[at]}pentaho{[dot]}com)
 * @version $Revision: 10203 $
 */
public class Array implements Serializable {

  /** ID added to avoid warning */
  private static final long serialVersionUID = 4286234448957826177L;

  /**
   * Utility method to check if an XML element is an array.
   * 
   * @param arrayE the XML element to check
   * @return returns true if the XML element is an array
   */
  public static boolean isArray(Element arrayE) {
    String name = arrayE.getTagName();

    if (name.equals("Array") || name.equals("NUM-ARRAY")
      || name.equals("INT-ARRAY") || name.equals("REAL-ARRAY")
      || name.equals("STRING-ARRAY") || isSparseArray(arrayE)) {
      return true;
    }
    return false;
  }

  /**
   * Utility method to check if an XML element is a sparse array.
   * 
   * @param arrayE the XML element to check.
   * @return true if the XML element is a sparse array.
   */
  private static boolean isSparseArray(Element arrayE) {
    String name = arrayE.getTagName();

    if (name.equals("INT-SparseArray") || name.equals("REAL-SparseArray")) {
      return true;
    }

    return false;
  }

  public static Array create(List values, List indices)
    throws Exception {

    ArrayType type = null;

    Object first = values.get(0);
    if ((first instanceof Double) || (first instanceof Float)) {
      type = ArrayType.REAL;
    } else if ((first instanceof Integer) || (first instanceof Long)) {
      type = ArrayType.INT;
    } else if ((first instanceof String)) {
      type = ArrayType.STRING;
    } else {
      throw new Exception("[Array] unsupport type!");
    }

    if (indices != null) {
      // array is sparse

      if (indices.size() != values.size()) {
        throw new Exception("[Array] num values is not equal to num indices!!");
      }

      if (type == ArrayType.REAL) {
        type = ArrayType.REAL_SPARSE;
      } else if (type == ArrayType.INT) {
        type = ArrayType.INT_SPARSE;
      } else {
        throw new Exception(
          "[Array] sparse arrays can only be integer, long, float or double!");
      }

      return new SparseArray(type, values, indices);
    }

    return new Array(type, values);
  }

  /**
   * Static factory method for creating non-sparse or sparse array types as
   * needed.
   * 
   * @param arrayE the XML element encapsulating the array
   * @return an appropriate Array type
   * @throws Exception if there is a problem when constructing the array
   */
  public static Array create(Element arrayE) throws Exception {
    if (!isArray(arrayE)) {
      throw new Exception(
        "[Array] the supplied element does not contain an array!");
    }

    if (isSparseArray(arrayE)) {
      return new SparseArray(arrayE);
    }

    return new Array(arrayE);
  }

  public static enum ArrayType {
    NUM("NUM-ARRAY"), INT("INT-ARRAY"), REAL("REAL-ARRAY"), STRING(
      "STRING-ARRAY"), REAL_SPARSE("REAL-SparseArray"), INT_SPARSE(
      "INT-SparseArray");

    private final String m_stringVal;

    ArrayType(String name) {
      m_stringVal = name;
    }

    @Override
    public String toString() {
      return m_stringVal;
    }
  }

  /** The values of the array */
  protected ArrayList m_values = new ArrayList();

  /** The type of the array */
  protected ArrayType m_type = ArrayType.NUM;

  protected void initialize(Element arrayE) throws Exception {
    String arrayS = arrayE.getTagName();

    // get the type of the array
    if (arrayS.equals("Array")) {
      String type = arrayE.getAttribute("type");
      if (type.equals("int")) {
        m_type = ArrayType.INT;
      } else if (type.equals("real")) {
        m_type = ArrayType.REAL;
      } else if (type.equals("string")) {
        m_type = ArrayType.STRING;
      }
    } else {
      for (ArrayType a : ArrayType.values()) {
        if (a.toString().equals(arrayS)) {
          m_type = a;
          break;
        }
      }
    }
    // now read the values
    String contents = arrayE.getChildNodes().item(0).getNodeValue();
    StringReader sr = new StringReader(contents);
    StreamTokenizer st = new StreamTokenizer(sr);
    st.resetSyntax();
    st.whitespaceChars(0, ' ');
    st.wordChars(' ' + 1, '\u00FF');
    st.whitespaceChars(' ', ' ');
    st.quoteChar('"');
    st.quoteChar('\'');
    // m_Tokenizer.eolIsSignificant(true);

    st.nextToken();
    while (st.ttype != StreamTokenizer.TT_EOF
      && st.ttype != StreamTokenizer.TT_EOL) {
      m_values.add(st.sval);
      st.nextToken();
    }
  }

  /**
   * Construct an array from an XML node
   * 
   * @param arrayE the Element containing the XML
   * @throws Exception if something goes wrong
   */
  protected Array(Element arrayE) throws Exception {
    initialize(arrayE);
  }

  /**
   * Construct an array from the given values.
   * 
   * @param type the type of the elements.
   * @param values the values of the array.
   */
  protected Array(ArrayType type, List values) {
    m_values = new ArrayList();
    m_type = type;

    for (Object o : values) {
      m_values.add(o.toString());
    }
  }

  /**
   * Get the type of this array.
   * 
   * @return the type of the array.
   */
  public ArrayType getType() {
    return m_type;
  }

  /**
   * Is this array a SparseArray?
   * 
   * @return true if this array is sparse.
   */
  public boolean isSparse() {
    return false;
  }

  /**
   * Get the number of values in this array.
   * 
   * @return the number of values in this array.
   */
  public int numValues() {
    return m_values.size();
  }

  /**
   * Returns true if the array contains this string value.
   * 
   * @param value the value to check for.
   * @return true if the array contains this string value
   */
  public boolean contains(String value) {
    return m_values.contains(value);
  }

  /**
   * Returns true if the array contains this integer value.
   * 
   * @param value the value to check for
   * @return true if the array contains this integer value
   */
  public boolean contains(int value) {
    return contains(new Integer(value).toString());
  }

  /**
   * Returns true if the array contains this real value.
   * 
   * @param value the value to check for
   * @return true if the array contains this real value
   */
  public boolean contains(double value) {
    return contains(new Double(value).toString());
  }

  /**
   * Returns true if the array contains this real value.
   * 
   * @param value the value to check for
   * @return true if the array contains this real value
   */
  public boolean contains(float value) {
    return contains(new Float(value).toString());
  }

  private void checkInRange(int index) throws Exception {
    if (index >= m_values.size() || index < 0) {
      throw new IllegalArgumentException("[Array] index out of range " + index);
    }
  }

  /**
   * Returns the index of the value stored at the given position
   * 
   * @param position the position
   * @return the index of the value stored at the given position
   */
  public int index(int position) {
    return position; // position is the index for dense arrays
  }

  /**
   * Gets the value at index from the array.
   * 
   * @param index the index of the value to get.
   * @return the value at index in the array as as String.
   * @throws Exception if index is out of bounds.
   */
  public String value(int index) throws Exception {
    return actualValue(index);
  }

  /**
   * Gets the value at index from the array
   * 
   * @param index the index of the value to get.
   * @return the value at index in the array as as String.
   * @throws Exception if index is out of bounds.
   */
  protected String actualValue(int index) throws Exception {
    checkInRange(index);
    return m_values.get(index);
  }

  /**
   * Gets the value at index from the array as a String. Calls value().
   * 
   * @param index the index of the value to get.
   * @return the value at index in the array as a String.
   * @throws Exception if index is out of bounds.
   */
  public String valueString(int index) throws Exception {
    return value(index);
  }

  /**
   * Gets the value at index from the array as a double.
   * 
   * @param index the index of the value to get.
   * @return the value at index in the array as a double.
   * @throws Exception if index is out of bounds.
   */
  public double valueDouble(int index) throws Exception {
    if (m_type == ArrayType.STRING) {
      throw new Exception("[Array] Array does not contain numbers!");
    }
    return Double.parseDouble(value(index));
  }

  /**
   * Gets the value at index from the array as a float.
   * 
   * @param index the index of the value to get.
   * @return the value at index in the array as a float.
   * @throws Exception if index is out of bounds.
   */
  public float valueFloat(int index) throws Exception {
    if (m_type == ArrayType.STRING) {
      throw new Exception("[Array] Array does not contain numbers!");
    }
    return Float.parseFloat(value(index));
  }

  /**
   * Gets the value at index from the array as an int.
   * 
   * @param index the index of the value to get.
   * @return the value at index in the array as an int.
   * @throws Exception if index is out of bounds.
   */
  public int valueInt(int index) throws Exception {
    if (m_type != ArrayType.INT && m_type != ArrayType.INT_SPARSE) {
      throw new Exception("[Array] Array does not contain integers!");
    }
    return Integer.parseInt(value(index));
  }

  /**
   * Gets the value at indexOfIndex from the array. Does the same as value() if
   * this array is not sparse.
   * 
   * @param indexOfIndex the index of the index of the value to get.
   * @return a value from the array as a String.
   * @throws Exception if indexOfIndex is out of bounds.
   */
  public String valueSparse(int indexOfIndex) throws Exception {
    return actualValue(indexOfIndex);
  }

  /**
   * Gets the value at indexOfIndex from the array. Does the same as value() if
   * this array is not sparse.
   * 
   * @param indexOfIndex the index of the index of the value to get.
   * @return a value from the array as a String.
   * @throws Exception if indexOfIndex is out of bounds.
   */
  public String valueSparseString(int indexOfIndex) throws Exception {
    return valueSparse(indexOfIndex);
  }

  /**
   * Gets the value at indexOfIndex from the array. Does the same as value() if
   * this array is not sparse.
   * 
   * @param indexOfIndex the index of the index of the value to get.
   * @return a value from the array as a double.
   * @throws Exception if indexOfIndex is out of bounds.
   */
  public double valueSparseDouble(int indexOfIndex) throws Exception {
    return Double.parseDouble(actualValue(indexOfIndex));
  }

  /**
   * Gets the value at indexOfIndex from the array. Does the same as value() if
   * this array is not sparse.
   * 
   * @param indexOfIndex the index of the index of the value to get.
   * @return a value from the array as a float.
   * @throws Exception if indexOfIndex is out of bounds.
   */
  public float valueSparseFloat(int indexOfIndex) throws Exception {
    return Float.parseFloat(actualValue(indexOfIndex));
  }

  /**
   * Gets the value at indexOfIndex from the array. Does the same as value() if
   * this array is not sparse.
   * 
   * @param indexOfIndex the index of the index of the value to get.
   * @return a value from the array as an int.
   * @throws Exception if indexOfIndex is out of bounds.
   */
  public int valueSparseInt(int indexOfIndex) throws Exception {
    return Integer.parseInt(actualValue(indexOfIndex));
  }

  @Override
  public String toString() {
    StringBuffer text = new StringBuffer();

    text.append("<");
    for (int i = 0; i < m_values.size(); i++) {
      text.append(m_values.get(i));
      if (i < m_values.size() - 1) {
        text.append(",");
      }
    }

    text.append(">");
    return text.toString();
  }
}