All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.sysml.runtime.matrix.data.LibMatrixReorg Maven / Gradle / Ivy

There is a newer version: 1.2.0
Show newest version
/*
 * 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.matrix.data;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map.Entry;

import org.apache.sysml.runtime.DMLRuntimeException;
import org.apache.sysml.runtime.DMLUnsupportedOperationException;
import org.apache.sysml.runtime.functionobjects.DiagIndex;
import org.apache.sysml.runtime.functionobjects.RevIndex;
import org.apache.sysml.runtime.functionobjects.SortIndex;
import org.apache.sysml.runtime.functionobjects.SwapIndex;
import org.apache.sysml.runtime.matrix.mapred.IndexedMatrixValue;
import org.apache.sysml.runtime.matrix.operators.ReorgOperator;
import org.apache.sysml.runtime.util.DataConverter;
import org.apache.sysml.runtime.util.SortUtils;
import org.apache.sysml.runtime.util.UtilFunctions;

/**
 * MB:
 * Library for selected matrix reorg operations including special cases
 * and all combinations of dense and sparse representations.
 * 
 * Current list of supported operations:
 *  - reshape, 
 *  - r' (transpose), 
 *  - rdiag (diagV2M/diagM2V), 
 *  - rsort (sorting data/indexes)
 *  - rmempty (remove empty)
 *  - rexpand (outer/table-seq expansion)
 */
public class LibMatrixReorg 
{
	
	public static final boolean SHALLOW_DENSE_VECTOR_TRANSPOSE = true;
	public static final boolean SHALLOW_DENSE_ROWWISE_RESHAPE = true;
	public static final boolean ALLOW_BLOCK_REUSE = false;
	
	private enum ReorgType {
		TRANSPOSE,
		REV,
		DIAG,
		RESHAPE,
		SORT,
		INVALID,
	}
	
	private LibMatrixReorg() {
		//prevent instantiation via private constructor
	}
	
	/////////////////////////
	// public interface    //
	/////////////////////////
	
	/**
	 * 
	 * @param op
	 * @return
	 */
	public static boolean isSupportedReorgOperator( ReorgOperator op )
	{
		return (getReorgType(op) != ReorgType.INVALID);
	}

	/**
	 * 
	 * @param in
	 * @param out
	 * @return
	 * @throws DMLRuntimeException
	 */
	public static MatrixBlock reorg( MatrixBlock in, MatrixBlock out, ReorgOperator op ) 
		throws DMLRuntimeException
	{
		ReorgType type = getReorgType(op);
		
		switch( type )
		{
			case TRANSPOSE: 
				return transpose(in, out);
			case REV: 
				return rev(in, out);
			case DIAG:      
				return diag(in, out); 
			case SORT:      
				SortIndex ix = (SortIndex) op.fn;
				return sort(in, out, ix.getCol(), ix.getDecreasing(), ix.getIndexReturn());
			
			default:        
				throw new DMLRuntimeException("Unsupported reorg operator: "+op.fn);
		}
	}
	
	/**
	 * 
	 * @param in
	 * @param out
	 * @return
	 * @throws DMLRuntimeException
	 */
	public static MatrixBlock transpose( MatrixBlock in, MatrixBlock out ) 
		throws DMLRuntimeException
	{
		//Timing time = new Timing(true);
	
		//sparse-safe operation
		if( in.isEmptyBlock(false) )
			return out;
		
		if( !in.sparse && !out.sparse )
			transposeDenseToDense( in, out );
		else if( in.sparse && out.sparse )
			transposeSparseToSparse( in, out );
		else if( in.sparse )
			transposeSparseToDense( in, out );
		else
			transposeDenseToSparse( in, out );
		
		//System.out.println("r' ("+in.rlen+", "+in.clen+", "+in.sparse+", "+out.sparse+") in "+time.stop()+" ms.");
		
		return out;
	}
	
