/* * 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.runtime.DMLRuntimeException; import org.apache.sysml.runtime.instructions.InstructionUtils; import org.apache.sysml.runtime.matrix.data.MatrixBlock; import org.apache.sysml.runtime.matrix.data.MatrixIndexes; import org.apache.sysml.runtime.matrix.data.MatrixValue; import org.apache.sysml.runtime.matrix.mapred.CachedValueMap; import org.apache.sysml.runtime.matrix.mapred.IndexedMatrixValue; import org.apache.sysml.runtime.matrix.operators.Operator; public class AppendGInstruction extends AppendInstruction { private long _offset = -1; //cols of input1 private long _offset2 = -1; //cols of input2 private long _len = -1; public AppendGInstruction(Operator op, byte in1, byte in2, long offset, long offset2, byte out, boolean cbind, String istr) { super(op, in1, in2, out, cbind, istr); _offset = offset; _offset2 = offset2; _len = _offset + _offset2; } public static AppendGInstruction 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])); long len = (long)(Double.parseDouble(parts[4])); byte out = Byte.parseByte(parts[5]); boolean cbind = Boolean.parseBoolean(parts[6]); return new AppendGInstruction(null, in1, in2, offset, len, out, cbind, str); } @Override public void processInstruction(Class<? extends MatrixValue> valueClass, CachedValueMap cachedValues, IndexedMatrixValue tempValue, IndexedMatrixValue zeroInput, int brlen, int bclen) throws DMLRuntimeException { //setup basic meta data int blen = _cbind ? bclen : brlen; //Step 1: handle first input (forward blocks, change dim of last block) ArrayList<IndexedMatrixValue> blkList1 = cachedValues.get(input1); if( blkList1 != null ) for( IndexedMatrixValue in1 : blkList1 ) { if( in1 == null ) continue; if( _offset%blen == 0 ) { //special case: forward only cachedValues.add(output, in1); } else //general case: change dims and forward { MatrixIndexes tmpix = in1.getIndexes(); MatrixBlock tmpval = (MatrixBlock) in1.getValue(); //always block if( _cbind && _offset/blen+1 == tmpix.getColumnIndex() //border block || !_cbind && _offset/blen+1 == tmpix.getRowIndex()) { IndexedMatrixValue data = cachedValues.holdPlace(output, valueClass); MatrixBlock tmpvalNew = (MatrixBlock)data.getValue(); //always block int lrlen = _cbind ? tmpval.getNumRows() : Math.min(blen, (int)(_len-(tmpix.getRowIndex()-1)*blen)); int lclen = _cbind ? Math.min(blen, (int)(_len-(tmpix.getColumnIndex()-1)*blen)) : tmpval.getNumColumns(); tmpvalNew.reset(lrlen, lclen); tmpvalNew.copy(0, tmpval.getNumRows()-1, 0, tmpval.getNumColumns()-1, tmpval, true); data.getIndexes().setIndexes(tmpix); } else //inner block { cachedValues.add(output, in1); } } } //Step 2: handle second input (split/forward blocks with new index) ArrayList<IndexedMatrixValue> blkList2 = cachedValues.get(input2); if( blkList2 != null ) for( IndexedMatrixValue in2 : blkList2 ) { if( in2 == null ) continue; MatrixIndexes tmpix = in2.getIndexes(); MatrixBlock tmpval = (MatrixBlock) in2.getValue(); //always block if( _offset%bclen == 0 ) //special case no split { IndexedMatrixValue data = cachedValues.holdPlace(output, valueClass); MatrixIndexes ix1 = data.getIndexes(); long rix = _cbind ? tmpix.getRowIndex() : _offset/blen + tmpix.getRowIndex(); long cix = _cbind ? _offset/blen + tmpix.getColumnIndex() : tmpix.getColumnIndex(); ix1.setIndexes(rix, cix); data.set(ix1, in2.getValue()); } else //general case: split and forward { IndexedMatrixValue data1 = cachedValues.holdPlace(output, valueClass); MatrixIndexes ix1 = data1.getIndexes(); MatrixBlock tmpvalNew = (MatrixBlock)data1.getValue(); //always block if( _cbind ) { //first half int cix1 = (int)(_offset/blen + tmpix.getColumnIndex()); int cols1 = Math.min(blen, (int)(_len-(long)(cix1-1)*blen)); ix1.setIndexes( tmpix.getRowIndex(), cix1); tmpvalNew.reset( tmpval.getNumRows(), cols1 ); tmpvalNew.copy(0, tmpval.getNumRows()-1, (int)((_offset+1)%blen)-1, cols1-1, tmpval.sliceOperations(0, tmpval.getNumRows()-1, 0, (int)(cols1-((_offset)%blen)-1), new MatrixBlock()), true); data1.getIndexes().setIndexes(ix1); if( cols1-((_offset)%blen)<tmpval.getNumColumns() ) { //second half (if required) IndexedMatrixValue data2 = cachedValues.holdPlace(output, valueClass); MatrixIndexes ix2 = data2.getIndexes(); MatrixBlock tmpvalNew2 = (MatrixBlock)data2.getValue(); //always block int cix2 = (int)(_offset/blen + 1 + tmpix.getColumnIndex()); int cols2 = Math.min(blen, (int)(_len-(long)(cix2-1)*blen)); ix2.setIndexes( tmpix.getRowIndex(), cix2); tmpvalNew2.reset( tmpval.getNumRows(), cols2 ); tmpvalNew2.copy(0, tmpval.getNumRows()-1, 0, cols2-1, tmpval.sliceOperations(0, tmpval.getNumRows()-1, (int)(cols1-((_offset)%blen)), tmpval.getNumColumns()-1, new MatrixBlock()), true); data2.getIndexes().setIndexes(ix2); } } else //rbind { //first half int rix1 = (int)(_offset/blen + tmpix.getRowIndex()); int rows1 = Math.min(blen, (int)(_len-(long)(rix1-1)*blen)); ix1.setIndexes( rix1, tmpix.getColumnIndex()); tmpvalNew.reset( rows1, tmpval.getNumColumns() ); tmpvalNew.copy((int)((_offset+1)%blen)-1, rows1-1, 0, tmpval.getNumColumns()-1, tmpval.sliceOperations(0,(int)(rows1-((_offset)%blen)-1), 0, tmpval.getNumColumns()-1, new MatrixBlock()), true); data1.getIndexes().setIndexes(ix1); if( rows1-((_offset)%blen)<tmpval.getNumRows() ) { //second half (if required) IndexedMatrixValue data2 = cachedValues.holdPlace(output, valueClass); MatrixIndexes ix2 = data2.getIndexes(); MatrixBlock tmpvalNew2 = (MatrixBlock)data2.getValue(); //always block int rix2 = (int)(_offset/blen + 1 + tmpix.getRowIndex()); int rows2 = Math.min(blen, (int)(_len-(long)(rix2-1)*blen)); ix2.setIndexes(rix2, tmpix.getColumnIndex()); tmpvalNew2.reset( rows2, tmpval.getNumColumns() ); tmpvalNew2.copy(0, rows2-1, 0, tmpval.getNumColumns()-1, tmpval.sliceOperations((int)(rows1-((_offset)%blen)), tmpval.getNumRows()-1, 0, tmpval.getNumColumns()-1, new MatrixBlock()), true); data2.getIndexes().setIndexes(ix2); } } } } } }