package weka.core.pmml; import java.util.ArrayList; import weka.core.Attribute; /** * Built-in function for uppercase, substring and trimblanks. * * @author Mark Hall (mhall{[at]}pentaho{[dot]}com * @version $Revision 1.0 $ */ public class BuiltInString extends Function { /** * For serialization */ private static final long serialVersionUID = -7391516909331728653L; /** * Enum for the string functions */ enum StringFunc { UPPERCASE ("uppercase") { String eval(Object[] args) { return ((String)args[0]).toUpperCase(); } boolean legalNumParams(int num) { return (num == 1); } String[] getParameterNames() { return new String[] {"input"}; } }, SUBSTRING ("substring") { String eval(Object[] args) { String input = (String)args[0]; int startPos = ((Integer)args[1]).intValue(); int length = ((Integer)args[2]).intValue(); return input.substring(startPos-1, startPos + length); } boolean legalNumParams(int num) { return (num == 3); } String[] getParameterNames() { return new String[] {"input", "startPos", "length"}; } }, TRIMBLANKS ("trimBlanks") { String eval(Object[] args) { return ((String)args[0]).trim(); } boolean legalNumParams(int num) { return (num == 1); } String[] getParameterNames() { return new String[] {"input"}; } }; abstract String eval(Object[] args); abstract boolean legalNumParams(int num); abstract String[] getParameterNames(); private String m_stringVal; StringFunc(String funcName) { m_stringVal = funcName; } public String toString() { return m_stringVal; } } /** The function to apply */ protected StringFunc m_func; /** The output structure produced by this function */ protected Attribute m_outputDef = null; BuiltInString(StringFunc func) { m_func = func; m_functionName = m_func.toString(); } /** * Get the structure of the result produced by this function. * Subclasses must implement. * * @return the structure of the result produced by this function. */ public Attribute getOutputDef() { if (m_outputDef == null) { if (m_func == StringFunc.SUBSTRING) { // there is no way we can compute the legal values for this attribute // in advance of the application of this function. So return a string attribute m_outputDef = new Attribute("BuiltInStringResult:substring", (ArrayList<String>)null); } // for the other functions we can compute the resulting set of values Attribute inputVals = m_parameterDefs.get(0); ArrayList<String> newVals = new ArrayList<String>(); for (int i = 0; i < inputVals.numValues(); i++) { String inVal = inputVals.value(i); newVals.add(m_func.eval(new Object[] {inVal})); } m_outputDef = new Attribute("BuiltInStringResult:" + m_func.toString(), newVals); } return m_outputDef; } /** * Returns an array of the names of the parameters expected * as input by this function. May return null if the function * can accept an unbounded number of arguments. * * @return an array of the parameter names (or null if the function * can accept any number of arguments). */ public String[] getParameterNames() { return m_func.getParameterNames(); } private Object[] setUpArgs(double[] incoming) { // construct the input to the function Object[] args = new Object[incoming.length]; Attribute input = m_parameterDefs.get(0); args[0] = input.value((int)incoming[0]); for (int i = 1; i < incoming.length; i++) { args[i] = new Integer((int)incoming[i]); } return args; } /** * Get the result of applying this function. * * @param incoming the arguments to this function (supplied in order to match that * of the parameter definitions * @return the result of applying this function. When the optype is * categorical or ordinal, an index into the values of the output definition * is returned. * @throws Exception if there is a problem computing the result of this function */ public double getResult(double[] incoming) throws Exception { if (m_parameterDefs == null) { throw new Exception("[BuiltInString] incoming parameter structure has not been set"); } if (!m_func.legalNumParams(incoming.length)) { throw new Exception("[BuiltInString] wrong number of parameters!"); } // construct the input to the function Object[] args = setUpArgs(incoming); // get the result String result = m_func.eval(args); int resultI = m_outputDef.indexOfValue(result); if (resultI < 0) { if (m_outputDef.isString()) { // add this as a new value resultI = m_outputDef.addStringValue(result); } else { throw new Exception("[BuiltInString] unable to find value " + result + " in nominal result type!"); } } return resultI; } /** * Get the result of applying this function when the output type categorical. * Will throw an exception for numeric output. If subclasses output definition * is a string attribute (i.e. because all legal values can't be computed apriori), * then the subclass will need to overide this method and return something sensible * in this case. * * @param incoming the incoming arguments to this function (supplied in order to match * that of the parameter definitions * @return the result of applying this function as a String. * @throws Exception if this method is not applicable because the optype is not * categorical/ordinal * public String getResultCategorical(double[] incoming) throws Exception { if (m_parameterDefs == null) { throw new Exception("[BuiltInString] incoming parameter structure has not been set"); } if (!m_func.legalNumParams(incoming.length)) { throw new Exception("[BuiltInString] wrong number of parameters!"); } // construct the input to the function Object[] args = setUpArgs(incoming); // get the result String result = m_func.eval(args); return result; }*/ /** * Set the structure of the parameters that are expected as input by * this function. This must be called before getOutputDef() is called. * * @param paramDefs the structure of the input parameters * @throws Exception if the number or types of parameters are not acceptable by * this function */ public void setParameterDefs(ArrayList<Attribute> paramDefs) throws Exception { m_parameterDefs = paramDefs; if (!m_func.legalNumParams(m_parameterDefs.size())) { throw new Exception("[BuiltInMath] illegal number of parameters for function: " + m_functionName); } } public String toString() { String result = m_func.toString() + "("; for (int i = 0; i < m_parameterDefs.size(); i++) { result += m_parameterDefs.get(i).name(); if (i != m_parameterDefs.size() - 1) { result += ", "; } else { result += ")"; } } return result; } }