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

org.apache.sysml.parser.Expression Maven / Gradle / Ivy

There is a newer version: 1.2.0
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.apache.sysml.parser;

import java.util.ArrayList;
import java.util.HashMap;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.sysml.hops.Hop.FileFormatTypes;


public abstract class Expression 
{
	
	public enum Kind {
		UnaryOp, BinaryOp, BooleanOp, BuiltinFunctionOp, ParameterizedBuiltinFunctionOp, DataOp, Data, Literal, RelationalOp, ExtBuiltinFunctionOp, FunctionCallOp
	};

	public enum BinaryOp {
		PLUS, MINUS, MULT, DIV, MODULUS, INTDIV, MATMULT, POW, INVALID
	};

	public enum RelationalOp {
		LESSEQUAL, LESS, GREATEREQUAL, GREATER, EQUAL, NOTEQUAL, INVALID
	};

	public enum BooleanOp {
		CONDITIONALAND, CONDITIONALOR, LOGICALAND, LOGICALOR, NOT, INVALID
	};

	public enum BuiltinFunctionOp { 
		ABS, 
		ACOS,
		ASIN, 
		ATAN,
		AVG,
		CAST_AS_BOOLEAN,
		CAST_AS_DOUBLE,
		CAST_AS_INT,
		CAST_AS_MATRIX,
		CAST_AS_SCALAR,
		CBIND, //previously APPEND
		CEIL,
		CHOLESKY,
		COLMAX,
		COLMEAN,
		COLMIN,
		COLSD,
		COLSUM,
		COLVAR,
		COS,
		COV,
		CUMMAX,
		CUMMIN,
		CUMPROD,
		CUMSUM,
		DIAG,
		EIGEN,
		EXP,
		FLOOR,
		INTERQUANTILE,
		INVERSE,
		IQM,
		LENGTH, 
		LOG,
		LU,
		MAX,
		MEAN,
		MEDIAN,
		MIN,
		MOMENT, 
		NCOL, 
		NROW,
		OUTER,
		PPRED, 
		PROD,
		QR,
		QUANTILE,
		RANGE,
		RBIND,
		REV,
		ROUND,
		ROWINDEXMAX,
		ROWINDEXMIN,
		ROWMAX,
		ROWMEAN, 
		ROWMIN,
		ROWSD,
		ROWSUM,
		ROWVAR,
		SAMPLE,
		SD,
		SEQ,
		SIN,
		SIGN,
		SOLVE,
		SQRT,
		SUM,
		TABLE,
		TAN,
		TRACE, 
		TRANS,
		VAR
	};

	public enum ParameterizedBuiltinFunctionOp {
		GROUPEDAGG, RMEMPTY, REPLACE, ORDER, 
		// Distribution Functions
		CDF, INVCDF, PNORM, QNORM, PT, QT, PF, QF, PCHISQ, QCHISQ, PEXP, QEXP,
		TRANSFORM, 
		INVALID
	};
	
	public enum DataOp {
		READ, WRITE, RAND, MATRIX, INVALID	
	}

	public enum FunctCallOp {
		INTERNAL, EXTERNAL
	};
	
	public enum ExtBuiltinFunctionOp {
		EIGEN, CHOLESKY
	};

	public enum AggOp {
		SUM, MIN, MAX, INVALID
	};

	public enum ReorgOp {
		TRANSPOSE, DIAG
	};

	//public enum DataOp {
	//	READ, WRITE
	//};

	public enum DataType {
		MATRIX, SCALAR, FRAME, OBJECT, UNKNOWN;
		
		public boolean isMatrix() {
			return (this == MATRIX);
		}
		public boolean isScalar() {
			return (this == SCALAR);
		}
	};

	public enum ValueType {
		INT, DOUBLE, STRING, BOOLEAN, OBJECT, UNKNOWN
	};

	public enum FormatType {
		TEXT, BINARY, MM, CSV, UNKNOWN
	};
	
	protected static final Log LOG = LogFactory.getLog(Expression.class.getName());

