blob: d81b6a86b3b29dbed521129c016256b053cebbdc [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.sysds.lops;
import java.util.ArrayList;
import org.apache.sysds.common.Types.DataType;
import org.apache.sysds.common.Types.ValueType;
import org.apache.sysds.lops.LopProperties.ExecType;
import org.apache.sysds.lops.compile.Dag;
import org.apache.sysds.runtime.privacy.PrivacyConstraint;
/**
* Base class for all Lops.
*/
public abstract class Lop
{
public enum Type {
Data, DataGen, //CP/MR read/write/datagen
ReBlock, CSVReBlock, //MR reblock operations
MatMultCP,
MMCJ, MMRJ, MMTSJ, PMMJ, MapMult, MapMultChain, //MR matrix multiplications
UnaryCP, UNARY, BinaryCP, Binary, Ternary, Nary, //CP/MR unary/binary/ternary
RightIndex, LeftIndex, ZeroOut, //CP/MR indexing
Aggregate, PartialAggregate, //CP/MR aggregation
BinUaggChain, UaggOuterChain, //CP/MR aggregation
TernaryAggregate, //CP ternary-binary aggregates
Grouping, //MR grouping
Append, //CP/MR append (column append)
CombineUnary, CombineBinary, CombineTernary, //MR combine (stitch together)
CentralMoment, CoVariance, GroupedAgg, GroupedAggM,
Transform, DataPartition, RepMat, //CP/MR reorganization, partitioning, replication
ParameterizedBuiltin, //CP/MR parameterized ops (name/value)
FunctionCallCP, FunctionCallCPSingle, //CP function calls
CumulativePartialAggregate, CumulativeSplitAggregate, CumulativeOffsetBinary, //MR cumsum/cumprod/cummin/cummax
WeightedSquaredLoss, WeightedSigmoid, WeightedDivMM, WeightedCeMM, WeightedUMM,
SortKeys, PickValues, Ctable,
Checkpoint, //Spark persist into storage level
PlusMult, MinusMult, //CP
SpoofFused, //CP/SP generated fused operator
Sql, //CP sql read
Federated //FED federated read
}
/**
* Lop types
*/
public enum SimpleInstType {
Scalar
}
public enum VisitStatus {
DONE, NOTVISITED
}
public static final String FILE_SEPARATOR = "/";
public static final String PROCESS_PREFIX = "_p";
public static final String CP_ROOT_THREAD_ID = "_t0";
public static final String CP_CHILD_THREAD = "_t";
public static final double SAMPLE_FRACTION = 0.01; // for row sampling in distributed frame meta operations
//special delimiters w/ extended ASCII characters to avoid collisions
public static final String INSTRUCTION_DELIMITOR = "\u2021";
public static final String OPERAND_DELIMITOR = "\u00b0";
public static final String VALUETYPE_PREFIX = "\u00b7" ;
public static final String DATATYPE_PREFIX = VALUETYPE_PREFIX;
public static final String LITERAL_PREFIX = VALUETYPE_PREFIX;
public static final String VARIABLE_NAME_PLACEHOLDER = "\u00b6";
public static final String NAME_VALUE_SEPARATOR = "="; // e.g., used in parameterized builtins
public static final String MATRIX_VAR_NAME_PREFIX = "_mVar";
public static final String FRAME_VAR_NAME_PREFIX = "_fVar";
public static final String SCALAR_VAR_NAME_PREFIX = "_Var";
public static final String UPDATE_INPLACE_PREFIX = "_uip";
// Boolean array to hold the list of nodes(lops) in the DAG that are reachable from this lop.
private boolean[] reachable = null;
private DataType _dataType;
private ValueType _valueType;
private VisitStatus _visited = VisitStatus.NOTVISITED;
protected Lop.Type type;
/**
* handle to all inputs and outputs.
*/
protected ArrayList<Lop> inputs;
protected ArrayList<Lop> outputs;
/**
* Privacy Constraint
*/
protected PrivacyConstraint privacyConstraint;
/**
* refers to #lops whose input is equal to the output produced by this lop.
* This is used in generating rmvar instructions as soon as the output produced
* by this lop is consumed. Otherwise, such rmvar instructions are added
* at the end of program blocks.
*
*/
protected int consumerCount;
/**
* handle to output parameters, dimensions, blocking, etc.
*/
protected OutputParameters outParams = null;
protected LopProperties lps = null;
/**
* Constructor to be invoked by base class.
*
* @param t lop type
* @param dt data type
* @param vt value type
*/
public Lop(Type t, DataType dt, ValueType vt) {
type = t;
_dataType = dt; // data type of the output produced from this LOP
_valueType = vt; // value type of the output produced from this LOP
inputs = new ArrayList<>();
outputs = new ArrayList<>();
outParams = new OutputParameters();
lps = new LopProperties();
}
/**
* get visit status of node
*
* @return visit status
*/
public VisitStatus getVisited() {
return _visited;
}
/**
* set visit status of node
*
* @param visited visit status
*/
public void setVisited(VisitStatus visited) {
_visited = visited;
}
public boolean[] getReachable() {
return reachable;
}
public boolean[] createReachable(int size) {
reachable = new boolean[size];
return reachable;
}
public boolean isDataExecLocation() {
return this instanceof Data;
}
protected void setupLopProperties(ExecType et) {
//setup Spark parameters
lps.setProperties( inputs, et);
}
/**
* get data type of the output that is produced by this lop
*
* @return data type
*/
public DataType getDataType() {
return _dataType;
}
/**
* set data type of the output that is produced by this lop
*
* @param dt data type
*/
public void setDataType(DataType dt) {
_dataType = dt;
}
/**
* get value type of the output that is produced by this lop
*
* @return value type
*/
public ValueType getValueType() {
return _valueType;
}
/**
* set value type of the output that is produced by this lop
*
* @param vt value type
*/
public void setValueType(ValueType vt) {
_valueType = vt;
}
/**
* Method to get Lop type.
*
* @return lop type
*/
public Lop.Type getType() {
return type;
}
/**
* Method to get input of Lops
*
* @return list of input lops
*/
public ArrayList<Lop> getInputs() {
return inputs;
}
/**
* Method to get output of Lops
*
* @return list of output lops
*/
public ArrayList<Lop> getOutputs() {
return outputs;
}
/**
* Method to add input to Lop
*
* @param op input lop
*/
public void addInput(Lop op) {
inputs.add(op);
}
/**
* Method to add output to Lop
*
* @param op output lop
*/
public void addOutput(Lop op) {
outputs.add(op);
}
/**
* Method to set privacy constraint of Lop.
* @param privacy privacy constraint instance
*/
public void setPrivacyConstraint(PrivacyConstraint privacy){
privacyConstraint = privacy;
}
public PrivacyConstraint getPrivacyConstraint(){
return privacyConstraint;
}
public void setConsumerCount(int cc) {
consumerCount = cc;
}
public int removeConsumer() {
consumerCount--;
return consumerCount;
}
/**
* Method to have Lops print their state. This is for debugging purposes.
*/
@Override
public abstract String toString();
public void resetVisitStatus() {
if (this.getVisited() == Lop.VisitStatus.NOTVISITED)
return;
for (int i = 0; i < this.getInputs().size(); i++) {
this.getInputs().get(i).resetVisitStatus();
}
this.setVisited(Lop.VisitStatus.NOTVISITED);
}
/**
* Method to return the ID of LOP
*
* @return lop ID
*/
public long getID() {
return lps.getID();
}
public int getLevel() {
return lps.getLevel();
}
protected void setLevel() {
lps.setLevel(inputs);
}
protected void updateLevel(int newLevel) {
if(newLevel < getLevel()) {
throw new RuntimeException("Decrement the levels not supported.");
}
else if(newLevel > getLevel()) {
lps.setLevel(newLevel);
for(Lop out : outputs) {
if(out.getLevel() < newLevel+1)
out.updateLevel(newLevel+1);
}
}
}
/**
* Method to get the execution type (CP, CP_FILE, MR, SPARK, GPU, INVALID) of LOP
*
* @return execution type
*/
public ExecType getExecType() {
return lps.getExecType();
}
public boolean getProducesIntermediateOutput() {
return lps.getProducesIntermediateOutput();
}
/**
* Method to recursively add LOPS to a DAG
*
* @param dag lop DAG
*/
public final void addToDag(Dag<Lop> dag) {
if( dag.addNode(this) )
for( Lop l : getInputs() )
l.addToDag(dag);
}
/**
* Method to get output parameters
*
* @return output parameters
*/
public OutputParameters getOutputParameters() {
return outParams;
}
/** Method should be overridden if needed
*
* @param output output
* @return instructions as string
*/
public String getInstructions(String output) {
throw new LopsException(this.printErrorLocation() + "Should never be invoked in Baseclass");
}
/** Method should be overridden if needed
*
* @param input1 input 1
* @param output output
* @return instructions as string
*/
public String getInstructions(String input1, String output) {
throw new LopsException(this.printErrorLocation() + "Should never be invoked in Baseclass");
}
/** Method should be overridden if needed
*
* @param input1 input 1
* @param input2 input 2
* @param output output
* @return instructions as string
*/
public String getInstructions(String input1, String input2, String output) {
throw new LopsException(this.printErrorLocation() + "Should never be invoked in Baseclass");
}
/**
* Method should be overridden if needed
*
* @param input1 input 1
* @param input2 input 2
* @param input3 input 3
* @param output output
* @return instructions as string
*/
public String getInstructions(String input1, String input2, String input3, String output) {
throw new LopsException(this.printErrorLocation() + "Should never be invoked in Baseclass");
}
/**
* Method should be overridden if needed
*
* @param input1 input 1
* @param input2 input 2
* @param input3 input 3
* @param input4 input 4
* @param output output
* @return instructions as string
*/
public String getInstructions(String input1, String input2, String input3, String input4, String output) {
throw new LopsException(this.printErrorLocation() + "Should never be invoked in Baseclass");
}
/**
* Method should be overridden if needed
*
* @param input1 input 1
* @param input2 input 2
* @param input3 input 3
* @param input4 input 4
* @param input5 input 5
* @param output output
* @return instructions as string
*/
public String getInstructions(String input1, String input2, String input3, String input4, String input5, String output) {
throw new LopsException(this.printErrorLocation() + "Should never be invoked in Baseclass");
}
/** Method should be overridden if needed
*
* @param input1 input 1
* @param input2 input 2
* @param input3 input 3
* @param input4 input 4
* @param input5 input 5
* @param input6 input 6
* @param output output
* @return instructions as string
*/
public String getInstructions(String input1, String input2, String input3, String input4, String input5, String input6, String output) {
throw new LopsException(this.printErrorLocation() + "Should never be invoked in Baseclass");
}
public String getInstructions(String input1, String input2, String input3, String input4, String input5, String input6, String input7, String output) {
throw new LopsException(this.printErrorLocation() + "Should never be invoked in Baseclass");
}
public String getInstructions(String[] inputs, String outputs) {
throw new LopsException(this.printErrorLocation() + "Should never be invoked in Baseclass");
}
/** Method should be overridden if needed
*
* @param inputs array of inputs
* @param outputs array of outputs
* @return instructions as string
*/
public String getInstructions(String[] inputs, String[] outputs) {
throw new LopsException(this.printErrorLocation() + "Should never be invoked in Baseclass");
}
/** Method should be overridden if needed
*
* @return instructions as string
*/
public String getInstructions() {
throw new LopsException(this.printErrorLocation() + "Should never be invoked in Baseclass");
}
/** Method should be overridden if needed
*
* @return simple instruction type
*/
public SimpleInstType getSimpleInstructionType() {
throw new LopsException(this.printErrorLocation() + "Should never be invoked in Baseclass");
}
///////////////////////////////////////////////////////////////////////////
// store position information for Lops
///////////////////////////////////////////////////////////////////////////
public int _beginLine, _beginColumn;
public int _endLine, _endColumn;
public String _filename;
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 setFilename(String passed) { _filename = 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 int getBeginLine() { return _beginLine; }
public int getBeginColumn() { return _beginColumn; }
public int getEndLine() { return _endLine; }
public int getEndColumn() { return _endColumn; }
public String getFilename() { return _filename; }
public String printErrorLocation(){
return "ERROR: line " + _beginLine + ", column " + _beginColumn + " -- ";
}
public String getInstructions(int input, int rowl, int rowu,
int coll, int colu, int leftRowDim,
int leftColDim, int output) {
throw new LopsException(this.printErrorLocation() + "Should never be invoked in Baseclass");
}
/**
* Function that determines if the output of a LOP is defined by a variable or not.
*
* @return true if lop output defined by a variable
*/
public boolean isVariable() {
return ( (isDataExecLocation() && !((Data)this).isLiteral())
|| !isDataExecLocation() );
}
/**
* Method to prepare instruction operand with given parameters.
*
* @param label instruction label
* @param dt data type
* @param vt value type
* @return instruction operand with data type and value type
*/
public String prepOperand(String label, DataType dt, ValueType vt) {
StringBuilder sb = new StringBuilder();
sb.append(label);
sb.append(Lop.DATATYPE_PREFIX);
sb.append(dt);
sb.append(Lop.VALUETYPE_PREFIX);
sb.append(vt);
return sb.toString();
}
/**
* Method to prepare instruction operand with given parameters.
*
* @param label instruction label
* @param dt data type
* @param vt value type
* @param literal true if literal
* @return instruction operand with data type, value type, and literal status
*/
public String prepOperand(String label, DataType dt, ValueType vt, boolean literal) {
StringBuilder sb = new StringBuilder();
sb.append(label);
sb.append(Lop.DATATYPE_PREFIX);
sb.append(dt);
sb.append(Lop.VALUETYPE_PREFIX);
sb.append(vt);
sb.append(Lop.LITERAL_PREFIX);
sb.append(literal);
return sb.toString();
}
/**
* Method to prepare instruction operand with given label. Data type
* and Value type are derived from Lop's properties.
*
* @param label instruction label
* @return instruction operand with data type and value type
*/
private String prepOperand(String label) {
StringBuilder sb = new StringBuilder("");
sb.append(label);
sb.append(Lop.DATATYPE_PREFIX);
sb.append(getDataType());
sb.append(Lop.VALUETYPE_PREFIX);
sb.append(getValueType());
return sb.toString();
}
public String prepOutputOperand() {
return prepOperand(getOutputParameters().getLabel());
}
public String prepOutputOperand(int index) {
return prepOperand(String.valueOf(index));
}
public String prepOutputOperand(String label) {
return prepOperand(label);
}
/**
* Function to prepare label for scalar inputs while generating instructions.
* It attaches placeholder suffix and prefixes if the Lop denotes a variable.
*
* @return prepared scalar label
*/
public String prepScalarLabel() {
String ret = getOutputParameters().getLabel();
if ( isVariable() ){
ret = Lop.VARIABLE_NAME_PLACEHOLDER + ret + Lop.VARIABLE_NAME_PLACEHOLDER;
}
return ret;
}
/**
* Function to be used in creating instructions for creating scalar
* operands. It decides whether or not attach placeholders for instruction
* patching. Resulting string also encodes if the operand is a literal.
*
* For non-literals:
* Placeholder prefix and suffix need to be attached for Instruction
* Patching during execution. However, they should NOT be attached IF:
* - the operand is a literal
* OR
* - the execution type is CP. This is because CP runtime has access
* to symbol table and the instruction encodes sufficient information
* to determine if an operand is a literal or not.
*
* @param et execution type
* @param label instruction label
* @return prepared scalar operand
*/
public String prepScalarOperand(ExecType et, String label) {
boolean isData = isDataExecLocation();
boolean isLiteral = (isData && ((Data)this).isLiteral());
StringBuilder sb = new StringBuilder("");
if ( et == ExecType.CP || et == ExecType.SPARK || et == ExecType.GPU || (isData && isLiteral)) {
sb.append(label);
}
else {
sb.append(Lop.VARIABLE_NAME_PLACEHOLDER);
sb.append(label);
sb.append(Lop.VARIABLE_NAME_PLACEHOLDER);
}
sb.append(Lop.DATATYPE_PREFIX);
sb.append(getDataType());
sb.append(Lop.VALUETYPE_PREFIX);
sb.append(getValueType());
sb.append(Lop.LITERAL_PREFIX);
sb.append(isLiteral);
return sb.toString();
}
public String prepScalarInputOperand(ExecType et) {
return prepScalarOperand(et, getOutputParameters().getLabel());
}
public String prepScalarInputOperand(String label) {
boolean isData = isDataExecLocation();
boolean isLiteral = (isData && ((Data)this).isLiteral());
StringBuilder sb = new StringBuilder("");
sb.append(label);
sb.append(Lop.DATATYPE_PREFIX);
sb.append(getDataType());
sb.append(Lop.VALUETYPE_PREFIX);
sb.append(getValueType());
sb.append(Lop.LITERAL_PREFIX);
sb.append(isLiteral);
return sb.toString();
}
public String prepInputOperand(int index) {
return prepInputOperand(String.valueOf(index));
}
public String prepInputOperand(String label) {
DataType dt = getDataType();
if ( dt == DataType.MATRIX ) {
return prepOperand(label);
}
else {
return prepScalarInputOperand(label);
}
}
}