001 /* 002 * Copyright (C) 2008-2010 by Holger Arndt 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 024 package org.ujmp.core.calculation; 025 026 import org.ujmp.core.Coordinates; 027 import org.ujmp.core.Matrix; 028 import org.ujmp.core.doublematrix.DenseDoubleMatrix2D; 029 import org.ujmp.core.exceptions.MatrixException; 030 import org.ujmp.core.interfaces.HasColumnMajorDoubleArray1D; 031 import org.ujmp.core.interfaces.HasRowMajorDoubleArray2D; 032 import org.ujmp.core.matrix.DenseMatrix; 033 import org.ujmp.core.matrix.DenseMatrix2D; 034 import org.ujmp.core.matrix.SparseMatrix; 035 import org.ujmp.core.util.VerifyUtil; 036 import org.ujmp.core.util.concurrent.PFor; 037 038 public class Transpose { 039 040 public static final TransposeCalculation<Matrix, Matrix> MATRIX = new TransposeMatrix(); 041 042 public static final TransposeCalculation<DenseMatrix, DenseMatrix> DENSEMATRIX = new TransposeDenseMatrix(); 043 044 public static final TransposeCalculation<DenseMatrix2D, DenseMatrix2D> DENSEMATRIX2D = new TransposeDenseMatrix2D(); 045 046 public static final TransposeCalculation<DenseDoubleMatrix2D, DenseDoubleMatrix2D> DENSEDOUBLEMATRIX2D = new TransposeDenseDoubleMatrix2D(); 047 048 public static final TransposeCalculation<SparseMatrix, SparseMatrix> SPARSEMATRIX = new TransposeSparseMatrix(); 049 050 } 051 052 class TransposeMatrix implements TransposeCalculation<Matrix, Matrix> { 053 054 public final void calc(final Matrix source, final Matrix target) { 055 if (source == target) { 056 throw new MatrixException("cannot transpose into original matrix"); 057 } 058 if (source instanceof DenseDoubleMatrix2D && target instanceof DenseDoubleMatrix2D) { 059 Transpose.DENSEDOUBLEMATRIX2D.calc((DenseDoubleMatrix2D) source, 060 (DenseDoubleMatrix2D) target); 061 } else if (source instanceof DenseMatrix2D && target instanceof DenseMatrix2D) { 062 Transpose.DENSEMATRIX2D.calc((DenseMatrix2D) source, (DenseMatrix2D) target); 063 } else if (source instanceof DenseMatrix && target instanceof DenseMatrix) { 064 Transpose.DENSEMATRIX.calc((DenseMatrix) source, (DenseMatrix) target); 065 } else if (source instanceof SparseMatrix && target instanceof SparseMatrix) { 066 Transpose.SPARSEMATRIX.calc((SparseMatrix) source, (SparseMatrix) target); 067 } else { 068 VerifyUtil.assert2D(source); 069 VerifyUtil.assert2D(target); 070 VerifyUtil.assertEquals(source.getRowCount(), target.getColumnCount(), 071 "matrices have wrong size"); 072 VerifyUtil.assertEquals(source.getColumnCount(), target.getRowCount(), 073 "matrices have wrong size"); 074 for (long[] c : source.allCoordinates()) { 075 Object o = source.getAsObject(c); 076 target.setAsObject(o, Coordinates.transpose(c)); 077 } 078 } 079 } 080 }; 081 082 class TransposeDenseMatrix implements TransposeCalculation<DenseMatrix, DenseMatrix> { 083 084 public final void calc(final DenseMatrix source, final DenseMatrix target) { 085 if (source instanceof DenseMatrix2D && target instanceof DenseMatrix2D) { 086 Transpose.DENSEMATRIX2D.calc((DenseMatrix2D) source, (DenseMatrix2D) target); 087 } else { 088 VerifyUtil.assert2D(source); 089 VerifyUtil.assert2D(target); 090 VerifyUtil.assertEquals(source.getRowCount(), target.getColumnCount(), 091 "matrices have wrong size"); 092 VerifyUtil.assertEquals(source.getColumnCount(), target.getRowCount(), 093 "matrices have wrong size"); 094 for (long[] c : source.allCoordinates()) { 095 Object o = source.getAsObject(c); 096 target.setAsObject(o, Coordinates.transpose(c)); 097 } 098 } 099 } 100 }; 101 102 class TransposeSparseMatrix implements TransposeCalculation<SparseMatrix, SparseMatrix> { 103 104 public final void calc(final SparseMatrix source, final SparseMatrix target) { 105 VerifyUtil.assert2D(source); 106 VerifyUtil.assert2D(target); 107 VerifyUtil.assertEquals(source.getRowCount(), target.getColumnCount(), 108 "matrices have wrong size"); 109 VerifyUtil.assertEquals(source.getColumnCount(), target.getRowCount(), 110 "matrices have wrong size"); 111 for (long[] c : source.availableCoordinates()) { 112 Object o = source.getAsObject(c); 113 target.setAsObject(o, Coordinates.transpose(c)); 114 } 115 } 116 }; 117 118 class TransposeDenseMatrix2D implements TransposeCalculation<DenseMatrix2D, DenseMatrix2D> { 119 120 public final void calc(final DenseMatrix2D source, final DenseMatrix2D target) { 121 if (source instanceof DenseDoubleMatrix2D && target instanceof DenseDoubleMatrix2D) { 122 Transpose.DENSEDOUBLEMATRIX2D.calc((DenseDoubleMatrix2D) source, 123 (DenseDoubleMatrix2D) target); 124 } else { 125 VerifyUtil.assert2D(source); 126 VerifyUtil.assert2D(target); 127 VerifyUtil.assertEquals(source.getRowCount(), target.getColumnCount(), 128 "matrices have wrong size"); 129 VerifyUtil.assertEquals(source.getColumnCount(), target.getRowCount(), 130 "matrices have wrong size"); 131 for (int r = (int) source.getRowCount(); --r != -1;) { 132 for (int c = (int) source.getColumnCount(); --c != -1;) { 133 Object o = source.getAsObject(r, c); 134 target.setAsObject(o, c, r); 135 } 136 } 137 } 138 } 139 }; 140 141 class TransposeDenseDoubleMatrix2D implements 142 TransposeCalculation<DenseDoubleMatrix2D, DenseDoubleMatrix2D> { 143 144 public final void calc(final DenseDoubleMatrix2D source, final DenseDoubleMatrix2D target) { 145 if (source instanceof HasColumnMajorDoubleArray1D 146 && target instanceof HasColumnMajorDoubleArray1D) { 147 calc((int) source.getRowCount(), (int) source.getColumnCount(), 148 ((HasColumnMajorDoubleArray1D) source).getColumnMajorDoubleArray1D(), 149 ((HasColumnMajorDoubleArray1D) target).getColumnMajorDoubleArray1D()); 150 } else if (source instanceof HasRowMajorDoubleArray2D 151 && target instanceof HasRowMajorDoubleArray2D) { 152 calc(((HasRowMajorDoubleArray2D) source).getRowMajorDoubleArray2D(), 153 ((HasRowMajorDoubleArray2D) target).getRowMajorDoubleArray2D()); 154 } else { 155 VerifyUtil.assert2D(source); 156 VerifyUtil.assert2D(target); 157 VerifyUtil.assertEquals(source.getRowCount(), target.getColumnCount(), 158 "matrices have wrong size"); 159 VerifyUtil.assertEquals(source.getColumnCount(), target.getRowCount(), 160 "matrices have wrong size"); 161 for (int r = (int) source.getRowCount(); --r != -1;) { 162 for (int c = (int) source.getColumnCount(); --c != -1;) { 163 target.setDouble(source.getDouble(r, c), c, r); 164 } 165 } 166 } 167 } 168 169 private final void calc(final double[][] source, final double[][] target) { 170 VerifyUtil.assertNotNull(source, "source cannot be null"); 171 VerifyUtil.assertNotNull(target, "target cannot be null"); 172 VerifyUtil.assertNotNull(source[0], "source must be 2d"); 173 VerifyUtil.assertNotNull(target[0], "target must be 2d"); 174 VerifyUtil.assertEquals(source.length, target.length, "matrices have wrong size"); 175 VerifyUtil.assertEquals(source[0].length, target[0].length, "matrices have wrong size"); 176 final int retcols = source.length; 177 final int retrows = source[0].length; 178 if (retcols * retrows > 10000) { 179 new PFor(0, retrows - 1) { 180 @Override 181 public void step(int i) { 182 for (int c = 0; c < retcols; c++) { 183 target[i][c] = source[c][i]; 184 } 185 } 186 }; 187 } else { 188 for (int r = 0; r < retrows; r++) { 189 for (int c = 0; c < retcols; c++) { 190 target[r][c] = source[c][r]; 191 } 192 } 193 } 194 } 195 196 private final void calc(final int rows, final int cols, final double[] source, 197 final double[] target) { 198 VerifyUtil.assertNotNull(source, "source cannot be null"); 199 VerifyUtil.assertNotNull(target, "target cannot be null"); 200 VerifyUtil.assertEquals(source.length, target.length, "matrices have different sizes"); 201 if (source.length > 10000) { 202 new PFor(0, rows - 1) { 203 204 @Override 205 public void step(int i) { 206 for (int r = 0; r < cols; r++) { 207 target[i * cols + r] = source[r * rows + i]; 208 } 209 } 210 }; 211 } else { 212 for (int c = 0; c < rows; c++) { 213 for (int r = 0; r < cols; r++) { 214 target[c * cols + r] = source[r * rows + c]; 215 } 216 } 217 } 218 } 219 };