blob: 74711e3b4dfc4227f4f0cd577c52b8344f3c264c [file] [log] [blame]
/*
* 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.hops.rewrite;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import org.apache.commons.lang.ArrayUtils;
import org.apache.sysml.api.DMLScript;
import org.apache.sysml.api.DMLScript.RUNTIME_PLATFORM;
import org.apache.sysml.conf.ConfigurationManager;
import org.apache.sysml.hops.AggBinaryOp;
import org.apache.sysml.hops.AggUnaryOp;
import org.apache.sysml.hops.BinaryOp;
import org.apache.sysml.hops.DataOp;
import org.apache.sysml.hops.Hop;
import org.apache.sysml.hops.Hop.AggOp;
import org.apache.sysml.hops.Hop.DataGenMethod;
import org.apache.sysml.hops.DataGenOp;
import org.apache.sysml.hops.Hop.DataOpTypes;
import org.apache.sysml.hops.Hop.Direction;
import org.apache.sysml.hops.Hop.FileFormatTypes;
import org.apache.sysml.hops.Hop.OpOp2;
import org.apache.sysml.hops.Hop.OpOp3;
import org.apache.sysml.hops.Hop.OpOpN;
import org.apache.sysml.hops.Hop.ParamBuiltinOp;
import org.apache.sysml.hops.Hop.ReOrgOp;
import org.apache.sysml.hops.HopsException;
import org.apache.sysml.hops.IndexingOp;
import org.apache.sysml.hops.LeftIndexingOp;
import org.apache.sysml.hops.LiteralOp;
import org.apache.sysml.hops.MemoTable;
import org.apache.sysml.hops.NaryOp;
import org.apache.sysml.hops.OptimizerUtils;
import org.apache.sysml.hops.ParameterizedBuiltinOp;
import org.apache.sysml.hops.ReorgOp;
import org.apache.sysml.hops.TernaryOp;
import org.apache.sysml.hops.UnaryOp;
import org.apache.sysml.hops.Hop.OpOp1;
import org.apache.sysml.parser.DataExpression;
import org.apache.sysml.parser.DataIdentifier;
import org.apache.sysml.parser.ForStatementBlock;
import org.apache.sysml.parser.FunctionStatementBlock;
import org.apache.sysml.parser.IfStatementBlock;
import org.apache.sysml.parser.Statement;
import org.apache.sysml.parser.StatementBlock;
import org.apache.sysml.parser.WhileStatementBlock;
import org.apache.sysml.parser.Expression.DataType;
import org.apache.sysml.parser.Expression.ValueType;
import org.apache.sysml.runtime.instructions.cp.ScalarObject;
import org.apache.sysml.runtime.instructions.cp.ScalarObjectFactory;
import org.apache.sysml.runtime.instructions.cp.StringInitCPInstruction;
import org.apache.sysml.runtime.matrix.data.MatrixBlock;
import org.apache.sysml.runtime.util.UtilFunctions;
public class HopRewriteUtils
{
public static boolean isValueTypeCast( OpOp1 op )
{
return ( op == OpOp1.CAST_AS_BOOLEAN
|| op == OpOp1.CAST_AS_INT
|| op == OpOp1.CAST_AS_DOUBLE );
}
//////////////////////////////////
// literal handling
public static boolean getBooleanValue( LiteralOp op )
throws HopsException
{
switch( op.getValueType() )
{
case DOUBLE: return op.getDoubleValue() != 0;
case INT: return op.getLongValue() != 0;
case BOOLEAN: return op.getBooleanValue();
default: throw new HopsException("Invalid boolean value: "+op.getValueType());
}
}
public static boolean getBooleanValueSafe( LiteralOp op )
{
try
{
switch( op.getValueType() )
{
case DOUBLE: return op.getDoubleValue() != 0;
case INT: return op.getLongValue() != 0;
case BOOLEAN: return op.getBooleanValue();
default: throw new HopsException("Invalid boolean value: "+op.getValueType());
}
}
catch(Exception ex){
//silently ignore error
}
return false;
}
public static double getDoubleValue( LiteralOp op )
throws HopsException
{
switch( op.getValueType() )
{
case DOUBLE: return op.getDoubleValue();
case INT: return op.getLongValue();
case BOOLEAN: return op.getBooleanValue() ? 1 : 0;
default: throw new HopsException("Invalid double value: "+op.getValueType());
}
}
public static double getDoubleValueSafe( LiteralOp op )
{
try
{
switch( op.getValueType() )
{
case DOUBLE: return op.getDoubleValue();
case INT: return op.getLongValue();
case BOOLEAN: return op.getBooleanValue() ? 1 : 0;
default: throw new HopsException("Invalid double value: "+op.getValueType());
}
}
catch(Exception ex){
//silently ignore error
}
return Double.MAX_VALUE;
}
/**
* Return the int value of a LiteralOp (as a long).
*
* Note: For comparisons, this is *only* to be used in situations
* in which the value is absolutely guaranteed to be an integer.
* Otherwise, a safer alternative is `getDoubleValue`.
*
* @param op literal operator
* @return long value of literator op
* @throws HopsException if HopsException occurs
*/
public static long getIntValue( LiteralOp op )
throws HopsException
{
switch( op.getValueType() )
{
case DOUBLE: return UtilFunctions.toLong(op.getDoubleValue());
case INT: return op.getLongValue();
case BOOLEAN: return op.getBooleanValue() ? 1 : 0;
default: throw new HopsException("Invalid int value: "+op.getValueType());
}
}
public static long getIntValueSafe( LiteralOp op )
{
try
{
switch( op.getValueType() )
{
case DOUBLE: return UtilFunctions.toLong(op.getDoubleValue());
case INT: return op.getLongValue();
case BOOLEAN: return op.getBooleanValue() ? 1 : 0;
default:
throw new RuntimeException("Invalid int value: "+op.getValueType());
}
}
catch(Exception ex){
//silently ignore error
}
return Long.MAX_VALUE;
}
public static boolean isLiteralOfValue( Hop hop, double val ) {
return (hop instanceof LiteralOp
&& (hop.getValueType()==ValueType.DOUBLE || hop.getValueType()==ValueType.INT)
&& getDoubleValueSafe((LiteralOp)hop)==val);
}
public static boolean isLiteralOfValue(Hop hop, String val) {
return hop instanceof LiteralOp
&& ((LiteralOp)hop).getStringValue().equals(val);
}
public static boolean isLiteralOfValue( Hop hop, boolean val ) {
try {
return (hop instanceof LiteralOp
&& (hop.getValueType()==ValueType.BOOLEAN)
&& ((LiteralOp)hop).getBooleanValue()==val);
}
catch(HopsException ex) {
throw new RuntimeException(ex);
}
}
public static ScalarObject getScalarObject( LiteralOp op )
{
try {
return ScalarObjectFactory
.createScalarObject(op.getValueType(), op);
}
catch(Exception ex) {
throw new RuntimeException("Failed to create scalar object for constant. Continue.", ex);
}
}
///////////////////////////////////
// hop dag transformations
public static int getChildReferencePos( Hop parent, Hop child ) {
return parent.getInput().indexOf(child);
}
public static void removeChildReference( Hop parent, Hop child ) {
parent.getInput().remove( child );
child.getParent().remove( parent );
}
public static void removeChildReferenceByPos( Hop parent, Hop child, int posChild ) {
parent.getInput().remove( posChild );
child.getParent().remove( parent );
}
public static void removeAllChildReferences( Hop parent )
{
//remove parent reference from all childs
for( Hop child : parent.getInput() )
child.getParent().remove(parent);
//remove all child references
parent.getInput().clear();
}
public static void addChildReference( Hop parent, Hop child ) {
parent.getInput().add( child );
child.getParent().add( parent );
}
public static void addChildReference( Hop parent, Hop child, int pos ){
parent.getInput().add( pos, child );
child.getParent().add( parent );
}
/**
* Replace an old Hop with a replacement Hop.
* If the old Hop has no parents, then return the replacement.
* Otherwise rewire each of the Hop's parents into the replacement and return the replacement.
* @param hold To be replaced
* @param hnew The replacement
* @return hnew
*/
public static Hop rewireAllParentChildReferences( Hop hold, Hop hnew ) {
ArrayList<Hop> parents = hold.getParent();
while (!parents.isEmpty())
HopRewriteUtils.replaceChildReference(parents.get(0), hold, hnew);
return hnew;
}
public static void replaceChildReference( Hop parent, Hop inOld, Hop inNew ) {
int pos = getChildReferencePos(parent, inOld);
removeChildReferenceByPos(parent, inOld, pos);
addChildReference(parent, inNew, pos);
parent.refreshSizeInformation();
}
public static void replaceChildReference( Hop parent, Hop inOld, Hop inNew, int pos ) {
replaceChildReference(parent, inOld, inNew, pos, true);
}
public static void replaceChildReference( Hop parent, Hop inOld, Hop inNew, int pos, boolean refresh ) {
removeChildReferenceByPos(parent, inOld, pos);
addChildReference(parent, inNew, pos);
if( refresh )
parent.refreshSizeInformation();
}
public static void cleanupUnreferenced( Hop... inputs ) {
for( Hop input : inputs )
if( input.getParent().isEmpty() )
removeAllChildReferences(input);
}
public static Hop getOtherInput(Hop hop, Hop input) {
for( Hop c : hop.getInput() )
if( c != input )
return c;
return null;
}
public static Hop getLargestInput(Hop hop) {
return hop.getInput().stream()
.max(Comparator.comparing(h -> h.getLength())).orElse(null);
}
public static Hop createDataGenOp( Hop input, double value )
throws HopsException
{
Hop rows = input.rowsKnown() ? new LiteralOp(input.getDim1()) :
new UnaryOp("tmprows", DataType.SCALAR, ValueType.INT, OpOp1.NROW, input);
Hop cols = input.colsKnown() ? new LiteralOp(input.getDim2()) :
new UnaryOp("tmpcols", DataType.SCALAR, ValueType.INT, OpOp1.NCOL, input);
Hop val = new LiteralOp(value);
HashMap<String, Hop> params = new HashMap<>();
params.put(DataExpression.RAND_ROWS, rows);
params.put(DataExpression.RAND_COLS, cols);
params.put(DataExpression.RAND_MIN, val);
params.put(DataExpression.RAND_MAX, val);
params.put(DataExpression.RAND_PDF, new LiteralOp(DataExpression.RAND_PDF_UNIFORM));
params.put(DataExpression.RAND_LAMBDA, new LiteralOp(-1.0));
params.put(DataExpression.RAND_SPARSITY, new LiteralOp(1.0));
params.put(DataExpression.RAND_SEED, new LiteralOp(DataGenOp.UNSPECIFIED_SEED) );
//note internal refresh size information
Hop datagen = new DataGenOp(DataGenMethod.RAND, new DataIdentifier("tmp"), params);
datagen.setOutputBlocksizes(input.getRowsInBlock(), input.getColsInBlock());
copyLineNumbers(input, datagen);
if( value==0 )
datagen.setNnz(0);
return datagen;
}
/**
* Assumes that min and max are literal ops, needs to be checked from outside.
*
* @param inputGen input data gen op
* @param scale the scale
* @param shift the shift
* @return data gen op
* @throws HopsException if HopsException occurs
*/
public static DataGenOp copyDataGenOp( DataGenOp inputGen, double scale, double shift )
throws HopsException
{
HashMap<String, Integer> params = inputGen.getParamIndexMap();
Hop rows = inputGen.getInput().get(params.get(DataExpression.RAND_ROWS));
Hop cols = inputGen.getInput().get(params.get(DataExpression.RAND_COLS));
Hop min = inputGen.getInput().get(params.get(DataExpression.RAND_MIN));
Hop max = inputGen.getInput().get(params.get(DataExpression.RAND_MAX));
Hop pdf = inputGen.getInput().get(params.get(DataExpression.RAND_PDF));
Hop mean = inputGen.getInput().get(params.get(DataExpression.RAND_LAMBDA));
Hop sparsity = inputGen.getInput().get(params.get(DataExpression.RAND_SPARSITY));
Hop seed = inputGen.getInput().get(params.get(DataExpression.RAND_SEED));
//check for literal ops
if( !(min instanceof LiteralOp) || !(max instanceof LiteralOp))
return null;
//scale and shift
double smin = getDoubleValue((LiteralOp) min);
double smax = getDoubleValue((LiteralOp) max);
smin = smin * scale + shift;
smax = smax * scale + shift;
Hop sminHop = new LiteralOp(smin);
Hop smaxHop = new LiteralOp(smax);
HashMap<String, Hop> params2 = new HashMap<>();
params2.put(DataExpression.RAND_ROWS, rows);
params2.put(DataExpression.RAND_COLS, cols);
params2.put(DataExpression.RAND_MIN, sminHop);
params2.put(DataExpression.RAND_MAX, smaxHop);
params2.put(DataExpression.RAND_PDF, pdf);
params2.put(DataExpression.RAND_LAMBDA, mean);
params2.put(DataExpression.RAND_SPARSITY, sparsity);
params2.put(DataExpression.RAND_SEED, seed );
//note internal refresh size information
DataGenOp datagen = new DataGenOp(DataGenMethod.RAND, new DataIdentifier("tmp"), params2);
datagen.setOutputBlocksizes(inputGen.getRowsInBlock(), inputGen.getColsInBlock());
copyLineNumbers(inputGen, datagen);
if( smin==0 && smax==0 )
datagen.setNnz(0);
return datagen;
}
public static Hop createDataGenOp( Hop rowInput, Hop colInput, double value )
throws HopsException
{
Hop rows = rowInput.rowsKnown() ? new LiteralOp(rowInput.getDim1()) :
new UnaryOp("tmprows", DataType.SCALAR, ValueType.INT, OpOp1.NROW, rowInput);
Hop cols = colInput.colsKnown() ? new LiteralOp(colInput.getDim2()) :
new UnaryOp("tmpcols", DataType.SCALAR, ValueType.INT, OpOp1.NCOL, colInput);
Hop val = new LiteralOp(value);
HashMap<String, Hop> params = new HashMap<>();
params.put(DataExpression.RAND_ROWS, rows);
params.put(DataExpression.RAND_COLS, cols);
params.put(DataExpression.RAND_MIN, val);
params.put(DataExpression.RAND_MAX, val);
params.put(DataExpression.RAND_PDF, new LiteralOp(DataExpression.RAND_PDF_UNIFORM));
params.put(DataExpression.RAND_LAMBDA, new LiteralOp(-1.0));
params.put(DataExpression.RAND_SPARSITY, new LiteralOp(1.0));
params.put(DataExpression.RAND_SEED, new LiteralOp(DataGenOp.UNSPECIFIED_SEED) );
//note internal refresh size information
Hop datagen = new DataGenOp(DataGenMethod.RAND, new DataIdentifier("tmp"), params);
datagen.setOutputBlocksizes(rowInput.getRowsInBlock(), colInput.getColsInBlock());
copyLineNumbers(rowInput, datagen);
if( value==0 )
datagen.setNnz(0);
return datagen;
}
public static Hop createDataGenOp( Hop rowInput, boolean tRowInput, Hop colInput, boolean tColInput, double value )
throws HopsException
{
long nrow = tRowInput ? rowInput.getDim2() : rowInput.getDim1();
long ncol = tColInput ? colInput.getDim1() : rowInput.getDim2();
Hop rows = (nrow>=0) ? new LiteralOp(nrow) :
new UnaryOp("tmprows", DataType.SCALAR, ValueType.INT, tRowInput?OpOp1.NCOL:OpOp1.NROW, rowInput);
Hop cols = (ncol>=0) ? new LiteralOp(ncol) :
new UnaryOp("tmpcols", DataType.SCALAR, ValueType.INT, tColInput?OpOp1.NROW:OpOp1.NCOL, colInput);
Hop val = new LiteralOp(value);
HashMap<String, Hop> params = new HashMap<>();
params.put(DataExpression.RAND_ROWS, rows);
params.put(DataExpression.RAND_COLS, cols);
params.put(DataExpression.RAND_MIN, val);
params.put(DataExpression.RAND_MAX, val);
params.put(DataExpression.RAND_PDF, new LiteralOp(DataExpression.RAND_PDF_UNIFORM));
params.put(DataExpression.RAND_LAMBDA,new LiteralOp(-1.0));
params.put(DataExpression.RAND_SPARSITY, new LiteralOp(1.0));
params.put(DataExpression.RAND_SEED, new LiteralOp(DataGenOp.UNSPECIFIED_SEED) );
//note internal refresh size information
Hop datagen = new DataGenOp(DataGenMethod.RAND, new DataIdentifier("tmp"), params);
datagen.setOutputBlocksizes(rowInput.getRowsInBlock(), colInput.getColsInBlock());
copyLineNumbers(rowInput, datagen);
if( value==0 )
datagen.setNnz(0);
return datagen;
}
public static Hop createDataGenOpByVal( Hop rowInput, Hop colInput, double value )
throws HopsException
{
Hop val = new LiteralOp(value);
HashMap<String, Hop> params = new HashMap<>();
params.put(DataExpression.RAND_ROWS, rowInput);
params.put(DataExpression.RAND_COLS, colInput);
params.put(DataExpression.RAND_MIN, val);
params.put(DataExpression.RAND_MAX, val);
params.put(DataExpression.RAND_PDF, new LiteralOp(DataExpression.RAND_PDF_UNIFORM));
params.put(DataExpression.RAND_LAMBDA, new LiteralOp(-1.0));
params.put(DataExpression.RAND_SPARSITY, new LiteralOp(1.0));
params.put(DataExpression.RAND_SEED, new LiteralOp(DataGenOp.UNSPECIFIED_SEED) );
//note internal refresh size information
Hop datagen = new DataGenOp(DataGenMethod.RAND, new DataIdentifier("tmp"), params);
datagen.setOutputBlocksizes(rowInput.getRowsInBlock(), colInput.getColsInBlock());
copyLineNumbers(rowInput, datagen);
if( value==0 )
datagen.setNnz(0);
return datagen;
}
public static Hop createDataGenOpByVal( ArrayList<LiteralOp> values, long rows, long cols )
throws HopsException
{
StringBuilder sb = new StringBuilder();
for(LiteralOp lit : values) {
if(sb.length()>0)
sb.append(StringInitCPInstruction.DELIM);
sb.append(lit.getStringValue());
}
LiteralOp str = new LiteralOp(sb.toString());
HashMap<String, Hop> params = new HashMap<>();
params.put(DataExpression.RAND_ROWS, new LiteralOp(rows));
params.put(DataExpression.RAND_COLS, new LiteralOp(cols));
params.put(DataExpression.RAND_MIN, str);
params.put(DataExpression.RAND_MAX, str);
params.put(DataExpression.RAND_SEED, new LiteralOp(DataGenOp.UNSPECIFIED_SEED));
Hop datagen = new DataGenOp(DataGenMethod.SINIT, new DataIdentifier("tmp"), params);
int blksz = ConfigurationManager.getBlocksize();
datagen.setOutputBlocksizes(blksz, blksz);
copyLineNumbers(values.get(0), datagen);
return datagen;
}
public static boolean isDataGenOp(Hop hop, DataGenMethod... ops) {
return (hop instanceof DataGenOp
&& ArrayUtils.contains(ops, ((DataGenOp)hop).getOp()));
}
public static boolean isDataGenOpWithConstantValue(Hop hop) {
return hop instanceof DataGenOp
&& ((DataGenOp)hop).getOp()==DataGenMethod.RAND
&& ((DataGenOp)hop).hasConstantValue();
}
public static boolean isDataGenOpWithConstantValue(Hop hop, double value) {
return hop instanceof DataGenOp
&& ((DataGenOp)hop).getOp()==DataGenMethod.RAND
&& ((DataGenOp)hop).hasConstantValue(value);
}
public static Hop getDataGenOpConstantValue(Hop hop) {
return ((DataGenOp) hop).getConstantValue();
}
public static ReorgOp createTranspose(Hop input) {
return createReorg(input, ReOrgOp.TRANSPOSE);
}
public static ReorgOp createReorg(Hop input, ReOrgOp rop) {
ReorgOp reorg = new ReorgOp(input.getName(), input.getDataType(), input.getValueType(), rop, input);
reorg.setOutputBlocksizes(input.getRowsInBlock(), input.getColsInBlock());
copyLineNumbers(input, reorg);
reorg.refreshSizeInformation();
return reorg;
}
public static ReorgOp createReorg(ArrayList<Hop> inputs, ReOrgOp rop) {
Hop main = inputs.get(0);
ReorgOp reorg = new ReorgOp(main.getName(), main.getDataType(), main.getValueType(), rop, inputs);
reorg.setOutputBlocksizes(main.getRowsInBlock(), main.getColsInBlock());
copyLineNumbers(main, reorg);
reorg.refreshSizeInformation();
return reorg;
}
public static UnaryOp createUnary(Hop input, OpOp1 type)
{
DataType dt = (type==OpOp1.CAST_AS_SCALAR) ? DataType.SCALAR :
(type==OpOp1.CAST_AS_MATRIX) ? DataType.MATRIX : input.getDataType();
ValueType vt = (type==OpOp1.CAST_AS_MATRIX) ? ValueType.DOUBLE : input.getValueType();
UnaryOp unary = new UnaryOp(input.getName(), dt, vt, type, input);
unary.setOutputBlocksizes(input.getRowsInBlock(), input.getColsInBlock());
if( type == OpOp1.CAST_AS_SCALAR || type == OpOp1.CAST_AS_MATRIX ) {
int dim = (type==OpOp1.CAST_AS_SCALAR) ? 0 : 1;
int blksz = (type==OpOp1.CAST_AS_SCALAR) ? 0 : ConfigurationManager.getBlocksize();
setOutputParameters(unary, dim, dim, blksz, blksz, -1);
}
copyLineNumbers(input, unary);
unary.refreshSizeInformation();
return unary;
}
public static BinaryOp createBinaryMinus(Hop input) {
return createBinary(new LiteralOp(0), input, OpOp2.MINUS);
}
public static BinaryOp createBinary(Hop input1, Hop input2, OpOp2 op) {
return createBinary(input1, input2, op, false);
}
public static BinaryOp createBinary(Hop input1, Hop input2, OpOp2 op, boolean outer) {
Hop mainInput = input1.getDataType().isMatrix() ? input1 :
input2.getDataType().isMatrix() ? input2 : input1;
BinaryOp bop = new BinaryOp(mainInput.getName(), mainInput.getDataType(),
mainInput.getValueType(), op, input1, input2);
//cleanup value type for relational operations
if( bop.isPPredOperation() && bop.getDataType().isScalar() )
bop.setValueType(ValueType.BOOLEAN);
bop.setOuterVectorOperation(outer);
bop.setOutputBlocksizes(mainInput.getRowsInBlock(), mainInput.getColsInBlock());
copyLineNumbers(mainInput, bop);
bop.refreshSizeInformation();
return bop;
}
public static AggUnaryOp createSum( Hop input ) {
return createAggUnaryOp(input, AggOp.SUM, Direction.RowCol);
}
public static AggUnaryOp createAggUnaryOp( Hop input, AggOp op, Direction dir ) {
DataType dt = (dir==Direction.RowCol) ? DataType.SCALAR : input.getDataType();
AggUnaryOp auop = new AggUnaryOp(input.getName(), dt, input.getValueType(), op, dir, input);
auop.setOutputBlocksizes(input.getRowsInBlock(), input.getColsInBlock());
copyLineNumbers(input, auop);
auop.refreshSizeInformation();
return auop;
}
public static AggBinaryOp createMatrixMultiply(Hop left, Hop right) {
AggBinaryOp mmult = new AggBinaryOp(left.getName(), left.getDataType(), left.getValueType(), OpOp2.MULT, AggOp.SUM, left, right);
mmult.setOutputBlocksizes(left.getRowsInBlock(), right.getColsInBlock());
copyLineNumbers(left, mmult);
mmult.refreshSizeInformation();
return mmult;
}
public static ParameterizedBuiltinOp createParameterizedBuiltinOp(Hop input, HashMap<String,Hop> args, ParamBuiltinOp op) {
ParameterizedBuiltinOp pbop = new ParameterizedBuiltinOp("tmp", DataType.MATRIX, ValueType.DOUBLE, op, args);
pbop.setOutputBlocksizes(input.getRowsInBlock(), input.getColsInBlock());
copyLineNumbers(input, pbop);
pbop.refreshSizeInformation();
return pbop;
}
public static Hop createScalarIndexing(Hop input, long rix, long cix) {
Hop ix = createIndexingOp(input, rix, cix);
return createUnary(ix, OpOp1.CAST_AS_SCALAR);
}
public static IndexingOp createIndexingOp(Hop input, long rix, long cix) {
LiteralOp row = new LiteralOp(rix);
LiteralOp col = new LiteralOp(cix);
return createIndexingOp(input, row, row, col, col);
}
public static IndexingOp createIndexingOp(Hop input, Hop rl, Hop ru, Hop cl, Hop cu) {
IndexingOp ix = new IndexingOp("tmp", DataType.MATRIX, ValueType.DOUBLE, input, rl, ru, cl, cu, rl==ru, cl==cu);
ix.setOutputBlocksizes(input.getRowsInBlock(), input.getColsInBlock());
copyLineNumbers(input, ix);
ix.refreshSizeInformation();
return ix;
}
public static LeftIndexingOp createLeftIndexingOp(Hop lhs, Hop rhs, Hop rl, Hop ru, Hop cl, Hop cu) {
LeftIndexingOp ix = new LeftIndexingOp("tmp", DataType.MATRIX, ValueType.DOUBLE, lhs, rhs, rl, ru, cl, cu, rl==ru, cl==cu);
ix.setOutputBlocksizes(lhs.getRowsInBlock(), lhs.getColsInBlock());
copyLineNumbers(lhs, ix);
ix.refreshSizeInformation();
return ix;
}
public static NaryOp createNary(OpOpN op, Hop... inputs) throws HopsException {
Hop mainInput = inputs[0];
NaryOp nop = new NaryOp(mainInput.getName(), mainInput.getDataType(),
mainInput.getValueType(), op, inputs);
nop.setOutputBlocksizes(mainInput.getRowsInBlock(), mainInput.getColsInBlock());
copyLineNumbers(mainInput, nop);
nop.refreshSizeInformation();
return nop;
}
public static Hop createValueHop( Hop hop, boolean row )
throws HopsException
{
Hop ret = null;
if( row ){
ret = hop.rowsKnown() ? new LiteralOp(hop.getDim1()) :
new UnaryOp("tmprows", DataType.SCALAR, ValueType.INT, OpOp1.NROW, hop);
}
else{
ret = hop.colsKnown() ? new LiteralOp(hop.getDim2()) :
new UnaryOp("tmpcols", DataType.SCALAR, ValueType.INT, OpOp1.NCOL, hop);
}
return ret;
}
public static DataGenOp createSeqDataGenOp( Hop input )
throws HopsException
{
return createSeqDataGenOp(input, true);
}
public static DataGenOp createSeqDataGenOp( Hop input, boolean asc )
throws HopsException
{
Hop to = input.rowsKnown() ? new LiteralOp(input.getDim1()) :
new UnaryOp("tmprows", DataType.SCALAR, ValueType.INT, OpOp1.NROW, input);
HashMap<String, Hop> params = new HashMap<>();
if( asc ) {
params.put(Statement.SEQ_FROM, new LiteralOp(1));
params.put(Statement.SEQ_TO, to);
params.put(Statement.SEQ_INCR, new LiteralOp(1));
}
else {
params.put(Statement.SEQ_FROM, to);
params.put(Statement.SEQ_TO, new LiteralOp(1));
params.put(Statement.SEQ_INCR, new LiteralOp(-1));
}
//note internal refresh size information
DataGenOp datagen = new DataGenOp(DataGenMethod.SEQ, new DataIdentifier("tmp"), params);
datagen.setOutputBlocksizes(input.getRowsInBlock(), input.getColsInBlock());
copyLineNumbers(input, datagen);
return datagen;
}
public static TernaryOp createTernaryOp(Hop mleft, Hop smid, Hop mright, OpOp3 op) {
TernaryOp ternOp = new TernaryOp("tmp", DataType.MATRIX, ValueType.DOUBLE, op, mleft, smid, mright);
ternOp.setOutputBlocksizes(mleft.getRowsInBlock(), mleft.getColsInBlock());
copyLineNumbers(mleft, ternOp);
ternOp.refreshSizeInformation();
return ternOp;
}
public static DataOp createDataOp(String name, Hop input, DataOpTypes type) {
DataOp dop = new DataOp(name, input.getDataType(), input.getValueType(), input, type, null);
dop.setOutputBlocksizes(input.getRowsInBlock(), input.getColsInBlock());
copyLineNumbers(input, dop);
dop.refreshSizeInformation();
return dop;
}
public static void setOutputParameters( Hop hop, long rlen, long clen, long brlen, long bclen, long nnz ) {
hop.setDim1( rlen );
hop.setDim2( clen );
hop.setOutputBlocksizes(brlen, bclen );
hop.setNnz( nnz );
}
public static void setOutputParametersForScalar( Hop hop ) {
hop.setDataType(DataType.SCALAR);
hop.setDim1( 0 );
hop.setDim2( 0 );
hop.setOutputBlocksizes(-1, -1 );
hop.setNnz( -1 );
}
public static void refreshOutputParameters( Hop hnew, Hop hold ) {
hnew.setDim1( hold.getDim1() );
hnew.setDim2( hold.getDim2() );
hnew.setOutputBlocksizes(hold.getRowsInBlock(), hold.getColsInBlock());
hnew.refreshSizeInformation();
}
public static void copyLineNumbers(Hop src, Hop dest) {
dest.setParseInfo(src);
}
public static void updateHopCharacteristics( Hop hop, long brlen, long bclen, Hop src )
{
updateHopCharacteristics(hop, brlen, bclen, new MemoTable(), src);
}
public static void updateHopCharacteristics( Hop hop, long brlen, long bclen, MemoTable memo, Hop src )
{
//update block sizes and dimensions
hop.setOutputBlocksizes(brlen, bclen);
hop.refreshSizeInformation();
//compute memory estimates (for exec type selection)
hop.computeMemEstimate(memo);
//update line numbers
HopRewriteUtils.copyLineNumbers(src, hop);
}
///////////////////////////////////
// hop size information
public static boolean isDimsKnown( Hop hop ) {
return hop.dimsKnown();
}
public static boolean isEmpty( Hop hop ) {
return ( hop.getNnz()==0 );
}
public static boolean isEqualSize( Hop hop1, Hop hop2 ) {
return (hop1.dimsKnown() && hop2.dimsKnown()
&& hop1.getDim1() == hop2.getDim1()
&& hop1.getDim2() == hop2.getDim2());
}
public static boolean isEqualSize( Hop hop1, Hop... hops ) {
boolean ret = hop1.dimsKnown();
for( int i=0; i<hops.length && ret; i++ )
ret &= isEqualSize(hop1, hops[i]);
return ret;
}
public static boolean isSingleBlock( Hop hop ) {
return isSingleBlock(hop, true)
&& isSingleBlock(hop, false);
}
/**
* Checks our BLOCKSIZE CONSTRAINT, w/ awareness of forced single node
* execution mode.
*
* @param hop high-level operator
* @param cols true if cols
* @return true if single block
*/
public static boolean isSingleBlock( Hop hop, boolean cols )
{
//awareness of forced exec single node (e.g., standalone), where we can
//guarantee a single block independent of the size because always in CP.
if( DMLScript.rtplatform == RUNTIME_PLATFORM.SINGLE_NODE ) {
return true;
}
//check row- or column-wise single block constraint
return cols ? (hop.colsKnown() && hop.getDim2()<=hop.getColsInBlock()) :
(hop.rowsKnown() && hop.getDim1()<=hop.getRowsInBlock());
}
public static boolean isOuterProductLikeMM( Hop hop ) {
return isMatrixMultiply(hop) && hop.dimsKnown()
&& hop.getInput().get(0).dimsKnown() && hop.getInput().get(1).dimsKnown()
&& hop.getInput().get(0).getDim1() > hop.getInput().get(0).getDim2()
&& hop.getInput().get(1).getDim1() < hop.getInput().get(1).getDim2();
}
public static boolean isValidOuterBinaryOp( OpOp2 op ) {
String opcode = Hop.getBinaryOpCode(op);
return (Hop.getOpOp2ForOuterVectorOperation(opcode) == op);
}
public static boolean isSparse(Hop hop) {
return hop.dimsKnown(true) //dims and nnz known
&& MatrixBlock.evalSparseFormatInMemory(hop.getDim1(), hop.getDim2(), hop.getNnz());
}
public static boolean isDense(Hop hop) {
return hop.dimsKnown(true) //dims and nnz known
&& !MatrixBlock.evalSparseFormatInMemory(hop.getDim1(), hop.getDim2(), hop.getNnz());
}
public static boolean isSparse( Hop hop, double threshold ) {
return hop.getSparsity() < threshold;
}
public static boolean isEqualValue( LiteralOp hop1, LiteralOp hop2 )
throws HopsException
{
//check for string (no defined double value)
if( hop1.getValueType()==ValueType.STRING
|| hop2.getValueType()==ValueType.STRING )
{
return false;
}
double val1 = getDoubleValue(hop1);
double val2 = getDoubleValue(hop2);
return ( val1 == val2 );
}
public static boolean isNotMatrixVectorBinaryOperation( Hop hop )
{
boolean ret = true;
if( hop instanceof BinaryOp )
{
BinaryOp bop = (BinaryOp) hop;
Hop left = bop.getInput().get(0);
Hop right = bop.getInput().get(1);
boolean mv = (left.getDim1()>1 && right.getDim1()==1)
|| (left.getDim2()>1 && right.getDim2()==1);
ret = isDimsKnown(bop) && !mv;
}
return ret;
}
public static boolean isReorg(Hop hop, ReOrgOp type) {
return hop instanceof ReorgOp && ((ReorgOp)hop).getOp()==type;
}
public static boolean isReorg(Hop hop, ReOrgOp... types) {
return ( hop instanceof ReorgOp
&& ArrayUtils.contains(types, ((ReorgOp) hop).getOp()));
}
public static boolean isTransposeOperation(Hop hop) {
return isReorg(hop, ReOrgOp.TRANSPOSE);
}
public static boolean isTransposeOperation(Hop hop, int maxParents) {
return isTransposeOperation(hop) && hop.getParent().size() <= maxParents;
}
public static boolean containsTransposeOperation(ArrayList<Hop> hops) {
boolean ret = false;
for( Hop hop : hops )
ret |= isTransposeOperation(hop);
return ret;
}
public static boolean isTransposeOfItself(Hop hop1, Hop hop2) {
return isTransposeOperation(hop1) && hop1.getInput().get(0) == hop2
|| isTransposeOperation(hop2) && hop2.getInput().get(0) == hop1;
}
public static boolean isTsmmInput(Hop input) {
if( input.getParent().size()==2 )
for(int i=0; i<2; i++)
if( isMatrixMultiply(input.getParent().get(i)) && isTransposeOfItself(
input.getParent().get(i).getInput().get(0), input.getParent().get(i).getInput().get(1)) )
return true;
return false;
}
public static boolean isBinary(Hop hop, OpOp2 type) {
return hop instanceof BinaryOp && ((BinaryOp)hop).getOp()==type;
}
public static boolean isBinary(Hop hop, OpOp2... types) {
return ( hop instanceof BinaryOp
&& ArrayUtils.contains(types, ((BinaryOp) hop).getOp()));
}
public static boolean isBinary(Hop hop, OpOp2 type, int maxParents) {
return isBinary(hop, type) && hop.getParent().size() <= maxParents;
}
public static boolean isBinarySparseSafe(Hop hop) {
if( !(hop instanceof BinaryOp) )
return false;
if( isBinary(hop, OpOp2.MULT, OpOp2.DIV) )
return true;
BinaryOp bop = (BinaryOp) hop;
Hop lit = bop.getInput().get(0) instanceof LiteralOp ? bop.getInput().get(0) :
bop.getInput().get(1) instanceof LiteralOp ? bop.getInput().get(1) : null;
return lit != null && OptimizerUtils
.isBinaryOpSparsityConditionalSparseSafe(bop.getOp(), (LiteralOp)lit);
}
public static boolean isBinaryMatrixScalarOperation(Hop hop) {
return hop instanceof BinaryOp &&
((hop.getInput().get(0).getDataType().isMatrix() && hop.getInput().get(1).getDataType().isScalar())
||(hop.getInput().get(1).getDataType().isMatrix() && hop.getInput().get(0).getDataType().isScalar()));
}
public static boolean isBinaryMatrixMatrixOperation(Hop hop) {
return hop instanceof BinaryOp
&& hop.getInput().get(0).getDataType().isMatrix() && hop.getInput().get(1).getDataType().isMatrix()
&& hop.getInput().get(0).dimsKnown() && hop.getInput().get(0).getDim1() > 1 && hop.getInput().get(0).getDim2() > 1
&& hop.getInput().get(1).dimsKnown() && hop.getInput().get(1).getDim1() > 1 && hop.getInput().get(1).getDim2() > 1;
}
public static boolean isBinaryMatrixMatrixOperationWithSharedInput(Hop hop) {
boolean ret = isBinaryMatrixMatrixOperation(hop);
ret = ret && (rContainsInput(hop.getInput().get(0), hop.getInput().get(1), new HashSet<Long>())
|| rContainsInput(hop.getInput().get(1), hop.getInput().get(0), new HashSet<Long>()));
return ret;
}
public static boolean isBinaryMatrixScalar(Hop hop, OpOp2 type, double val) {
return isBinary(hop, type)
&& (isLiteralOfValue(hop.getInput().get(0), val)
|| isLiteralOfValue(hop.getInput().get(1), val));
}
public static boolean isTernary(Hop hop, OpOp3 type) {
return hop instanceof TernaryOp && ((TernaryOp)hop).getOp()==type;
}
public static boolean isTernary(Hop hop, OpOp3... types) {
return ( hop instanceof TernaryOp
&& ArrayUtils.contains(types, ((TernaryOp) hop).getOp()));
}
public static boolean containsInput(Hop current, Hop probe) {
return rContainsInput(current, probe, new HashSet<Long>());
}
private static boolean rContainsInput(Hop current, Hop probe, HashSet<Long> memo) {
if( memo.contains(current.getHopID()) )
return false;
boolean ret = false;
for( int i=0; i<current.getInput().size() && !ret; i++ )
ret |= rContainsInput(current.getInput().get(i), probe, memo);
ret |= (current == probe);
memo.add(current.getHopID());
return ret;
}
public static boolean isData(Hop hop, DataOpTypes type) {
return hop instanceof DataOp
&& ((DataOp)hop).getDataOpType()==type;
}
public static boolean isBinaryMatrixColVectorOperation(Hop hop) {
return hop instanceof BinaryOp
&& hop.getInput().get(0).getDataType().isMatrix() && hop.getInput().get(1).getDataType().isMatrix()
&& hop.getInput().get(0).dimsKnown() && hop.getInput().get(1).dimsKnown() && hop.getInput().get(1).getDim2() == 1;
}
public static boolean isUnary(Hop hop, OpOp1 type) {
return hop instanceof UnaryOp && ((UnaryOp)hop).getOp()==type;
}
public static boolean isUnary(Hop hop, OpOp1 type, int maxParents) {
return isUnary(hop, type) && hop.getParent().size() <= maxParents;
}
public static boolean isUnary(Hop hop, OpOp1... types) {
return ( hop instanceof UnaryOp
&& ArrayUtils.contains(types, ((UnaryOp) hop).getOp()));
}
public static boolean isMatrixMultiply(Hop hop) {
return hop instanceof AggBinaryOp && ((AggBinaryOp)hop).isMatrixMultiply();
}
public static boolean isAggUnaryOp(Hop hop, AggOp...op) {
if( !(hop instanceof AggUnaryOp) )
return false;
AggOp hopOp = ((AggUnaryOp)hop).getOp();
return ArrayUtils.contains(op, hopOp);
}
public static boolean isSum(Hop hop) {
return (hop instanceof AggUnaryOp && ((AggUnaryOp)hop).getOp()==AggOp.SUM);
}
public static boolean isSumSq(Hop hop) {
return (hop instanceof AggUnaryOp && ((AggUnaryOp)hop).getOp()==AggOp.SUM_SQ);
}
public static boolean isNary(Hop hop, OpOpN type) {
return hop instanceof NaryOp && ((NaryOp)hop).getOp()==type;
}
public static boolean isNary(Hop hop, OpOpN... types) {
return ( hop instanceof NaryOp
&& ArrayUtils.contains(types, ((NaryOp) hop).getOp()));
}
public static boolean isNonZeroIndicator(Hop pred, Hop hop )
{
if( pred instanceof BinaryOp && ((BinaryOp)pred).getOp()==OpOp2.NOTEQUAL
&& pred.getInput().get(0) == hop //depend on common subexpression elimination
&& pred.getInput().get(1) instanceof LiteralOp
&& HopRewriteUtils.getDoubleValueSafe((LiteralOp)pred.getInput().get(1))==0 )
{
return true;
}
return false;
}
public static boolean checkInputDataTypes(Hop hop, DataType... dt) {
for( int i=0; i<hop.getInput().size(); i++ )
if( hop.getInput().get(i).getDataType() != dt[i] )
return false;
return true;
}
public static boolean isColumnRightIndexing(Hop hop) {
return hop instanceof IndexingOp
&& ((IndexingOp) hop).isColLowerEqualsUpper()
&& ((hop.dimsKnown() && hop.getDim1() == hop.getInput().get(0).getDim1())
|| (isLiteralOfValue(hop.getInput().get(1), 1)
&& isUnary(hop.getInput().get(2), OpOp1.NROW)
&& hop.getInput().get(2).getInput().get(0)==hop.getInput().get(0)));
}
public static boolean isFullColumnIndexing(LeftIndexingOp hop) {
return hop.isColLowerEqualsUpper()
&& isLiteralOfValue(hop.getInput().get(2), 1)
&& (isLiteralOfValue(hop.getInput().get(3), hop.getDim1())
|| isSizeExpressionOf(hop.getInput().get(3), hop.getInput().get(0), true));
}
public static boolean isFullColumnIndexing(IndexingOp hop) {
return hop.isColLowerEqualsUpper()
&& isLiteralOfValue(hop.getInput().get(1), 1)
&& (isLiteralOfValue(hop.getInput().get(2), hop.getDim1())
|| isSizeExpressionOf(hop.getInput().get(2), hop.getInput().get(0), true));
}
public static boolean isFullRowIndexing(LeftIndexingOp hop) {
return hop.isRowLowerEqualsUpper()
&& isLiteralOfValue(hop.getInput().get(4), 1)
&& (isLiteralOfValue(hop.getInput().get(5), hop.getDim2())
|| isSizeExpressionOf(hop.getInput().get(5), hop.getInput().get(0), false));
}
public static boolean isFullRowIndexing(IndexingOp hop) {
return hop.isRowLowerEqualsUpper()
&& isLiteralOfValue(hop.getInput().get(3), 1)
&& (isLiteralOfValue(hop.getInput().get(4), hop.getDim2())
|| isSizeExpressionOf(hop.getInput().get(4), hop.getInput().get(0), false));
}
public static boolean isColumnRangeIndexing(IndexingOp hop) {
return ((isLiteralOfValue(hop.getInput().get(1), 1)
&& isLiteralOfValue(hop.getInput().get(2), hop.getInput().get(0).getDim1()))
|| hop.getDim1() == hop.getInput().get(0).getDim1())
&& isLiteralOfValue(hop.getInput().get(3), 1)
&& hop.getInput().get(4) instanceof LiteralOp;
}
public static boolean isConsecutiveIndex(Hop index, Hop index2) {
return (index instanceof LiteralOp && index2 instanceof LiteralOp) ?
getDoubleValueSafe((LiteralOp)index2) == (getDoubleValueSafe((LiteralOp)index)+1) :
(isBinaryMatrixScalar(index2, OpOp2.PLUS, 1) &&
(index2.getInput().get(0) == index || index2.getInput().get(1) == index));
}
public static boolean isUnnecessaryRightIndexing(Hop hop) {
if( !(hop instanceof IndexingOp) )
return false;
//note: in addition to equal sizes, we also check a valid
//starting row and column ranges of 1 in order to guard against
//invalid modifications in the presence of invalid index ranges
//(e.g., X[,2] on a column vector needs to throw an error)
return isEqualSize(hop, hop.getInput().get(0))
&& !(hop.getDim1()==1 && hop.getDim2()==1)
&& isLiteralOfValue(hop.getInput().get(1), 1) //rl
&& isLiteralOfValue(hop.getInput().get(3), 1); //cl
}
public static boolean isScalarMatrixBinaryMult( Hop hop ) {
return hop instanceof BinaryOp && ((BinaryOp)hop).getOp()==OpOp2.MULT
&& ((hop.getInput().get(0).getDataType()==DataType.SCALAR && hop.getInput().get(1).getDataType()==DataType.MATRIX)
|| (hop.getInput().get(0).getDataType()==DataType.MATRIX && hop.getInput().get(1).getDataType()==DataType.SCALAR));
}
public static boolean isBasic1NSequence(Hop hop) {
if( hop instanceof DataGenOp && ((DataGenOp)hop).getOp() == DataGenMethod.SEQ ) {
DataGenOp dgop = (DataGenOp) hop;
Hop from = dgop.getInput().get(dgop.getParamIndex(Statement.SEQ_FROM));
Hop incr = dgop.getInput().get(dgop.getParamIndex(Statement.SEQ_INCR));
return (from instanceof LiteralOp && getDoubleValueSafe((LiteralOp)from)==1)
&&(incr instanceof LiteralOp && getDoubleValueSafe((LiteralOp)incr)==1);
}
return false;
}
public static boolean isBasic1NSequence(Hop seq, Hop input, boolean row) {
if( seq instanceof DataGenOp && ((DataGenOp)seq).getOp() == DataGenMethod.SEQ ) {
DataGenOp dgop = (DataGenOp) seq;
Hop from = dgop.getInput().get(dgop.getParamIndex(Statement.SEQ_FROM));
Hop to = dgop.getInput().get(dgop.getParamIndex(Statement.SEQ_TO));
Hop incr = dgop.getInput().get(dgop.getParamIndex(Statement.SEQ_INCR));
return isLiteralOfValue(from, 1) && isLiteralOfValue(incr, 1)
&& isSizeExpressionOf(to, input, row);
}
return false;
}
public static boolean isBasicN1Sequence(Hop hop)
{
boolean ret = false;
if( hop instanceof DataGenOp )
{
DataGenOp dgop = (DataGenOp) hop;
if( dgop.getOp() == DataGenMethod.SEQ ){
Hop to = dgop.getInput().get(dgop.getParamIndex(Statement.SEQ_TO));
Hop incr = dgop.getInput().get(dgop.getParamIndex(Statement.SEQ_INCR));
ret = (to instanceof LiteralOp && getDoubleValueSafe((LiteralOp)to)==1)
&&(incr instanceof LiteralOp && getDoubleValueSafe((LiteralOp)incr)==-1);
}
}
return ret;
}
public static Hop getBasic1NSequenceMax(Hop hop)
throws HopsException
{
if( isDataGenOp(hop, DataGenMethod.SEQ) ) {
DataGenOp dgop = (DataGenOp) hop;
return dgop.getInput()
.get(dgop.getParamIndex(Statement.SEQ_TO));
}
throw new HopsException("Failed to retrieve 'to' argument from basic 1-N sequence.");
}
public static boolean isSizeExpressionOf(Hop size, Hop input, boolean row) {
return (input.dimsKnown() && isLiteralOfValue(size, row?input.getDim1():input.getDim2()))
|| ((row ? isUnary(size, OpOp1.NROW) : isUnary(size, OpOp1.NCOL)) && (size.getInput().get(0)==input
|| (isColumnRightIndexing(input) && size.getInput().get(0)==input.getInput().get(0))));
}
public static boolean hasOnlyWriteParents( Hop hop, boolean inclTransient, boolean inclPersistent )
{
boolean ret = true;
ArrayList<Hop> parents = hop.getParent();
for( Hop p : parents )
{
if( inclTransient && inclPersistent )
ret &= ( p instanceof DataOp && (((DataOp)p).getDataOpType()==DataOpTypes.TRANSIENTWRITE
|| ((DataOp)p).getDataOpType()==DataOpTypes.PERSISTENTWRITE));
else if(inclTransient)
ret &= ( p instanceof DataOp && ((DataOp)p).getDataOpType()==DataOpTypes.TRANSIENTWRITE);
else if(inclPersistent)
ret &= ( p instanceof DataOp && ((DataOp)p).getDataOpType()==DataOpTypes.PERSISTENTWRITE);
}
return ret;
}
public static boolean alwaysRequiresReblock(Hop hop) {
return (hop instanceof DataOp
&& ((DataOp)hop).getDataOpType()==DataOpTypes.PERSISTENTREAD
&& ((DataOp)hop).getInputFormatType()!=FileFormatTypes.BINARY);
}
public static boolean containsOp(ArrayList<Hop> candidates, Class<? extends Hop> clazz) {
if( candidates != null )
for( Hop cand : candidates )
if( cand.getClass().equals(clazz) )
return true;
return false;
}
public static boolean rHasSimpleReadChain(Hop root, String var)
{
if( root.isVisited() )
return false;
boolean ret = false;
//handle leaf node for variable
if( root instanceof DataOp && ((DataOp)root).isRead()
&& root.getName().equals(var) )
{
ret = (root.getParent().size()<=1);
}
//recursively process childs (on the entire path to var, all
//intermediates are supposed to have at most one consumer, but
//side-ways inputs can have arbitrary dag structures)
for( Hop c : root.getInput() ) {
if( rHasSimpleReadChain(c, var) )
ret |= root.getParent().size()<=1;
}
root.setVisited();
return ret;
}
public static boolean rContainsRead(Hop root, String var, boolean includeMetaOp)
{
if( root.isVisited() )
return false;
boolean ret = false;
//handle leaf node for variable
if( root instanceof DataOp && ((DataOp)root).isRead()
&& root.getName().equals(var) )
{
boolean onlyMetaOp = true;
if( !includeMetaOp ){
for( Hop p : root.getParent() ) {
onlyMetaOp &= (p instanceof UnaryOp
&& (((UnaryOp)p).getOp()==OpOp1.NROW
|| ((UnaryOp)p).getOp()==OpOp1.NCOL) );
}
ret = !onlyMetaOp;
}
else
ret = true;
}
//recursively process childs
for( Hop c : root.getInput() )
ret |= rContainsRead(c, var, includeMetaOp);
root.setVisited();
return ret;
}
//////////////////////////////////////
// utils for lookup tables
public static boolean isValidOp( AggOp input, AggOp... validTab ) {
return ArrayUtils.contains(validTab, input);
}
public static boolean isValidOp( OpOp1 input, OpOp1... validTab ) {
return ArrayUtils.contains(validTab, input);
}
public static boolean isValidOp( OpOp2 input, OpOp2... validTab ) {
return ArrayUtils.contains(validTab, input);
}
public static boolean isValidOp( ReOrgOp input, ReOrgOp... validTab ) {
return ArrayUtils.contains(validTab, input);
}
public static boolean isValidOp( ParamBuiltinOp input, ParamBuiltinOp... validTab ) {
return ArrayUtils.contains(validTab, input);
}
public static int getValidOpPos( OpOp2 input, OpOp2... validTab ) {
return ArrayUtils.indexOf(validTab, input);
}
/**
* Compares the size of outputs from hop1 and hop2, in terms of number
* of matrix cells.
*
* @param hop1 high-level operator 1
* @param hop2 high-level operator 2
* @return 0 if sizes are equal, &lt;0 for hop1&lt;hop2, &gt;0 for hop1&gt;hop2.
*/
public static int compareSize( Hop hop1, Hop hop2 ) {
long size1 = hop1.getDim1() * hop1.getDim2();
long size2 = hop2.getDim1() * hop2.getDim2();
return Long.compare(size1, size2);
}
public static boolean isLastLevelStatementBlock(StatementBlock sb) {
return !(sb instanceof FunctionStatementBlock
|| sb instanceof WhileStatementBlock
|| sb instanceof IfStatementBlock
|| sb instanceof ForStatementBlock); //incl parfor
}
public static long getMaxNrowInput(Hop hop) {
return getMaxInputDim(hop, true);
}
public static long getMaxNcolInput(Hop hop) {
return getMaxInputDim(hop, false);
}
public static long getMaxInputDim(Hop hop, boolean dim1) {
return hop.getInput().stream().mapToLong(
h -> (dim1?h.getDim1():h.getDim2())).max().orElse(-1);
}
public static long getSumValidInputDims(Hop hop, boolean dim1) {
if( !hasValidInputDims(hop, dim1) )
return -1;
return hop.getInput().stream().mapToLong(
h -> (dim1?h.getDim1():h.getDim2())).sum();
}
public static boolean hasValidInputDims(Hop hop, boolean dim1) {
return hop.getInput().stream().allMatch(
h -> dim1 ? h.rowsKnown() : h.colsKnown());
}
}