/*
 * Copyright (C) 2010 by Frode Carlsen
 *
 * This file is part of the Universal Java Matrix Package (UJMP).
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership and licensing.
 *
 * UJMP is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * UJMP is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with UJMP; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 * Boston, MA  02110-1301  USA
 */
package org.ujmp.core.doublematrix.impl;

import java.io.Serializable;
import java.util.Arrays;

/**
 * This class describes the layout (size, order) of a square block of data
 * within a {@link BlockDenseDoubleMatrix2D block matrix}.
 * 
 * @author Frode Carlsen, Holger Arndt
 */
public final class BlockMatrixLayout implements Serializable {
	private static final long serialVersionUID = 2726685238884065594L;

	/** Enum describing the layout of a block of data. */
	public enum BlockOrder {
		ROWMAJOR, COLUMNMAJOR;

		public BlockOrder transpose() {
			return (this == ROWMAJOR) ? COLUMNMAJOR : ROWMAJOR;
		}
	}

	/** Total size of a block (area). */
	protected final int blockArea;

	/** Length of one side (stripe) of a square block. */
	public final int blockStripe;

	/** Number of columns of matrix. */
	public final int columns;

	/**
	 * Whether this block is laid out in row-major (true) or column-major
	 * (false) order.
	 */
	public final BlockOrder blockOrder;

	/** number of blocks in this matrix */
	final int numberOfBlocks;

	/** @see #blockOrder */
	private final boolean rowMajor;

	/** Number of rows of matrix. */
	public final int rows;

	/** threshold for when to stop using square blocks. */
	private final int sqbColThreshold, sqbRowThreshold;

	BlockMatrixLayout(final int rows, final int columns, final int blockStripe,
			final BlockOrder blockOrder) {

		this.blockStripe = blockStripe;

		if (rows <= 0 || columns <= 0 || blockStripe <= 0) {
			throw new IllegalArgumentException(String.format(
					"One or more invalid values: rows=%s, columns=%s, blockSize=%s", rows, columns,
					blockStripe));
		}

		this.blockArea = blockStripe * blockStripe;
		this.rows = rows;
		this.columns = columns;
		this.sqbColThreshold = (columns / blockStripe) * blockStripe;
		this.sqbRowThreshold = (rows / blockStripe) * blockStripe;
		this.blockOrder = blockOrder;
		this.rowMajor = (blockOrder == BlockOrder.ROWMAJOR);
		this.numberOfBlocks = (rows / blockStripe + (rows % blockStripe > 0 ? 1 : 0))
				* (columns / blockStripe + (columns % blockStripe > 0 ? 1 : 0));
	}

	/**
	 * Get the block which contains the specified row, column
	 * 
	 * @param matrix
	 *            to get block from
	 * @param row
	 * @param column
	 * @return block containing given row, column
	 */
	final double[] getBlock(BlockDenseDoubleMatrix2D matrix, int row, int column) {
		return matrix.getBlockData(row, column);
	}

	final int getBlockIndexByColumn(final int lrow, final int lcol, final int numRows,
			final int numCols) {
		return rowMajor ? (lcol * numRows + lrow) : (lrow * numCols + lcol);
	}

	final int getBlockIndexByRow(final int lrow, final int lcol, final int numRows,
			final int numCols) {
		return rowMajor ? (lrow * numCols + lcol) : (lcol * numRows + lrow);
	}

	final int getBlockNumber(int row, int col) {
		return (col / blockStripe) + (row / blockStripe)
				* (columns / blockStripe + (columns % blockStripe > 0 ? 1 : 0));
	}

	final int getIndexInBlock(int row, int col) {
		int lrows = getRowsInBlock(row);
		int lcols = getColumnsInBlock(col);
		return getBlockIndexByRow(row % blockStripe, col % blockStripe, lrows, lcols);
	}

	final int getBlockSize(int row, int col) {
		int lrows = getRowsInBlock(row);
		int lcols = getColumnsInBlock(col);
		return lrows * lcols;
	}

	final double[] toColMajorBlock(BlockDenseDoubleMatrix2D matrix, final int rowStart, int colStart) {
		double[] block = getBlock(matrix, rowStart, colStart);
		if (!rowMajor) {
			return block;
		}
		return toColMajorBlock(block, rowStart, colStart);
	}

	final double[] toColMajorBlock(double[] block, final int rowStart, int colStart) {

		final double[] targetBlock = new double[block.length];
		final int lrows = getRowsInBlock(rowStart);
		final int lcols = getColumnsInBlock(colStart);

		// transpose block, swap cols and rows
		for (int i = 0; i < lcols; i++) {
			final int ilrows = i * lrows;
			for (int j = 0; j < lrows; j++) {
				targetBlock[ilrows + j] = block[j * lcols + i];
			}
		}

		return targetBlock;
	}

	int getColumnsInBlock(int col) {
		return (col >= sqbColThreshold) ? this.columns - this.sqbColThreshold : blockStripe;
	}

	int getRowsInBlock(final int row) {
		return (row >= sqbRowThreshold) ? this.rows - this.sqbRowThreshold : blockStripe;
	}

	final double[] toRowMajorBlock(final BlockDenseDoubleMatrix2D matrix, final int rowStart,
			int colStart) {
		final double[] block = getBlock(matrix, rowStart, colStart);
		if (rowMajor) {
			return block;
		}
		return toRowMajorBlock(block, rowStart, colStart);
	}

	final double[] toRowMajorBlock(final double[] block, final int rowStart, int colStart) {

		final double[] targetBlock = new double[block.length];
		final int lrows = getRowsInBlock(rowStart);
		final int lcols = getColumnsInBlock(colStart);

		// transpose block
		for (int i = 0; i < lrows; i++) {
			final int ilcols = i * lcols;
			for (int j = 0; j < lcols; j++) {
				targetBlock[ilcols + j] = block[j * lrows + i];
			}
		}

		return targetBlock;
	}

	@Override
	public String toString() {
		int[] rowLayout = new int[blockStripe];
		StringBuilder b = new StringBuilder(blockArea * 4 + 40);
		String msg = "\n(rows=%s, columns=%s, blockSize=%s):\n";
		b.append(String.format(msg, rows, columns, blockStripe));
		int rows = blockStripe, cols = blockStripe;

		for (int i = 0; i < rows; i++) {
			for (int j = 0; j < cols; j++) {
				rowLayout[j] = getBlockIndexByRow(i, j, rows, cols);
			}
			b.append(Arrays.toString(rowLayout)).append("\n");
		}

		return b.toString();
	}
}

 

Ads help maintain this website.