/* * 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.runtime.instructions.mr; import java.util.ArrayList; import org.apache.sysml.lops.AppendM.CacheType; import org.apache.sysml.runtime.DMLRuntimeException; import org.apache.sysml.runtime.instructions.InstructionUtils; import org.apache.sysml.runtime.matrix.data.MatrixIndexes; import org.apache.sysml.runtime.matrix.data.MatrixValue; import org.apache.sysml.runtime.matrix.data.OperationsOnMatrixValues; import org.apache.sysml.runtime.matrix.mapred.CachedValueMap; import org.apache.sysml.runtime.matrix.mapred.DistributedCacheInput; import org.apache.sysml.runtime.matrix.mapred.IndexedMatrixValue; import org.apache.sysml.runtime.matrix.mapred.MRBaseForCommonInstructions; import org.apache.sysml.runtime.matrix.operators.Operator; public class AppendMInstruction extends AppendInstruction implements IDistributedCacheConsumer { private long _offset = -1; public AppendMInstruction(Operator op, byte in1, byte in2, long offset, CacheType type, byte out, boolean cbind, String istr) { super(op, in1, in2, out, cbind, istr); _offset = offset; } public static AppendMInstruction parseInstruction ( String str ) throws DMLRuntimeException { String[] parts = InstructionUtils.getInstructionParts ( str ); InstructionUtils.checkNumFields(parts, 6); byte in1 = Byte.parseByte(parts[1]); byte in2 = Byte.parseByte(parts[2]); long offset = (long)(Double.parseDouble(parts[3])); byte out = Byte.parseByte(parts[4]); CacheType type = CacheType.valueOf(parts[5]); boolean cbind = Boolean.parseBoolean(parts[6]); return new AppendMInstruction(null, in1, in2, offset, type, out, cbind, str); } @Override //IDistributedCacheConsumer public boolean isDistCacheOnlyIndex( String inst, byte index ) { return (index==input2 && index!=input1); } @Override //IDistributedCacheConsumer public void addDistCacheIndex( String inst, ArrayList<Byte> indexes ) { indexes.add(input2); } @Override public void processInstruction(Class<? extends MatrixValue> valueClass, CachedValueMap cachedValues, IndexedMatrixValue tempValue, IndexedMatrixValue zeroInput, int blockRowFactor, int blockColFactor) throws DMLRuntimeException { ArrayList<IndexedMatrixValue> blkList = cachedValues.get(input1); if( blkList == null ) return; //right now this only deals with appending matrix with number of column <= blockColFactor for(IndexedMatrixValue in1 : blkList) { if(in1 == null) continue; //check for boundary block int blen = _cbind ? blockColFactor : blockRowFactor; long lastBlockColIndex = (long)Math.ceil((double)_offset/blen); //case 1: pass through of non-boundary blocks MatrixIndexes ix = in1.getIndexes(); if( (_cbind?ix.getColumnIndex():ix.getRowIndex())!=lastBlockColIndex ) { cachedValues.add(output, in1); } //case 2: pass through full input block and rhs block else if( _cbind && in1.getValue().getNumColumns() == blen || !_cbind && in1.getValue().getNumRows() == blen ) { //output lhs block cachedValues.add(output, in1); //output shallow copy of rhs block DistributedCacheInput dcInput = MRBaseForCommonInstructions.dcValues.get(input2); if( _cbind ) { cachedValues.add(output, new IndexedMatrixValue( new MatrixIndexes(ix.getRowIndex(), ix.getColumnIndex()+1), dcInput.getDataBlock((int)ix.getRowIndex(), 1).getValue())); } else { cachedValues.add(output, new IndexedMatrixValue( new MatrixIndexes(ix.getRowIndex()+1, ix.getColumnIndex()), dcInput.getDataBlock(1, (int)ix.getColumnIndex()).getValue())); } } //case 3: append operation on boundary block else { DistributedCacheInput dcInput = MRBaseForCommonInstructions.dcValues.get(input2); //allocate space for the output value ArrayList<IndexedMatrixValue> outlist=new ArrayList<IndexedMatrixValue>(2); IndexedMatrixValue first=cachedValues.holdPlace(output, valueClass); first.getIndexes().setIndexes(ix); outlist.add(first); MatrixValue value_in2 = null; if( _cbind ) { value_in2 = dcInput.getDataBlock((int)ix.getRowIndex(), 1).getValue(); if(in1.getValue().getNumColumns()+value_in2.getNumColumns()>blen) { IndexedMatrixValue second=cachedValues.holdPlace(output, valueClass); second.getIndexes().setIndexes(ix.getRowIndex(), ix.getColumnIndex()+1); outlist.add(second); } } else { //rbind value_in2 = dcInput.getDataBlock(1, (int)ix.getRowIndex()).getValue(); if(in1.getValue().getNumRows()+value_in2.getNumRows()>blen) { IndexedMatrixValue second=cachedValues.holdPlace(output, valueClass); second.getIndexes().setIndexes(ix.getRowIndex()+1, ix.getColumnIndex()); outlist.add(second); } } OperationsOnMatrixValues.performAppend(in1.getValue(), value_in2, outlist, blockRowFactor, blockColFactor, _cbind, true, 0); } } } }