	/**
	 * 
	 * @param in
	 * @param out
	 * @return
	 * @throws DMLRuntimeException
	 */
	public static MatrixBlock rev( MatrixBlock in, MatrixBlock out ) 
		throws DMLRuntimeException
	{
		//Timing time = new Timing(true);
	
		//sparse-safe operation
		if( in.isEmptyBlock(false) )
			return out;
		
		//special case: row vector
		if( in.rlen == 1 ) {
			out.copy(in);
			return out;
		}
		
		if( in.sparse )
			reverseSparse( in, out );
		else
			reverseDense( in, out );
		
		//System.out.println("rev ("+in.rlen+", "+in.clen+", "+in.sparse+") in "+time.stop()+" ms.");

		return out;
	}
	
	/**
	 * 
	 * @param in
	 * @param rows1
	 * @param brlen
	 * @param out
	 * @throws DMLRuntimeException 
	 * @throws DMLUnsupportedOperationException 
	 */
	public static void rev( IndexedMatrixValue in, long rlen, int brlen, ArrayList out ) 
		throws DMLRuntimeException, DMLUnsupportedOperationException
	{
		//input block reverse 
		MatrixIndexes inix = in.getIndexes();
		MatrixBlock inblk = (MatrixBlock) in.getValue(); 
		MatrixBlock tmpblk = rev(inblk, new MatrixBlock(inblk.getNumRows(), inblk.getNumColumns(), inblk.isInSparseFormat()));
		
		//split and expand block if necessary (at most 2 blocks)
		if( rlen % brlen == 0 ) //special case: aligned blocks 
		{
			int nrblks = (int)Math.ceil((double)rlen/brlen);
			out.add(new IndexedMatrixValue(
					new MatrixIndexes(nrblks-inix.getRowIndex()+1, inix.getColumnIndex()), tmpblk));
		}
		else //general case: unaligned blocks
		{
			//compute target positions and sizes
			long pos1 = rlen - UtilFunctions.computeCellIndex(inix.getRowIndex(), brlen, tmpblk.getNumRows()-1) + 1;
			long pos2 = pos1 + tmpblk.getNumRows() - 1;
			int ipos1 = UtilFunctions.computeCellInBlock(pos1, brlen);
			int iposCut = tmpblk.getNumRows() - ipos1 - 1;
			int blkix1 = (int)UtilFunctions.computeBlockIndex(pos1, brlen);
			int blkix2 = (int)UtilFunctions.computeBlockIndex(pos2, brlen);
			int blklen1 = (int)UtilFunctions.computeBlockSize(rlen, blkix1, brlen);
			int blklen2 = (int)UtilFunctions.computeBlockSize(rlen, blkix2, brlen);
			
			//slice first block
			MatrixIndexes outix1 = new MatrixIndexes(blkix1, inix.getColumnIndex());
			MatrixBlock outblk1 = new MatrixBlock(blklen1, inblk.getNumColumns(), inblk.isInSparseFormat());
			MatrixBlock tmp1 = tmpblk.sliceOperations(0, iposCut, 0, tmpblk.getNumColumns()-1, new MatrixBlock());
			outblk1.leftIndexingOperations(tmp1, ipos1, outblk1.getNumRows()-1, 0, tmpblk.getNumColumns()-1, outblk1, true);
			out.add(new IndexedMatrixValue(outix1, outblk1));
			
			//slice second block (if necessary)
			if( blkix1 != blkix2 ) {
				MatrixIndexes outix2 = new MatrixIndexes(blkix2, inix.getColumnIndex());
				MatrixBlock outblk2 = new MatrixBlock(blklen2, inblk.getNumColumns(), inblk.isInSparseFormat());
				MatrixBlock tmp2 = tmpblk.sliceOperations(iposCut+1, tmpblk.getNumRows()-1, 0, tmpblk.getNumColumns()-1, new MatrixBlock());
				outblk2.leftIndexingOperations(tmp2, 0, tmp2.getNumRows()-1, 0, tmpblk.getNumColumns()-1, outblk2, true);
				out.add(new IndexedMatrixValue(outix2, outblk2));		
			}
		}
	}
	
	/**
	 * 
	 * @param in
	 * @param out
	 * @return
	 * @throws DMLRuntimeException
	 */
	public static MatrixBlock diag( MatrixBlock in, MatrixBlock out ) 
		throws DMLRuntimeException
	{
		//Timing time = new Timing(true);
		
		//sparse-safe operation
		if( in.isEmptyBlock(false) )
			return out;
		
		int rlen = in.rlen;
		int clen = in.clen;
		
		if( clen == 1 ){ //diagV2M
			diagV2M( in, out );
			out.setDiag();
		}
		else if ( rlen == clen ) //diagM2V
			diagM2V( in, out );
		else
			throw new DMLRuntimeException("Reorg diagM2V requires squared block input. ("+rlen+", "+clen+")");
		
		//System.out.println("rdiag ("+in.rlen+", "+in.clen+", "+in.sparse+", "+out.sparse+") in "+time.stop()+" ms.");
		
		return out;
	}
	
	/**
	 * 
	 * 
	 * @param in
	 * @param out
	 * @param by
	 * @param desc
	 * @param ixret
	 * @return
	 * @throws DMLRuntimeException 
	 */
	public static MatrixBlock sort(MatrixBlock in, MatrixBlock out, int by, boolean desc, boolean ixret) 
		throws DMLRuntimeException
	{
		//meta data gathering and preparation
		boolean sparse = in.isInSparseFormat();
		int rlen = in.rlen;
		int clen = in.clen;
		out.sparse = (in.sparse && !ixret);
		out.nonZeros = ixret ? rlen : in.nonZeros;
		
		//step 1: error handling
		if( by <= 0 || clen < by )
			throw new DMLRuntimeException("Sort configuration issue: non-existing orderby column: "+by+" ("+rlen+"x"+clen+" input).");
		
		//step 2: empty block / special case handling
		if( !ixret ) //SORT DATA
		{
			if( in.isEmptyBlock(false) ) //EMPTY INPUT BLOCK
				return out;
			
			if( !sparse && clen == 1 ) { //DENSE COLUMN VECTOR
				//in-place quicksort, unstable (no indexes needed)
				out.copy( in ); //dense
				Arrays.sort(out.denseBlock);
				if( desc )
					sortReverseDense(out);
				return out;
			}
		}
		else //SORT INDEX
		{
			if( in.isEmptyBlock(false) ) { //EMPTY INPUT BLOCK
				out.allocateDenseBlock(false);
				for( int i=0; i0 ) {
				Arrays.sort(vix, i, i+len+1);
				i += len; //skip processed run
			}
		}

		//step 4: create output matrix (guaranteed non-empty, see step 2)
		if( !ixret )
		{
			//copy input data in sorted order into result
			if( !sparse ) //DENSE
			{
				out.allocateDenseBlock(false);
				for( int i=0; i reshape( IndexedMatrixValue in, long rows1, long cols1, int brlen1, int bclen1, 
			                      ArrayList out, long rows2, long cols2, int brlen2, int bclen2, boolean rowwise ) 	
		throws DMLRuntimeException
	{
		//prepare inputs
		MatrixIndexes ixIn = in.getIndexes();
		MatrixBlock mbIn = (MatrixBlock) in.getValue();
		
		//prepare result blocks (no reuse in order to guarantee mem constraints)
		Collection rix = computeAllResultBlockIndexes(ixIn, rows1, cols1, brlen1, bclen1, rows2, cols2, brlen2, bclen2, rowwise);
		HashMap rblk = createAllResultBlocks(rix, mbIn.nonZeros, rows1, cols1, brlen1, bclen1, rows2, cols2, brlen2, bclen2, rowwise, out);
		
		//basic algorithm
		long row_offset = (ixIn.getRowIndex()-1)*brlen1;
		long col_offset = (ixIn.getColumnIndex()-1)*bclen1;
		if( mbIn.sparse )
			reshapeSparse(mbIn, row_offset, col_offset, rblk, rows1, cols1, rows2, cols2, brlen2, bclen2, rowwise);
		else //dense
			reshapeDense(mbIn, row_offset, col_offset, rblk, rows1, cols1, rows2, cols2, brlen2, bclen2, rowwise);

		//prepare output
		out = new ArrayList();
		for( Entry e : rblk.entrySet() )
			out.add(new IndexedMatrixValue(e.getKey(),e.getValue()));
		
		return out;
	}
	
	/**
	 * CP rmempty operation (single input, single output matrix) 
	 * 
	 * @param in
	 * @param out
	 * @param rows
	 * @throws DMLUnsupportedOperationException 
	 * @throws DMLRuntimeException 
	 */
	public static MatrixBlock rmempty(MatrixBlock in, MatrixBlock ret, boolean rows) 
		throws DMLRuntimeException, DMLUnsupportedOperationException
	{
		return rmempty(in, ret, rows, null);
	}
		
	/**
	 * CP rmempty operation (single input, single output matrix) 
	 * 
	 * @param in
	 * @param out
	 * @param rows
	 * @throws DMLUnsupportedOperationException 
	 * @throws DMLRuntimeException 
	 */
	public static MatrixBlock rmempty(MatrixBlock in, MatrixBlock ret, boolean rows, MatrixBlock select) 
		throws DMLRuntimeException, DMLUnsupportedOperationException
	{
		//check for empty inputs 
		//(the semantics of removeEmpty are that for an empty m-by-n matrix, the output 
		//is an empty 1-by-n or m-by-1 matrix because we don't allow matrices with dims 0)
		if( in.isEmptyBlock(false) ) {
			if( rows )
				ret.reset(1, in.clen, in.sparse);
			else //cols
				ret.reset(in.rlen, 1, in.sparse);	
			return ret;
		}
		
		if( rows )
			return removeEmptyRows(in, ret, select);
		else //cols
			return removeEmptyColumns(in, ret, select);
	}

	/**
	 * MR rmempty interface - for rmempty we cannot view blocks independently, and hence,
	 * there are different CP and MR interfaces.
	 * 
	 * @param imv1
	 * @param imv2
	 * @param out
	 * @throws DMLRuntimeException 
	 */
	public static void rmempty(IndexedMatrixValue data, IndexedMatrixValue offset, boolean rmRows, long len, long brlen, long bclen, ArrayList outList) 
		throws DMLRuntimeException
	{
		//sanity check inputs
		if( !(data.getValue() instanceof MatrixBlock && offset.getValue() instanceof MatrixBlock) )
			throw new DMLRuntimeException("Unsupported input data: expected "+MatrixBlock.class.getName()+" but got "+data.getValue().getClass().getName()+" and "+offset.getValue().getClass().getName());
		if(     rmRows && data.getValue().getNumRows()!=offset.getValue().getNumRows() 
			|| !rmRows && data.getValue().getNumColumns()!=offset.getValue().getNumColumns()  ){
			throw new DMLRuntimeException("Dimension mismatch between input data and offsets: ["
					+data.getValue().getNumRows()+"x"+data.getValue().getNumColumns()+" vs "+offset.getValue().getNumRows()+"x"+offset.getValue().getNumColumns());
		}
		
		//compute outputs (at most two output blocks)
		HashMap out = new HashMap();
		MatrixBlock linData = (MatrixBlock) data.getValue();
		MatrixBlock linOffset = (MatrixBlock) offset.getValue();
		MatrixIndexes tmpIx = new MatrixIndexes(-1,-1);
		if( rmRows ) //margin = "rows"
		{
			long rlen = len;
			long clen = linData.getNumColumns();
			
			for( int i=0; i 0 ) //otherwise empty row
				{
					//get single row from source block
					MatrixBlock src = (MatrixBlock) linData.sliceOperations(
							  i, i, 0, (int)(clen-1), new MatrixBlock());
					long brix = (rix-1)/brlen+1;
					long lbrix = (rix-1)%brlen;
					tmpIx.setIndexes(brix, data.getIndexes().getColumnIndex());
					 //create target block if necessary
					if( !out.containsKey(tmpIx) ) {
						IndexedMatrixValue tmpIMV = new IndexedMatrixValue(new MatrixIndexes(),new MatrixBlock());
						tmpIMV.getIndexes().setIndexes(tmpIx);
						((MatrixBlock)tmpIMV.getValue()).reset((int)Math.min(brlen, rlen-((brix-1)*brlen)), (int)clen);
						out.put(tmpIMV.getIndexes(), tmpIMV);
					}
					//put single row into target block
					((MatrixBlock)out.get(tmpIx).getValue()).copy(
							  (int)lbrix, (int)lbrix, 0, (int)clen-1, src, false);
				}
			}
		}
		else //margin = "cols"
		{
			long rlen = linData.getNumRows();
			long clen = len;
			
			for( int i=0; i 0 ) //otherwise empty row
				{
					//get single row from source block
					MatrixBlock src = (MatrixBlock) linData.sliceOperations(
							  0, (int)(rlen-1), i, i, new MatrixBlock());
					long bcix = (cix-1)/bclen+1;
					long lbcix = (cix-1)%bclen;
					tmpIx.setIndexes(data.getIndexes().getRowIndex(), bcix);
					 //create target block if necessary
					if( !out.containsKey(tmpIx) ) {
						IndexedMatrixValue tmpIMV = new IndexedMatrixValue(new MatrixIndexes(),new MatrixBlock());
						tmpIMV.getIndexes().setIndexes(tmpIx);
						((MatrixBlock)tmpIMV.getValue()).reset((int)rlen,(int)Math.min(bclen, clen-((bcix-1)*bclen)));
						out.put(tmpIMV.getIndexes(), tmpIMV);
					}
					//put single row into target block
					((MatrixBlock)out.get(tmpIx).getValue()).copy(
							  0, (int)rlen-1, (int)lbcix, (int)lbcix, src, false);
				}
			}
		}
		
		//prepare and return outputs (already in cached values)
		for( IndexedMatrixValue imv : out.values() ){
			((MatrixBlock)imv.getValue()).recomputeNonZeros();
			outList.add(imv);
		}
	}

	/**
	 * CP rexpand operation (single input, single output)
	 * 
	 * @param in
	 * @param ret
	 * @param rows
	 * @return
	 * @throws DMLRuntimeException
	 * @throws DMLUnsupportedOperationException
	 */
	public static MatrixBlock rexpand(MatrixBlock in, MatrixBlock ret, double max, boolean rows, boolean cast, boolean ignore) 
		throws DMLRuntimeException, DMLUnsupportedOperationException
	{
		//prepare parameters
		int lmax = (int)UtilFunctions.toLong(max);
		
		//sanity check for input nnz (incl implicit handling of empty blocks)
		if( !ignore && in.getNonZeros() outList) 
		throws DMLRuntimeException, DMLUnsupportedOperationException
	{
		//prepare parameters
		MatrixIndexes ix = data.getIndexes();
		MatrixBlock in = (MatrixBlock)data.getValue();
		
		//execute rexpand operations incl sanity checks
		//TODO more robust (memory efficient) implementation w/o tmp block
		MatrixBlock tmp = rexpand(in, new MatrixBlock(), max, rows, cast, ignore);
		
		//prepare outputs blocks (slice tmp block into output blocks ) 
		if( rows ) //expanded vertically
		{
			for( int rl=0; rl 0 )
					c[i] = new SparseRow(cnt[i]);
		}
		
		//blocking according to typical L2 cache sizes 
		final int blocksizeI = 128;
		final int blocksizeJ = 128; 
	
		//temporary array for block boundaries (for preventing binary search) 
		int[] ix = new int[blocksizeI];
		
		//blocked execution
		for( int bi = 0; biMATRIX
			{
				//note: cache-friendly on a but not on c
				for( int j=0, aix=0; jVECTOR	
			{
				//note: cache-friendly on c but not on a
				for( int j=0, cix=0; jMATRIX
			{
				//note: cache-friendly on c but not an a
				for( int i=0, cix=0; iVECTOR	
			{
				//note: cache-friendly on a and c; append-only
				if( cRows[0] == null )
					cRows[0] = new SparseRow(estnnz, cols);
				SparseRow crow = cRows[0];
				for( int i=0, cix=0; iMATRIX
			{
				//note: cache-friendly on a but not c; append-only
				//long cix because total cells in sparse can be larger than int
				long cix = 0;
				
				for( int i=0; iMATRIX
			{
				//note: cache-friendly on a but not c; append-only
				SparseRow arow = aRows[0];
				if( arow!=null && !arow.isEmpty() ){
					int alen = arow.size();
					int[] aix = arow.getIndexContainer();
					double[] avals = arow.getValueContainer();
					for( int j=0; jMATRIX
			{
				//note: cache-friendly on a but not c; append&sort, in-place w/o shifts
				for( int i=0; iMATRIX
			//note: cache-friendly on a and c; append-only
			for( int i=0, aix=0; iMATRIX
			{
				//note: cache-friendly on a but not c; append-only
				for( int j=0, aix=0; jMATRIX
			{
				//note: cache-friendly on c but not a; append-only
				for( int i=0; iMATRIX
			//note: cache-friendly on a and c
			for( int i=0, cix=0; iMATRIX
			{
				//note: cache-friendly on a but not c
				SparseRow arow = aRows[0];
				if( arow!=null && !arow.isEmpty() ){
					int alen = arow.size();
					int[] aix = arow.getIndexContainer();
					double[] avals = arow.getValueContainer();	
					for( int j=0; jMATRIX
			{
				//note: cache-friendly on a but not c
				for( int i=0; i computeAllResultBlockIndexes( MatrixIndexes ixin,
            long rows1, long cols1, int brlen1, int bclen1,
            long rows2, long cols2, int brlen2, int bclen2, boolean rowwise )
	{
		HashSet ret = new HashSet();
		
		long nrblk2 = rows2/brlen2 + ((rows2%brlen2!=0)?1:0);
		long ncblk2 = cols2/bclen2 + ((cols2%bclen2!=0)?1:0);
		
		long row_offset = (ixin.getRowIndex()-1)*brlen1;
		long col_offset = (ixin.getColumnIndex()-1)*bclen1;
		
		if( rowwise ){
			for( long i=row_offset; i createAllResultBlocks( Collection rix,
            long nnz, long rows1, long cols1, int brlen1, int bclen1,
            long rows2, long cols2, int brlen2, int bclen2, boolean rowwise, ArrayList reuse )
	{
		HashMap ret = new HashMap();
		long nBlocks = rix.size();
		int count = 0;
		
		//System.out.println("Reuse "+((reuse!=null)?reuse.size():0)+"/"+nBlocks);
		
		for( MatrixIndexes ix : rix )
		{
			//compute indexes
			long bi = ix.getRowIndex();
			long bj = ix.getColumnIndex();
			int lbrlen = (int) Math.min(brlen2, rows2-(bi-1)*brlen2);
			int lbclen = (int) Math.min(bclen2, cols2-(bj-1)*bclen2);
			
			//create result block
			int estnnz = (int) (nnz/nBlocks); //force initialcapacity per row to 1, for many blocks
			boolean sparse = MatrixBlock.evalSparseFormatInMemory(lbrlen, lbclen, estnnz);
			MatrixBlock block = null;
			if( ALLOW_BLOCK_REUSE && reuse!=null && !reuse.isEmpty()) {
				block = (MatrixBlock) reuse.get(count++).getValue();
				block.reset(lbrlen, lbclen, sparse, estnnz);
			}
			else
				block = new MatrixBlock(lbrlen, lbclen, sparse, estnnz); 
			
			//System.out.println("create block ("+bi+","+bj+"): "+lbrlen+" "+lbclen);
			if( lbrlen<1 || lbclen<1 )
				throw new RuntimeException("Computed block dimensions ("+bi+","+bj+" -> "+lbrlen+","+lbclen+") are invalid!");
			
			ret.put(ix, block);
		}
		
		return ret;
	}
	
	/**
	 * 
	 * @param in
	 * @param row_offset
	 * @param col_offset
	 * @param rix
	 * @param rows1
	 * @param cols1
	 * @param rows2
	 * @param cols2
	 * @param brlen2
	 * @param bclen2
	 * @param rowwise
	 */
	private static void reshapeDense( MatrixBlock in, long row_offset, long col_offset, 
			HashMap rix,
            long rows1, long cols1, 
            long rows2, long cols2, int brlen2, int bclen2, boolean rowwise )
    {
		if( in.isEmptyBlock(false) )
			return;
		
		int rlen = in.rlen;
		int clen = in.clen;
		double[] a = in.denseBlock;
		
		//append all values to right blocks
		MatrixIndexes ixtmp = new MatrixIndexes();
		for( int i=0, aix=0; i rix,
            long rows1, long cols1,
            long rows2, long cols2, int brlen2, int bclen2, boolean rowwise )
    {
		if( in.isEmptyBlock(false) )
			return;
		
		int rlen = in.rlen;
		SparseRow[] aRows = in.sparseRows;
		
		//append all values to right blocks
		MatrixIndexes ixtmp = new MatrixIndexes();
		for( int i=0; i  ci/cj: "+ci+"/"+cj);

		ixout.setIndexes(ci, cj);	
		return ixout;
	}

	/**
	 * 
	 * @param in
	 * @param ret
	 * @param select
	 * @return
	 * @throws DMLRuntimeException
	 * @throws DMLUnsupportedOperationException
	 */
	private static MatrixBlock removeEmptyRows(MatrixBlock in, MatrixBlock ret, MatrixBlock select) 
		throws DMLRuntimeException, DMLUnsupportedOperationException 
	{	
		final int m = in.rlen;
		final int n = in.clen;
		boolean[] flags = null; 
		int rlen2 = 0; 
		
		if(select == null) 
		{
			flags = new boolean[ m ]; //false
			//Step 1: scan block and determine non-empty rows
			
			if( in.sparse ) //SPARSE 
			{
				SparseRow[] a = in.sparseRows;
				
				for ( int i=0; i < m; i++ )
					if ( a[i] != null && !a[i].isEmpty() ) {
						flags[i] = true;
						rlen2++;
					}
			}
			else //DENSE
			{
				double[] a = in.denseBlock;
				
				for(int i=0, aix=0; i= 1 && val <= max )
					ret.appendValue((int)(val-1), i+tmpi[j], 1);
			}
			
		}
		
		return ret;
	}
	
	/**
	 * 
	 * @param in
	 * @param ret
	 * @param max
	 * @param cast
	 * @param ignore
	 * @return
	 * @throws DMLRuntimeException 
	 */
	private static MatrixBlock rexpandColumns(MatrixBlock in, MatrixBlock ret, int max, boolean cast, boolean ignore) 
		throws DMLRuntimeException
	{
		//set meta data
		final int rlen = in.rlen;
		final int clen = max;
		final long nnz = in.nonZeros;
		boolean sp = MatrixBlock.evalSparseFormatInMemory(rlen, clen, nnz);
		ret.reset(rlen, clen, sp);
		
		//expand input horizontally (input vector likely dense 
		//but generic implementation for general case)
		for( int i=0; i= 1 && val <= max )
				ret.appendValue(i, (int)(val-1), 1);
		}
		
		return ret;
	}
	
	/**
	 * 
	 * @param in
	 * @param ixin
	 * @param tmp
	 * @param len
	 */
	private static void copyColVector( MatrixBlock in, int ixin, double[] tmp, int[] tmpi, int len)
	{
		//copy value array from input matrix
		if( in.isEmptyBlock(false) ) {
			Arrays.fill(tmp, 0, 0, len);
		}
		else if( in.sparse ){ //SPARSE
			for( int i=0; i 
	{
		private MatrixBlock _mb = null;
		private int _col = -1;
		
		public AscRowComparator( MatrixBlock mb, int col )
		{
			_mb = mb;
			_col = col;
		}

		@Override
		public int compare(Integer arg0, Integer arg1) 
		{			
			double val0 = _mb.quickGetValue(arg0, _col);
			double val1 = _mb.quickGetValue(arg1, _col);			
			return (val0 < val1 ? -1 : (val0 == val1 ? 0 : 1));
		}		
	}
	
	/**
	 * 
	 */
	@SuppressWarnings("unused")
	private static class DescRowComparator implements Comparator 
	{
		private MatrixBlock _mb = null;
		private int _col = -1;
		
		public DescRowComparator( MatrixBlock mb, int col )
		{
			_mb = mb;
			_col = col;
		}

		@Override
		public int compare(Integer arg0, Integer arg1) 
		{			
			double val0 = _mb.quickGetValue(arg0, _col);
			double val1 = _mb.quickGetValue(arg1, _col);	
			return (val0 > val1 ? -1 : (val0 == val1 ? 0 : 1));
		}		
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy