/**
* (C) Copyright IBM Corp. 2010, 2015
*
* Licensed 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 com.ibm.bi.dml.lops;
import java.util.HashMap;
import com.ibm.bi.dml.hops.HopsException;
import com.ibm.bi.dml.lops.LopProperties.ExecLocation;
import com.ibm.bi.dml.lops.LopProperties.ExecType;
import com.ibm.bi.dml.lops.compile.JobType;
import com.ibm.bi.dml.parser.Expression.DataType;
import com.ibm.bi.dml.parser.Expression.ValueType;
import com.ibm.bi.dml.parser.ParameterizedBuiltinFunctionExpression;
/**
* Defines a LOP for functions.
*
*/
public class ParameterizedBuiltin extends Lop
{
public enum OperationTypes {
INVALID, CDF, INVCDF, RMEMPTY, REPLACE, REXPAND,
PNORM, QNORM, PT, QT, PF, QF, PCHISQ, QCHISQ, PEXP, QEXP,
TRANSFORM
};
private OperationTypes _operation;
private HashMap<String, Lop> _inputParams;
private boolean _bRmEmptyBC;
/**
* Creates a new builtin function LOP.
*
* @param target
* target identifier
* @param params
* parameter list
* @param inputParameters
* list of input LOPs
* @param function
* builtin function
* @param numRows
* number of resulting rows
* @param numCols
* number of resulting columns
*/
public ParameterizedBuiltin(HashMap<String, Lop> paramLops, OperationTypes op, DataType dt, ValueType vt)
{
super(Lop.Type.ParameterizedBuiltin, dt, vt);
_operation = op;
for (Lop lop : paramLops.values()) {
this.addInput(lop);
lop.addOutput(this);
}
_inputParams = paramLops;
/*
* This lop is executed in control program.
*/
boolean breaksAlignment = false;
boolean aligner = false;
boolean definesMRJob = false;
lps.addCompatibility(JobType.INVALID);
lps.setProperties(inputs, ExecType.CP, ExecLocation.ControlProgram, breaksAlignment, aligner, definesMRJob);
}
public ParameterizedBuiltin(HashMap<String, Lop> paramLops, OperationTypes op, DataType dt, ValueType vt, ExecType et)
throws HopsException
{
super(Lop.Type.ParameterizedBuiltin, dt, vt);
_operation = op;
for (Lop lop : paramLops.values()) {
this.addInput(lop);
lop.addOutput(this);
}
_inputParams = paramLops;
boolean breaksAlignment = false;
boolean aligner = false;
boolean definesMRJob = false;
ExecLocation eloc = null;
if( _operation == OperationTypes.REPLACE && et==ExecType.MR )
{
eloc = ExecLocation.MapOrReduce;
lps.addCompatibility(JobType.GMR);
lps.addCompatibility(JobType.DATAGEN);
lps.addCompatibility(JobType.REBLOCK);
}
else if( _operation == OperationTypes.RMEMPTY && et==ExecType.MR )
{
eloc = ExecLocation.Reduce;
lps.addCompatibility(JobType.GMR);
lps.addCompatibility(JobType.DATAGEN);
lps.addCompatibility(JobType.REBLOCK);
breaksAlignment=true;
}
else if( _operation == OperationTypes.REXPAND && et==ExecType.MR )
{
eloc = ExecLocation.MapOrReduce;
lps.addCompatibility(JobType.GMR);
lps.addCompatibility(JobType.DATAGEN);
lps.addCompatibility(JobType.REBLOCK);
breaksAlignment=true;
}
else if ( _operation == OperationTypes.TRANSFORM && et == ExecType.MR ) {
definesMRJob = true;
eloc = ExecLocation.MapAndReduce;
lps.addCompatibility(JobType.TRANSFORM);
}
else //executed in CP / CP_FILE / SPARK
{
eloc = ExecLocation.ControlProgram;
lps.addCompatibility(JobType.INVALID);
}
lps.setProperties(inputs, et, eloc, breaksAlignment, aligner, definesMRJob);
}
public ParameterizedBuiltin(HashMap<String, Lop> paramLops, OperationTypes op, DataType dt, ValueType vt, ExecType et, boolean bRmEmptyBC)
throws HopsException
{
this(paramLops, op, dt, vt, et);
_bRmEmptyBC = bRmEmptyBC;
}
public OperationTypes getOp() {
return _operation;
}
public int getInputIndex(String name) {
Lop n = _inputParams.get(name);
for(int i=0; i<getInputs().size(); i++)
if(getInputs().get(i) == n)
return i;
return -1;
}
public Lop getNamedInput(String name) {
return _inputParams.get(name);
}
@Override
public String getInstructions(String output)
throws LopsException
{
StringBuilder sb = new StringBuilder();
sb.append( getExecType() );
sb.append( Lop.OPERAND_DELIMITOR );
switch(_operation)
{
case CDF:
case INVCDF:
sb.append( (_operation == OperationTypes.CDF ? "cdf" : "invcdf") );
sb.append( OPERAND_DELIMITOR );
for ( String s : _inputParams.keySet() )
{
sb.append( s );
sb.append( NAME_VALUE_SEPARATOR );
// get the value/label of the scalar input associated with name "s"
Lop iLop = _inputParams.get(s);
sb.append( iLop.prepScalarLabel() );
sb.append( OPERAND_DELIMITOR );
}
break;
case RMEMPTY:
sb.append("rmempty");
sb.append(OPERAND_DELIMITOR);
for ( String s : _inputParams.keySet() ) {
sb.append(s);
sb.append(NAME_VALUE_SEPARATOR);
// get the value/label of the scalar input associated with name "s"
// (offset and maxdim only apply to exec type spark)
Lop iLop = _inputParams.get(s);
if( s.equals( "target") || s.equals( "select") || getExecType()==ExecType.SPARK )
sb.append( iLop.getOutputParameters().getLabel());
else
sb.append( iLop.prepScalarLabel() );
sb.append(OPERAND_DELIMITOR);
}
break;
case REPLACE:
sb.append( "replace" );
sb.append( OPERAND_DELIMITOR );
for ( String s : _inputParams.keySet() )
{
sb.append( s );
sb.append( NAME_VALUE_SEPARATOR );
// get the value/label of the scalar input associated with name "s"
Lop iLop = _inputParams.get(s);
if( s.equals("target") )
sb.append(iLop.getOutputParameters().getLabel());
else
sb.append( iLop.prepScalarLabel() );
sb.append( OPERAND_DELIMITOR );
}
break;
case REXPAND:
sb.append("rexpand");
sb.append(OPERAND_DELIMITOR);
for ( String s : _inputParams.keySet() ) {
sb.append(s);
sb.append(NAME_VALUE_SEPARATOR);
// get the value/label of the scalar input associated with name "s"
// (offset and maxdim only apply to exec type spark)
Lop iLop = _inputParams.get(s);
if( s.equals( "target") || getExecType()==ExecType.SPARK )
sb.append( iLop.getOutputParameters().getLabel());
else
sb.append( iLop.prepScalarLabel() );
sb.append(OPERAND_DELIMITOR);
}
break;
case TRANSFORM:
{
sb.append("transform");
sb.append(OPERAND_DELIMITOR);
for ( String s : _inputParams.keySet() ) {
sb.append(s);
sb.append(NAME_VALUE_SEPARATOR);
Lop iLop = _inputParams.get(s);
if( iLop.getDataType() != DataType.SCALAR )
sb.append( iLop.getOutputParameters().getLabel());
else
sb.append( iLop.prepScalarLabel() );
sb.append(OPERAND_DELIMITOR);
}
break;
}
default:
throw new LopsException(this.printErrorLocation() + "In ParameterizedBuiltin Lop, Unknown operation: " + _operation);
}
if (_operation == OperationTypes.RMEMPTY) {
sb.append("bRmEmptyBC");
sb.append(NAME_VALUE_SEPARATOR);
sb.append( _bRmEmptyBC );
sb.append(OPERAND_DELIMITOR);
}
sb.append(this.prepOutputOperand(output));
return sb.toString();
}
@Override
public String getInstructions(int input_index1, int input_index2, int input_index3, int output_index)
throws LopsException
{
StringBuilder sb = new StringBuilder();
sb.append( getExecType() );
sb.append( Lop.OPERAND_DELIMITOR );
switch(_operation)
{
case REPLACE:
{
sb.append( "replace" );
sb.append( OPERAND_DELIMITOR );
Lop iLop = _inputParams.get("target");
int pos = getInputs().indexOf(iLop);
int index = (pos==0)? input_index1 : (pos==1)? input_index2 : input_index3;
//input_index
sb.append(prepInputOperand(index));
sb.append( OPERAND_DELIMITOR );
Lop iLop2 = _inputParams.get("pattern");
sb.append(iLop2.prepScalarLabel());
sb.append( OPERAND_DELIMITOR );
Lop iLop3 = _inputParams.get("replacement");
sb.append(iLop3.prepScalarLabel());
sb.append( OPERAND_DELIMITOR );
break;
}
default:
throw new LopsException(this.printErrorLocation() + "In ParameterizedBuiltin Lop, Unknown operation: " + _operation);
}
sb.append( prepOutputOperand(output_index));
return sb.toString();
}
@Override
public String getInstructions(int input_index1, int input_index2, int input_index3, int input_index4, int output_index)
throws LopsException
{
StringBuilder sb = new StringBuilder();
sb.append( getExecType() );
sb.append( Lop.OPERAND_DELIMITOR );
switch(_operation)
{
case RMEMPTY:
{
sb.append("rmempty");
sb.append(OPERAND_DELIMITOR);
Lop iLop1 = _inputParams.get("target");
int pos1 = getInputs().indexOf(iLop1);
int index1 = (pos1==0)? input_index1 : (pos1==1)? input_index2 : (pos1==2)? input_index3 : input_index4;
sb.append(prepInputOperand(index1));
sb.append(OPERAND_DELIMITOR);
Lop iLop2 = _inputParams.get("offset");
int pos2 = getInputs().indexOf(iLop2);
int index2 = (pos2==0)? input_index1 : (pos2==1)? input_index2 : (pos1==2)? input_index3 : input_index4;
sb.append(prepInputOperand(index2));
sb.append(OPERAND_DELIMITOR);
Lop iLop3 = _inputParams.get("maxdim");
sb.append( iLop3.prepScalarLabel() );
sb.append(OPERAND_DELIMITOR);
Lop iLop4 = _inputParams.get("margin");
sb.append( iLop4.prepScalarLabel() );
sb.append( OPERAND_DELIMITOR );
break;
}
default:
throw new LopsException(this.printErrorLocation() + "In ParameterizedBuiltin Lop, Unknown operation: " + _operation);
}
sb.append( prepOutputOperand(output_index));
return sb.toString();
}
@Override
public String getInstructions(int input_index1, int input_index2, int input_index3, int input_index4, int input_index5, int output_index)
throws LopsException
{
StringBuilder sb = new StringBuilder();
sb.append( getExecType() );
sb.append( Lop.OPERAND_DELIMITOR );
switch(_operation)
{
case REXPAND:
{
sb.append("rexpand");
sb.append(OPERAND_DELIMITOR);
Lop iLop1 = _inputParams.get("target");
int pos1 = getInputs().indexOf(iLop1);
int index1 = (pos1==0)? input_index1 : (pos1==1)? input_index2 : (pos1==2)? input_index3 : (pos1==3)? input_index4 : input_index5;
sb.append(prepInputOperand(index1));
sb.append(OPERAND_DELIMITOR);
Lop iLop2 = _inputParams.get("max");
sb.append( iLop2.prepScalarLabel() );
sb.append(OPERAND_DELIMITOR);
Lop iLop3 = _inputParams.get("dir");
sb.append( iLop3.prepScalarLabel() );
sb.append(OPERAND_DELIMITOR);
Lop iLop4 = _inputParams.get("cast");
sb.append( iLop4.prepScalarLabel() );
sb.append( OPERAND_DELIMITOR );
Lop iLop5 = _inputParams.get("ignore");
sb.append( iLop5.prepScalarLabel() );
sb.append( OPERAND_DELIMITOR );
break;
}
default:
throw new LopsException(this.printErrorLocation() + "In ParameterizedBuiltin Lop, Unknown operation: " + _operation);
}
sb.append( prepOutputOperand(output_index));
return sb.toString();
}
@Override
public String getInstructions(int output_index)
throws LopsException
{
StringBuilder sb = new StringBuilder();
sb.append( getExecType() );
sb.append( Lop.OPERAND_DELIMITOR );
if(_operation== OperationTypes.TRANSFORM)
{
// int inputIndex = getInputIndex("target");
sb.append( "transform" );
sb.append( OPERAND_DELIMITOR );
Lop iLop = _inputParams.get(ParameterizedBuiltinFunctionExpression.TF_FN_PARAM_DATA);
sb.append(iLop.prepInputOperand(getInputIndex("target")));
sb.append( OPERAND_DELIMITOR );
Lop iLop2 = _inputParams.get(ParameterizedBuiltinFunctionExpression.TF_FN_PARAM_TXMTD);
sb.append(iLop2.prepScalarLabel());
sb.append( OPERAND_DELIMITOR );
// either applyTransformPath or transformSpec should be specified
boolean isApply = false;
Lop iLop3 = null;
if ( _inputParams.get(ParameterizedBuiltinFunctionExpression.TF_FN_PARAM_APPLYMTD) != null ) {
// apply transform
isApply = true;
iLop3 = _inputParams.get(ParameterizedBuiltinFunctionExpression.TF_FN_PARAM_APPLYMTD);
}
else {
iLop3 = _inputParams.get(ParameterizedBuiltinFunctionExpression.TF_FN_PARAM_TXSPEC);
}
sb.append(iLop3.prepScalarLabel());
sb.append( OPERAND_DELIMITOR );
sb.append(isApply);
sb.append( OPERAND_DELIMITOR );
Lop iLop4 = _inputParams.get(ParameterizedBuiltinFunctionExpression.TF_FN_PARAM_OUTNAMES);
if( iLop4 != null )
{
sb.append(iLop4.prepScalarLabel());
sb.append( OPERAND_DELIMITOR );
}
sb.append( prepOutputOperand(output_index));
}
//return getTransformInstructions(""+getInputIndex("target"), ""+output_index);
else
throw new LopsException(this.printErrorLocation() + "In ParameterizedBuiltin Lop, Unknown operation: " + _operation);
return sb.toString();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(_operation.toString());
if( !getInputs().isEmpty() )
sb.append("(");
for (Lop cur : getInputs()) {
sb.append(cur.toString());
}
if( !getInputs().isEmpty() )
sb.append(") ");
sb.append(" ; num_rows=" + this.getOutputParameters().getNumRows());
sb.append(" ; num_cols=" + this.getOutputParameters().getNumCols());
sb.append(" ; format=" + this.getOutputParameters().getFormat());
sb.append(" ; blocked=" + this.getOutputParameters().isBlocked());
return sb.toString();
}
}