/**
* (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.runtime.matrix.data;
import java.util.ArrayList;
import com.ibm.bi.dml.runtime.DMLRuntimeException;
import com.ibm.bi.dml.runtime.DMLUnsupportedOperationException;
import com.ibm.bi.dml.runtime.functionobjects.Builtin;
import com.ibm.bi.dml.lops.PartialAggregate.CorrectionLocationType;
import com.ibm.bi.dml.runtime.matrix.mapred.IndexedMatrixValue;
import com.ibm.bi.dml.runtime.matrix.operators.AggregateBinaryOperator;
import com.ibm.bi.dml.runtime.matrix.operators.AggregateOperator;
import com.ibm.bi.dml.runtime.matrix.operators.AggregateUnaryOperator;
import com.ibm.bi.dml.runtime.matrix.operators.BinaryOperator;
import com.ibm.bi.dml.runtime.matrix.operators.Operator;
import com.ibm.bi.dml.runtime.matrix.operators.ReorgOperator;
import com.ibm.bi.dml.runtime.matrix.operators.ScalarOperator;
import com.ibm.bi.dml.runtime.matrix.operators.UnaryOperator;
import com.ibm.bi.dml.runtime.util.IndexRange;
import com.ibm.bi.dml.runtime.util.UtilFunctions;
public class OperationsOnMatrixValues
{
public static void performScalarIgnoreIndexes(MatrixValue valueIn, MatrixValue valueOut, ScalarOperator op)
throws DMLUnsupportedOperationException, DMLRuntimeException
{
valueIn.scalarOperations(op, valueOut);
}
public static void performUnaryIgnoreIndexes(MatrixValue valueIn, MatrixValue valueOut, UnaryOperator op)
throws DMLUnsupportedOperationException, DMLRuntimeException
{
valueIn.unaryOperations(op, valueOut);
}
public static void performUnaryIgnoreIndexesInPlace(MatrixValue valueIn, UnaryOperator op)
throws DMLUnsupportedOperationException, DMLRuntimeException
{
valueIn.unaryOperationsInPlace(op);
}
public static void performReorg(MatrixIndexes indexesIn, MatrixValue valueIn, MatrixIndexes indexesOut,
MatrixValue valueOut, ReorgOperator op, int startRow, int startColumn, int length)
throws DMLUnsupportedOperationException, DMLRuntimeException
{
//operate on the value indexes first
op.fn.execute(indexesIn, indexesOut);
//operation on the cells inside the value
valueIn.reorgOperations(op, valueOut, startRow, startColumn, length);
}
public static void performAppend(MatrixValue valueIn1, MatrixValue valueIn2,
ArrayList<IndexedMatrixValue> outlist, int blockRowFactor, int blockColFactor, boolean cbind, boolean m2IsLast, int nextNCol)
throws DMLUnsupportedOperationException, DMLRuntimeException
{
valueIn1.appendOperations(valueIn2, outlist, blockRowFactor, blockColFactor, cbind, m2IsLast, nextNCol);
}
public static void performZeroOut(MatrixIndexes indexesIn, MatrixValue valueIn,
MatrixIndexes indexesOut, MatrixValue valueOut, IndexRange range, boolean complementary)
throws DMLUnsupportedOperationException, DMLRuntimeException
{
valueIn.zeroOutOperations(valueOut, range, complementary);
indexesOut.setIndexes(indexesIn);
}
// ------------- Ternary Operations -------------
// tertiary where all three inputs are matrices
public static void performTernary(MatrixIndexes indexesIn1, MatrixValue valueIn1, MatrixIndexes indexesIn2, MatrixValue valueIn2,
MatrixIndexes indexesIn3, MatrixValue valueIn3, CTableMap resultMap, MatrixBlock resultBlock, Operator op )
throws DMLUnsupportedOperationException, DMLRuntimeException
{
//operation on the cells inside the value
valueIn1.ternaryOperations(op, valueIn2, valueIn3, resultMap, resultBlock);
}
// tertiary where first two inputs are matrices, and third input is a scalar (double)
public static void performTernary(MatrixIndexes indexesIn1, MatrixValue valueIn1, MatrixIndexes indexesIn2, MatrixValue valueIn2,
double scalarIn3, CTableMap resultMap, MatrixBlock resultBlock, Operator op)
throws DMLUnsupportedOperationException, DMLRuntimeException
{
//operation on the cells inside the value
valueIn1.ternaryOperations(op, valueIn2, scalarIn3, false, resultMap, resultBlock);
}
// tertiary where first input is a matrix, and second and third inputs are scalars (double)
public static void performTernary(MatrixIndexes indexesIn1, MatrixValue valueIn1, double scalarIn2,
double scalarIn3, CTableMap resultMap, MatrixBlock resultBlock, Operator op )
throws DMLUnsupportedOperationException, DMLRuntimeException
{
//operation on the cells inside the value
valueIn1.ternaryOperations(op, scalarIn2, scalarIn3, resultMap, resultBlock);
}
// tertiary where first input is a matrix, and second is scalars (double)
public static void performTernary(MatrixIndexes indexesIn1, MatrixValue valueIn1, double scalarIn2, boolean left,
int brlen, CTableMap resultMap, MatrixBlock resultBlock, Operator op )
throws DMLUnsupportedOperationException, DMLRuntimeException
{
//operation on the cells inside the value
valueIn1.ternaryOperations(op, indexesIn1, scalarIn2, left, brlen, resultMap, resultBlock);
}
// tertiary where first and third inputs are matrices, and second is a scalars (double)
public static void performTernary(MatrixIndexes indexesIn1, MatrixValue valueIn1, double scalarIn2,
MatrixIndexes indexesIn3, MatrixValue valueIn3, CTableMap resultMap, MatrixBlock resultBlock, Operator op )
throws DMLUnsupportedOperationException, DMLRuntimeException
{
//operation on the cells inside the value
valueIn1.ternaryOperations(op, scalarIn2, valueIn3, resultMap, resultBlock);
}
// -----------------------------------------------------
//binary operations are those that the indexes of both cells have to be matched
public static void performBinaryIgnoreIndexes(MatrixValue value1, MatrixValue value2,
MatrixValue valueOut, BinaryOperator op)
throws DMLUnsupportedOperationException, DMLRuntimeException
{
value1.binaryOperations(op, value2, valueOut);
}
/**
*
* @param valueOut
* @param correction
* @param op
* @param rlen
* @param clen
* @param sparseHint
* @param imbededCorrection
* @throws DMLUnsupportedOperationException
* @throws DMLRuntimeException
*/
public static void startAggregation(MatrixValue valueOut, MatrixValue correction, AggregateOperator op,
int rlen, int clen, boolean sparseHint, boolean imbededCorrection)
throws DMLUnsupportedOperationException, DMLRuntimeException
{
int outRow=0, outCol=0, corRow=0, corCol=0;
if(op.correctionExists)
{
if(!imbededCorrection)
{
switch(op.correctionLocation)
{
case NONE:
outRow=rlen;
outCol=clen;
corRow=rlen;
corCol=clen;
break;
case LASTROW:
outRow=rlen-1;
outCol=clen;
corRow=1;
corCol=clen;
break;
case LASTCOLUMN:
if(op.increOp.fn instanceof Builtin
&& ( ((Builtin)(op.increOp.fn)).bFunc == Builtin.BuiltinFunctionCode.MAXINDEX
|| ((Builtin)(op.increOp.fn)).bFunc == Builtin.BuiltinFunctionCode.MININDEX) )
{
outRow = rlen;
outCol = 1;
corRow = rlen;
corCol = 1;
}
else{
outRow=rlen;
outCol=clen-1;
corRow=rlen;
corCol=1;
}
break;
case LASTTWOROWS:
outRow=rlen-2;
outCol=clen;
corRow=2;
corCol=clen;
break;
case LASTTWOCOLUMNS:
outRow=rlen;
outCol=clen-2;
corRow=rlen;
corCol=2;
break;
default:
throw new DMLRuntimeException("unrecognized correctionLocation: "+op.correctionLocation);
}
}else
{
outRow=rlen;
outCol=clen;
corRow=rlen;
corCol=clen;
}
//set initial values according to operator
if(op.initialValue==0) {
valueOut.reset(outRow, outCol, sparseHint);
correction.reset(corRow, corCol, false);
}
else {
valueOut.resetDenseWithValue(outRow, outCol, op.initialValue);
correction.resetDenseWithValue(corRow, corCol, op.initialValue);
}
}
else
{
if(op.initialValue==0)
valueOut.reset(rlen, clen, sparseHint);
else
valueOut.resetDenseWithValue(rlen, clen, op.initialValue);
}
}
public static void incrementalAggregation(MatrixValue valueAgg, MatrixValue correction, MatrixValue valueAdd,
AggregateOperator op, boolean imbededCorrection) throws DMLUnsupportedOperationException, DMLRuntimeException
{
if(op.correctionExists)
{
if(!imbededCorrection || op.correctionLocation==CorrectionLocationType.NONE)
valueAgg.incrementalAggregate(op, correction, valueAdd);
else
valueAgg.incrementalAggregate(op, valueAdd);
}
else
valueAgg.binaryOperationsInPlace(op.increOp, valueAdd);
}
public static void performAggregateUnary(MatrixIndexes indexesIn, MatrixValue valueIn, MatrixIndexes indexesOut,
MatrixValue valueOut, AggregateUnaryOperator op,int brlen, int bclen)
throws DMLUnsupportedOperationException, DMLRuntimeException
{
//operate on the value indexes first
op.indexFn.execute(indexesIn, indexesOut);
//perform on the value
valueIn.aggregateUnaryOperations(op, valueOut, brlen, bclen, indexesIn);
}
public static void performAggregateBinary(MatrixIndexes indexes1, MatrixValue value1, MatrixIndexes indexes2, MatrixValue value2,
MatrixIndexes indexesOut, MatrixValue valueOut, AggregateBinaryOperator op)
throws DMLUnsupportedOperationException, DMLRuntimeException
{
//compute output index
indexesOut.setIndexes(indexes1.getRowIndex(), indexes2.getColumnIndex());
//perform on the value
value1.aggregateBinaryOperations(indexes1, value1, indexes2, value2, valueOut, op);
}
public static void performAggregateBinaryIgnoreIndexes(
MatrixValue value1, MatrixValue value2,
MatrixValue valueOut, AggregateBinaryOperator op)
throws DMLUnsupportedOperationException, DMLRuntimeException {
//perform on the value
value1.aggregateBinaryOperations(value1, value2, valueOut, op);
}
/**
*
* @param val
* @param range
* @param brlen
* @param bclen
* @param outlist
* @throws DMLUnsupportedOperationException
* @throws DMLRuntimeException
*/
public static void performSlice(IndexedMatrixValue in, IndexRange ixrange, int brlen, int bclen, ArrayList<IndexedMatrixValue> outlist)
throws DMLUnsupportedOperationException, DMLRuntimeException
{
long cellIndexTopRow = UtilFunctions.cellIndexCalculation(in.getIndexes().getRowIndex(), brlen, 0);
long cellIndexBottomRow = UtilFunctions.cellIndexCalculation(in.getIndexes().getRowIndex(), brlen, in.getValue().getNumRows()-1);
long cellIndexLeftCol = UtilFunctions.cellIndexCalculation(in.getIndexes().getColumnIndex(), bclen, 0);
long cellIndexRightCol = UtilFunctions.cellIndexCalculation(in.getIndexes().getColumnIndex(), bclen, in.getValue().getNumColumns()-1);
long cellIndexOverlapTop = Math.max(cellIndexTopRow, ixrange.rowStart);
long cellIndexOverlapBottom = Math.min(cellIndexBottomRow, ixrange.rowEnd);
long cellIndexOverlapLeft = Math.max(cellIndexLeftCol, ixrange.colStart);
long cellIndexOverlapRight = Math.min(cellIndexRightCol, ixrange.colEnd);
//check if block is outside the indexing range
if(cellIndexOverlapTop>cellIndexOverlapBottom || cellIndexOverlapLeft>cellIndexOverlapRight) {
return;
}
IndexRange tmpRange = new IndexRange(
UtilFunctions.cellInBlockCalculation(cellIndexOverlapTop, brlen),
UtilFunctions.cellInBlockCalculation(cellIndexOverlapBottom, brlen),
UtilFunctions.cellInBlockCalculation(cellIndexOverlapLeft, bclen),
UtilFunctions.cellInBlockCalculation(cellIndexOverlapRight, bclen));
int rowCut=UtilFunctions.cellInBlockCalculation(ixrange.rowStart, brlen);
int colCut=UtilFunctions.cellInBlockCalculation(ixrange.colStart, bclen);
int rowsInLastBlock = (int)((ixrange.rowEnd-ixrange.rowStart+1)%brlen);
if(rowsInLastBlock==0)
rowsInLastBlock=brlen;
int colsInLastBlock = (int)((ixrange.colEnd-ixrange.colStart+1)%bclen);
if(colsInLastBlock==0)
colsInLastBlock=bclen;
long resultBlockIndexTop=UtilFunctions.blockIndexCalculation(cellIndexOverlapTop-ixrange.rowStart+1, brlen);
long resultBlockIndexBottom=UtilFunctions.blockIndexCalculation(cellIndexOverlapBottom-ixrange.rowStart+1, brlen);
long resultBlockIndexLeft=UtilFunctions.blockIndexCalculation(cellIndexOverlapLeft-ixrange.colStart+1, bclen);
long resultBlockIndexRight=UtilFunctions.blockIndexCalculation(cellIndexOverlapRight-ixrange.colStart+1, bclen);
int boundaryRlen = brlen;
int boundaryClen = bclen;
long finalBlockIndexBottom=UtilFunctions.blockIndexCalculation(ixrange.rowEnd-ixrange.rowStart+1, brlen);
long finalBlockIndexRight=UtilFunctions.blockIndexCalculation(ixrange.colEnd-ixrange.colStart+1, bclen);
if(resultBlockIndexBottom==finalBlockIndexBottom)
boundaryRlen=rowsInLastBlock;
if(resultBlockIndexRight==finalBlockIndexRight)
boundaryClen=colsInLastBlock;
//allocate space for the output value
for(long r=resultBlockIndexTop; r<=resultBlockIndexBottom; r++)
for(long c=resultBlockIndexLeft; c<=resultBlockIndexRight; c++)
{
IndexedMatrixValue out=new IndexedMatrixValue(new MatrixIndexes(), new MatrixBlock());
out.getIndexes().setIndexes(r, c);
outlist.add(out);
}
//execute actual slice operation
in.getValue().sliceOperations(outlist, tmpRange, rowCut, colCut, brlen, bclen, boundaryRlen, boundaryClen);
}
}