001 /* 002 * Copyright (C) 2010 by Frode Carlsen 003 * 004 * This file is part of the Universal Java Matrix Package (UJMP). 005 * See the NOTICE file distributed with this work for additional 006 * information regarding copyright ownership and licensing. 007 * 008 * UJMP is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU Lesser General Public License as 010 * published by the Free Software Foundation; either version 2 011 * of the License, or (at your option) any later version. 012 * 013 * UJMP is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU Lesser General Public License for more details. 017 * 018 * You should have received a copy of the GNU Lesser General Public 019 * License along with UJMP; if not, write to the 020 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 021 * Boston, MA 02110-1301 USA 022 */ 023 package org.ujmp.core.doublematrix.impl; 024 025 import java.io.Serializable; 026 import java.util.Arrays; 027 028 /** 029 * This class describes the layout (size, order) of a square block of data 030 * within a {@link BlockDenseDoubleMatrix2D block matrix}. 031 * 032 * @author Frode Carlsen, Holger Arndt 033 */ 034 public final class BlockMatrixLayout implements Serializable { 035 private static final long serialVersionUID = 2726685238884065594L; 036 037 /** Enum describing the layout of a block of data. */ 038 public enum BlockOrder { 039 ROWMAJOR, COLUMNMAJOR; 040 041 public BlockOrder transpose() { 042 return (this == ROWMAJOR) ? COLUMNMAJOR : ROWMAJOR; 043 } 044 } 045 046 /** Total size of a block (area). */ 047 protected final int blockArea; 048 049 /** Length of one side (stripe) of a square block. */ 050 public final int blockStripe; 051 052 /** Number of columns of matrix. */ 053 public final int columns; 054 055 /** 056 * Whether this block is laid out in row-major (true) or column-major 057 * (false) order. 058 */ 059 public final BlockOrder blockOrder; 060 061 /** number of blocks in this matrix */ 062 final int numberOfBlocks; 063 064 /** @see #blockOrder */ 065 private final boolean rowMajor; 066 067 /** Number of rows of matrix. */ 068 public final int rows; 069 070 /** threshold for when to stop using square blocks. */ 071 private final int sqbColThreshold, sqbRowThreshold; 072 073 BlockMatrixLayout(final int rows, final int columns, final int blockStripe, 074 final BlockOrder blockOrder) { 075 076 this.blockStripe = blockStripe; 077 078 if (rows <= 0 || columns <= 0 || blockStripe <= 0) { 079 throw new IllegalArgumentException(String.format( 080 "One or more invalid values: rows=%s, columns=%s, blockSize=%s", rows, columns, 081 blockStripe)); 082 } 083 084 this.blockArea = blockStripe * blockStripe; 085 this.rows = rows; 086 this.columns = columns; 087 this.sqbColThreshold = (columns / blockStripe) * blockStripe; 088 this.sqbRowThreshold = (rows / blockStripe) * blockStripe; 089 this.blockOrder = blockOrder; 090 this.rowMajor = (blockOrder == BlockOrder.ROWMAJOR); 091 this.numberOfBlocks = (rows / blockStripe + (rows % blockStripe > 0 ? 1 : 0)) 092 * (columns / blockStripe + (columns % blockStripe > 0 ? 1 : 0)); 093 } 094 095 /** 096 * Get the block which contains the specified row, column 097 * 098 * @param matrix 099 * to get block from 100 * @param row 101 * @param column 102 * @return block containing given row, column 103 */ 104 final double[] getBlock(BlockDenseDoubleMatrix2D matrix, int row, int column) { 105 return matrix.getBlockData(row, column); 106 } 107 108 final int getBlockIndexByColumn(final int lrow, final int lcol, final int numRows, 109 final int numCols) { 110 return rowMajor ? (lcol * numRows + lrow) : (lrow * numCols + lcol); 111 } 112 113 final int getBlockIndexByRow(final int lrow, final int lcol, final int numRows, 114 final int numCols) { 115 return rowMajor ? (lrow * numCols + lcol) : (lcol * numRows + lrow); 116 } 117 118 final int getBlockNumber(int row, int col) { 119 return (col / blockStripe) + (row / blockStripe) 120 * (columns / blockStripe + (columns % blockStripe > 0 ? 1 : 0)); 121 } 122 123 final int getIndexInBlock(int row, int col) { 124 int lrows = getRowsInBlock(row); 125 int lcols = getColumnsInBlock(col); 126 return getBlockIndexByRow(row % blockStripe, col % blockStripe, lrows, lcols); 127 } 128 129 final int getBlockSize(int row, int col) { 130 int lrows = getRowsInBlock(row); 131 int lcols = getColumnsInBlock(col); 132 return lrows * lcols; 133 } 134 135 final double[] toColMajorBlock(BlockDenseDoubleMatrix2D matrix, final int rowStart, int colStart) { 136 double[] block = getBlock(matrix, rowStart, colStart); 137 if (!rowMajor) { 138 return block; 139 } 140 return toColMajorBlock(block, rowStart, colStart); 141 } 142 143 final double[] toColMajorBlock(double[] block, final int rowStart, int colStart) { 144 145 final double[] targetBlock = new double[block.length]; 146 final int lrows = getRowsInBlock(rowStart); 147 final int lcols = getColumnsInBlock(colStart); 148 149 // transpose block, swap cols and rows 150 for (int i = 0; i < lcols; i++) { 151 final int ilrows = i * lrows; 152 for (int j = 0; j < lrows; j++) { 153 targetBlock[ilrows + j] = block[j * lcols + i]; 154 } 155 } 156 157 return targetBlock; 158 } 159 160 int getColumnsInBlock(int col) { 161 return (col >= sqbColThreshold) ? this.columns - this.sqbColThreshold : blockStripe; 162 } 163 164 int getRowsInBlock(final int row) { 165 return (row >= sqbRowThreshold) ? this.rows - this.sqbRowThreshold : blockStripe; 166 } 167 168 final double[] toRowMajorBlock(final BlockDenseDoubleMatrix2D matrix, final int rowStart, 169 int colStart) { 170 final double[] block = getBlock(matrix, rowStart, colStart); 171 if (rowMajor) { 172 return block; 173 } 174 return toRowMajorBlock(block, rowStart, colStart); 175 } 176 177 final double[] toRowMajorBlock(final double[] block, final int rowStart, int colStart) { 178 179 final double[] targetBlock = new double[block.length]; 180 final int lrows = getRowsInBlock(rowStart); 181 final int lcols = getColumnsInBlock(colStart); 182 183 // transpose block 184 for (int i = 0; i < lrows; i++) { 185 final int ilcols = i * lcols; 186 for (int j = 0; j < lcols; j++) { 187 targetBlock[ilcols + j] = block[j * lrows + i]; 188 } 189 } 190 191 return targetBlock; 192 } 193 194 @Override 195 public String toString() { 196 int[] rowLayout = new int[blockStripe]; 197 StringBuilder b = new StringBuilder(blockArea * 4 + 40); 198 String msg = "\n(rows=%s, columns=%s, blockSize=%s):\n"; 199 b.append(String.format(msg, rows, columns, blockStripe)); 200 int rows = blockStripe, cols = blockStripe; 201 202 for (int i = 0; i < rows; i++) { 203 for (int j = 0; j < cols; j++) { 204 rowLayout[j] = getBlockIndexByRow(i, j, rows, cols); 205 } 206 b.append(Arrays.toString(rowLayout)).append("\n"); 207 } 208 209 return b.toString(); 210 } 211 }