	public abstract Expression rewriteExpression(String prefix) throws LanguageException;
		
	
	protected Kind _kind;
	protected Identifier[] _outputs;

	private static int _tempId;

	public Expression() {
		_outputs = null;
	}

	public void setOutput(Identifier output) {
		if ( _outputs == null) {
			_outputs = new Identifier[1];
		}
		_outputs[0] = output;
	}

	public Kind getKind() {
		return _kind;
	}

	public Identifier getOutput() {
		if (_outputs != null && _outputs.length > 0)
			return _outputs[0];
		else
			return null;
	}
	
	public Identifier[] getOutputs() {
		return _outputs;
	}
	
	public void validateExpression(HashMap ids, HashMap currConstVars, boolean conditional) 
		throws LanguageException 
	{
		raiseValidateError("Should never be invoked in Baseclass 'Expression'", false);
	}
	
	public void validateExpression(MultiAssignmentStatement mas, HashMap ids, HashMap currConstVars, boolean conditional) 
		throws LanguageException 
	{
		raiseValidateError("Should never be invoked in Baseclass 'Expression'", false);
	}
	
	public static BinaryOp getBinaryOp(String val) {
		if (val.equalsIgnoreCase("+"))
			return BinaryOp.PLUS;
		else if (val.equalsIgnoreCase("-"))
			return BinaryOp.MINUS;
		else if (val.equalsIgnoreCase("*"))
			return BinaryOp.MULT;
		else if (val.equalsIgnoreCase("/"))
			return BinaryOp.DIV;
		else if (val.equalsIgnoreCase("%%"))
			return BinaryOp.MODULUS;
		else if (val.equalsIgnoreCase("%/%"))
			return BinaryOp.INTDIV;
		else if (val.equalsIgnoreCase("^"))
			return BinaryOp.POW;
		else if (val.equalsIgnoreCase("%*%"))
			return BinaryOp.MATMULT;
		return BinaryOp.INVALID;
	}

	public static RelationalOp getRelationalOp(String val) {
		if (val == null) 
			return null;
		else if (val.equalsIgnoreCase("<"))
			return RelationalOp.LESS;
		else if (val.equalsIgnoreCase("<="))
			return RelationalOp.LESSEQUAL;
		else if (val.equalsIgnoreCase(">"))
			return RelationalOp.GREATER;
		else if (val.equalsIgnoreCase(">="))
			return RelationalOp.GREATEREQUAL;
		else if (val.equalsIgnoreCase("=="))
			return RelationalOp.EQUAL;
		else if (val.equalsIgnoreCase("!="))
			return RelationalOp.NOTEQUAL;
		return RelationalOp.INVALID;
	}

	public static BooleanOp getBooleanOp(String val) {
		if (val.equalsIgnoreCase("&&"))
			return BooleanOp.CONDITIONALAND;
		else if (val.equalsIgnoreCase("&"))
			return BooleanOp.LOGICALAND;
		else if (val.equalsIgnoreCase("||"))
			return BooleanOp.CONDITIONALOR;
		else if (val.equalsIgnoreCase("|"))
			return BooleanOp.LOGICALOR;
		else if (val.equalsIgnoreCase("!"))
			return BooleanOp.NOT;
		return BooleanOp.INVALID;
	}

	/**
	 * Convert format types from parser to Hops enum : default is text
	 */
	
	public static FileFormatTypes convertFormatType(String fn) {
		if (fn == null)
			return FileFormatTypes.TEXT;
		if (fn.equalsIgnoreCase(DataExpression.FORMAT_TYPE_VALUE_TEXT)) {
			return FileFormatTypes.TEXT;
		}
		if (fn.equalsIgnoreCase(DataExpression.FORMAT_TYPE_VALUE_BINARY)) {
			return FileFormatTypes.BINARY;
		}
		if (fn.equalsIgnoreCase(DataExpression.FORMAT_TYPE_VALUE_MATRIXMARKET))  {
			return FileFormatTypes.MM;
		}
		if (fn.equalsIgnoreCase(DataExpression.FORMAT_TYPE_VALUE_CSV))  {
			return FileFormatTypes.CSV;
		}
		// ToDo : throw parse exception for invalid / unsupported format type
		return FileFormatTypes.TEXT;
	}
    
	/**
	 * Construct Hops from parse tree : Create temporary views in expressions
	 */
	public static String getTempName() {
		return "parsertemp" + _tempId++;
	}

	public abstract VariableSet variablesRead();

	public abstract VariableSet variablesUpdated();

	public static DataType computeDataType(Expression e1, Expression e2, boolean cast) throws LanguageException {
		return computeDataType(e1.getOutput(), e2.getOutput(), cast);
	}

	public static DataType computeDataType(Identifier id1, Identifier id2, boolean cast) throws LanguageException {
		DataType d1 = id1.getDataType();
		DataType d2 = id2.getDataType();

		if (d1 == d2)
			return d1;

		if (cast) {
			if (d1 == DataType.MATRIX && d2 == DataType.SCALAR)
				return DataType.MATRIX;
			if (d1 == DataType.SCALAR && d2 == DataType.MATRIX)
				return DataType.MATRIX;
		}

		//raise error with id1 location
		id1.raiseValidateError("Invalid Datatypes for operation "+d1+" "+d2, false, 
				LanguageException.LanguageErrorCodes.INVALID_PARAMETERS);
		return null; //never reached because unconditional
	}

	public static ValueType computeValueType(Expression e1, Expression e2, boolean cast) throws LanguageException {
		return computeValueType(e1.getOutput(), e2.getOutput(), cast);
	}

	public static ValueType computeValueType(Identifier id1, Identifier id2, boolean cast) throws LanguageException {
		ValueType v1 = id1.getValueType();
		ValueType v2 = id2.getValueType();

		if (v1 == v2)
			return v1;

		if (cast) {
			if (v1 == ValueType.DOUBLE && v2 == ValueType.INT)
				return ValueType.DOUBLE;
			if (v2 == ValueType.DOUBLE && v1 == ValueType.INT)
				return ValueType.DOUBLE;
			
			// String value type will override others
			// Primary operation involving strings is concatenation (+)
			if ( v1 == ValueType.STRING || v2 == ValueType.STRING )
				return ValueType.STRING;
		}

		//raise error with id1 location
		id1.raiseValidateError("Invalid Valuetypes for operation "+v1+" "+v2, false, 
				LanguageException.LanguageErrorCodes.INVALID_PARAMETERS);
		return null; //never reached because unconditional
	}

	@Override
	public boolean equals(Object that)
	{
		//empty check for robustness
		if( that == null || !(that instanceof Expression) )
			return false;
		
		Expression thatExpr = (Expression) that;
		
		//approach is to compare string representation of expression
		String thisStr = this.toString();
		String thatStr = thatExpr.toString();
		
		return thisStr.equalsIgnoreCase(thatStr);
	}
	
	@Override
	public int hashCode()
	{
		//use identity hash code
		return super.hashCode();
	}
	
	///////////////////////////////////////////////////////////////
	// validate error handling (consistent for all expressions)
	
	/**
	 * 
	 * @param msg
	 * @param conditional
	 * @throws LanguageException
	 */
	public void raiseValidateError( String msg, boolean conditional ) 
		throws LanguageException
	{
		raiseValidateError(msg, conditional, null);
	}
	
	/**
	 * 
	 * @param msg
	 * @param conditional
	 * @param code
	 * @throws LanguageException
	 */
	public void raiseValidateError( String msg, boolean conditional, String errorCode ) 
		throws LanguageException
	{
		if( conditional )  //warning if conditional
		{
			String fullMsg = this.printWarningLocation() + msg;
			
			LOG.warn( fullMsg );
		}
		else  //error and exception if unconditional
		{
			String fullMsg = this.printErrorLocation() + msg;
			
			LOG.error( fullMsg );			
			if( errorCode != null )
				throw new LanguageException( fullMsg, errorCode );
			else 
				throw new LanguageException( fullMsg );
		}
	}
	
	
	/**
	 * Returns the matrix characteristics for scalar-scalar, scalar-matrix, matrix-scalar, matrix-matrix
	 * operations. This method is aware of potentially unknowns and matrix-vector (col/row) operations.
	 * 
	 * Format: rlen, clen, brlen, bclen.
	 * 
	 * @param left
	 * @param right
	 * @return
	 */
	public static long[] getBinaryMatrixCharacteristics( Expression left, Expression right )
	{
		long[] ret = new long[]{ -1, -1, -1, -1 };
		
		Identifier idleft = left.getOutput();
		Identifier idright = right.getOutput();
		
		if( idleft.getDataType()==DataType.SCALAR && idright.getDataType()==DataType.SCALAR ) {
			ret[0] = 0; 
			ret[1] = 0; 
			ret[2] = 0; 
			ret[3] = 0; 
		}
		else if( idleft.getDataType()==DataType.SCALAR && idright.getDataType()==DataType.MATRIX ) {
			ret[0] = idright.getDim1(); 
			ret[1] = idright.getDim2(); 
			ret[2] = idright.getRowsInBlock(); 
			ret[3] = idright.getColumnsInBlock();
		}
		else if( idleft.getDataType()==DataType.MATRIX && idright.getDataType()==DataType.SCALAR ) {
			ret[0] = idleft.getDim1(); 
			ret[1] = idleft.getDim2(); 
			ret[2] = idleft.getRowsInBlock(); 
			ret[3] = idleft.getColumnsInBlock();
		}
		else if( idleft.getDataType()==DataType.MATRIX && idright.getDataType()==DataType.MATRIX ) {
			ret[0] = idleft.getDim1(); 
			ret[1] = idleft.getDim2(); 
			ret[2] = idleft.getRowsInBlock(); 
			ret[3] = idleft.getColumnsInBlock();
			if( ret[0] < 0 && idright.getDim1() > 1 ) //robustness for row vectors
				ret[0] = idright.getDim1();
			if( ret[1] < 0 && idright.getDim2() > 1 ) //robustness for row vectors
				ret[1] = idright.getDim2();
		}
		
		return ret;
	}
	
	///////////////////////////////////////////////////////////////////////////
	// store exception info + position information for expressions
	///////////////////////////////////////////////////////////////////////////
	private String _filename;
	private int _beginLine, _beginColumn;
	private int _endLine, _endColumn;
	private ArrayList _parseExceptionList = new ArrayList();
	
	public void setFilename(String passed)  { _filename = passed;   }
	public void setBeginLine(int passed)    { _beginLine = passed;   }
	public void setBeginColumn(int passed) 	{ _beginColumn = passed; }
	public void setEndLine(int passed) 		{ _endLine = passed;   }
	public void setEndColumn(int passed)	{ _endColumn = passed; }
	public void setParseExceptionList(ArrayList passed) { _parseExceptionList = passed;}
	
	public void setAllPositions(String filename, int blp, int bcp, int elp, int ecp){
		_filename    = filename;
		_beginLine	 = blp; 
		_beginColumn = bcp; 
		_endLine 	 = elp;
		_endColumn 	 = ecp;
	}

	public String getFilename()	{ return _filename;   }
	public int getBeginLine()	{ return _beginLine;   }
	public int getBeginColumn() { return _beginColumn; }
	public int getEndLine() 	{ return _endLine;   }
	public int getEndColumn()	{ return _endColumn; }
	public ArrayList getParseExceptionList() { return _parseExceptionList; }
	
	public String printErrorLocation(){
		return "ERROR: " + _filename + " -- line " + _beginLine + ", column " + _beginColumn + " -- ";
	}
	
	public String printErrorLocation(int beginLine, int beginColumn){
		return "ERROR: " + _filename + " -- line " + beginLine + ", column " + beginColumn + " -- ";
	}
	
	public String printWarningLocation(){
		return "WARNING: " + _filename + " -- line " + _beginLine + ", column " + _beginColumn + " -- ";
	}
	
	public String printInfoLocation(){
		return "INFO: " + _filename + " -- line " + _beginLine + ", column " + _beginColumn + " -- ";
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy