/** * (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.instructions.mr; import java.util.ArrayList; import com.ibm.bi.dml.hops.OptimizerUtils; import com.ibm.bi.dml.lops.PMMJ.CacheType; import com.ibm.bi.dml.runtime.DMLRuntimeException; import com.ibm.bi.dml.runtime.DMLUnsupportedOperationException; import com.ibm.bi.dml.runtime.instructions.Instruction; import com.ibm.bi.dml.runtime.instructions.InstructionUtils; import com.ibm.bi.dml.runtime.matrix.data.MatrixBlock; import com.ibm.bi.dml.runtime.matrix.data.MatrixValue; import com.ibm.bi.dml.runtime.matrix.mapred.CachedValueMap; import com.ibm.bi.dml.runtime.matrix.mapred.DistributedCacheInput; import com.ibm.bi.dml.runtime.matrix.mapred.IndexedMatrixValue; import com.ibm.bi.dml.runtime.matrix.mapred.MRBaseForCommonInstructions; import com.ibm.bi.dml.runtime.matrix.operators.Operator; import com.ibm.bi.dml.runtime.util.UtilFunctions; /** * * */ public class PMMJMRInstruction extends BinaryMRInstructionBase implements IDistributedCacheConsumer { private long _rlen = -1; private boolean _outputEmptyBlocks = true; public PMMJMRInstruction(Operator op, byte in1, byte in2, byte out, long nrow, CacheType ctype, boolean outputEmpty, String istr) { super(op, in1, in2, out); instString = istr; _rlen = nrow; _outputEmptyBlocks = outputEmpty; //NOTE: cache type only used by distributed cache input } public long getNumRows() { return _rlen; } public boolean getOutputEmptyBlocks() { return _outputEmptyBlocks; } /** * * @param str * @return * @throws DMLRuntimeException */ public static Instruction parseInstruction ( String str ) throws DMLRuntimeException { InstructionUtils.checkNumFields ( str, 6 ); String[] parts = InstructionUtils.getInstructionParts(str); String opcode = parts[0]; byte in1 = Byte.parseByte(parts[1]); byte in2 = Byte.parseByte(parts[2]); byte out = Byte.parseByte(parts[4]); long nrow = Long.parseLong(parts[3]); CacheType ctype = CacheType.valueOf(parts[5]); boolean outputEmpty = Boolean.parseBoolean(parts[6]); if(!opcode.equalsIgnoreCase("pmm")) throw new DMLRuntimeException("Unknown opcode while parsing an PmmMRInstruction: " + str); return new PMMJMRInstruction(new Operator(true), in1, in2, out, nrow, ctype, outputEmpty, str); } @Override public void processInstruction(Class<? extends MatrixValue> valueClass, CachedValueMap cachedValues, IndexedMatrixValue tempValue, IndexedMatrixValue zeroInput, int blockRowFactor, int blockColFactor) throws DMLUnsupportedOperationException, DMLRuntimeException { //get both matrix inputs (left side always permutation) DistributedCacheInput dcInput = MRBaseForCommonInstructions.dcValues.get(input1); IndexedMatrixValue in2 = cachedValues.getFirst(input2); IndexedMatrixValue in1 = dcInput.getDataBlock((int)in2.getIndexes().getRowIndex(), 1); MatrixBlock mb1 = (MatrixBlock)in1.getValue(); MatrixBlock mb2 = (MatrixBlock)in2.getValue(); //compute target block indexes long minPos = UtilFunctions.toLong( mb1.minNonZero() ); long maxPos = UtilFunctions.toLong( mb1.max() ); long rowIX1 = (minPos-1)/blockRowFactor+1; long rowIX2 = (maxPos-1)/blockRowFactor+1; boolean multipleOuts = (rowIX1 != rowIX2); if( minPos >= 1 ) //at least one row selected { //output sparsity estimate double spmb1 = OptimizerUtils.getSparsity(mb1.getNumRows(), 1, mb1.getNonZeros()); long estnnz = (long) (spmb1 * mb2.getNonZeros()); boolean sparse = MatrixBlock.evalSparseFormatInMemory(blockRowFactor, mb2.getNumColumns(), estnnz); //compute and allocate output blocks IndexedMatrixValue out1 = cachedValues.holdPlace(output, valueClass); IndexedMatrixValue out2 = multipleOuts ? cachedValues.holdPlace(output, valueClass) : null; out1.getValue().reset(blockRowFactor, mb2.getNumColumns(), sparse); if( out2 != null ) out2.getValue().reset(UtilFunctions.computeBlockSize(_rlen, rowIX2, blockRowFactor), mb2.getNumColumns(), sparse); //compute core matrix permutation (assumes that out1 has default blocksize, //hence we do a meta data correction afterwards) mb1.permutationMatrixMultOperations(mb2, out1.getValue(), (out2!=null)?out2.getValue():null); ((MatrixBlock)out1.getValue()).setNumRows(UtilFunctions.computeBlockSize(_rlen, rowIX1, blockRowFactor)); out1.getIndexes().setIndexes(rowIX1, in2.getIndexes().getColumnIndex()); if( out2 != null ) out2.getIndexes().setIndexes(rowIX2, in2.getIndexes().getColumnIndex()); //empty block output filter (enabled by compiler consumer operation is in CP) if( !_outputEmptyBlocks && out1.getValue().isEmpty() && (out2==null || out2.getValue().isEmpty() ) ) { cachedValues.remove(output); } } } @Override //IDistributedCacheConsumer public boolean isDistCacheOnlyIndex( String inst, byte index ) { return (index==input1 && index!=input2); } @Override //IDistributedCacheConsumer public void addDistCacheIndex( String inst, ArrayList<Byte> indexes ) { indexes.add(input1); } }