/* * 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 <http://www.gnu.org/licenses/>. */ /* * Expression.java * Copyright (C) 2008-2012 University of Waikato, Hamilton, New Zealand * */ package weka.core.pmml; import java.io.Serializable; import java.util.ArrayList; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import weka.core.Attribute; public abstract class Expression implements Serializable { /** * For serialization */ private static final long serialVersionUID = 4448840549804800321L; /** The optype of this Expression */ protected FieldMetaInfo.Optype m_opType; /** The field defs */ protected ArrayList<Attribute> m_fieldDefs = null; // NOTE - might need to pass in mining schema in order // to determine values for nominal optypes public Expression(FieldMetaInfo.Optype opType, ArrayList<Attribute> fieldDefs) { m_opType = opType; m_fieldDefs = fieldDefs; } /** * Set the field definitions for this Expression to use * * @param fieldDefs the field definitions to use * @throws Exception if there is a problem setting the field definitions */ public void setFieldDefs(ArrayList<Attribute> fieldDefs) throws Exception { m_fieldDefs = fieldDefs; } /** * Get the result of evaluating the expression. In the case * of a continuous optype, a real number is returned; in * the case of a categorical/ordinal optype, the index of the nominal * value is returned as a double. * * @param incoming the incoming parameter values * @return the result of evaluating the expression * @throws Exception if there is a problem computing the result */ public abstract double getResult(double[] incoming) throws Exception; /** * Get the result of evaluating the expression for continuous * optype. Is the same as calling getResult() when the optype * is continuous. * * @param incoming the incoming parameter values * mining schema * @return the result of evaluating the expression. * @throws Exception if the optype is not continuous. */ public double getResultContinuous(double[] incoming) throws Exception { if (!(m_opType == FieldMetaInfo.Optype.CONTINUOUS)) { throw new Exception("[Expression] Can't return continuous result " + "as optype is not continuous"); } return getResult(incoming); } /** * Gets the result of evaluating the expression when the * optype is categorical or ordinal as the actual String * value. * * @param incoming the incoming parameter values * @return the result of evaluating the expression * @throws Exception if the optype is continuous */ public abstract String getResultCategorical(double[] incoming) throws Exception; /** * Return the structure of the result of applying this Expression * as an Attribute. * * @return the structure of the result of applying this Expression as an * Attribute. */ protected abstract Attribute getOutputDef(); /** * Static factory method that returns a subclass of Expression that * encapsulates the type of expression contained in the Element * supplied. Assumes that there is just one expression contained * in the supplied Element. * * @param container the Node containing the expression * @param opType the optype of the value returned by this Expression. * @param fieldDefs an ArrayList of Attributes for the fields that this * Expression may need to access * Since Expressions are children of either DerivedFields or * DefineFuntions, they will have the same optype as their parent. * @param transDict the TransformationDictionary (may be null if there * is no dictionary) * @return an Expression object or null if there is no known expression in * the container * @throws Exception for unsupported Expression types */ public static Expression getExpression(Node container, FieldMetaInfo.Optype opType, ArrayList<Attribute> fieldDefs, TransformationDictionary transDict) throws Exception { // we need to examine children of this Node to find an expression, // not the entire subtree (as would be returned by Element.getElementsByTagName() Expression result = null; String tagName = ""; NodeList children = container.getChildNodes(); if (children.getLength() == 0) { throw new Exception("[Expression] container has no children!"); } // at this level in the tree there should be only one expression type // specified - look for it here. for (int i = 0; i < children.getLength(); i++) { Node child = children.item(i); if (child.getNodeType() == Node.ELEMENT_NODE) { tagName = ((Element)child).getTagName(); result = getExpression(tagName, child, opType, fieldDefs, transDict); if (result != null) { break; } } } return result; } /** * Static factory method that returns a subclass of Expression that * encapsulates the type of expression supplied as an argument. * * @param name the name of the Expression to get * @param expression the Node containing the expression * @param opType the optype of the value returned by this Expression. * @param fieldDefs an ArrayList of Attributes for the fields that this * Expression may need to access * Since Expressions are children of either DerivedFields or * DefineFuntions, they will have the same optype as their parent. * @param transDict the TransformationDictionary (may be null if there * is no dictionary) * @return an Expression object or null if there is no known expression in * the container * @throws Exception for unsupported Expression types */ public static Expression getExpression(String name, Node expression, FieldMetaInfo.Optype opType, ArrayList<Attribute> fieldDefs, TransformationDictionary transDict) throws Exception { Expression result = null; if (name.equals("Constant")) { // construct a Constant expression result = new Constant((Element)expression, opType, fieldDefs); } else if (name.equals("FieldRef")) { // construct a FieldRef expression result = new FieldRef((Element)expression, opType, fieldDefs); } else if (name.equals("Apply")) { // construct an Apply expression result = new Apply((Element)expression, opType, fieldDefs, transDict); } else if (name.equals("NormDiscrete")) { result = new NormDiscrete((Element)expression, opType, fieldDefs); } else if (name.equals("NormContinuous")) { result = new NormContinuous((Element)expression, opType, fieldDefs); } else if (name.equals("Discretize")) { result = new Discretize((Element)expression, opType, fieldDefs); } else if (name.equals("MapValues") || name.equals("Aggregate")) { throw new Exception("[Expression] Unhandled Expression type " + name); } return result; } /** * Return the named attribute from the list of reference fields. * * @param attName the name of the attribute to retrieve * @return the named attribute (or null if it can't be found). */ public Attribute getFieldDef(String attName) { Attribute returnV = null; for (int i = 0; i < m_fieldDefs.size(); i++) { if (m_fieldDefs.get(i).name().equals(attName)) { returnV = m_fieldDefs.get(i); break; } } return returnV; } public int getFieldDefIndex(String attName) { int returnV = -1; for (int i = 0; i < m_fieldDefs.size(); i++) { if (m_fieldDefs.get(i).name().equals(attName)) { returnV = i; break; } } return returnV; } /** * Get the optype of the result of applying this Expression. * * @return the optype of the result of applying this Expression */ public FieldMetaInfo.Optype getOptype() { return m_opType; } public String toString() { return toString(""); } public String toString(String pad) { return pad + this.getClass().getName(); } }