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    };