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 java.math.BigDecimal;
027    
028    import org.ujmp.core.Matrix;
029    import org.ujmp.core.doublematrix.DenseDoubleMatrix2D;
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.MathUtil;
036    import org.ujmp.core.util.UJMPSettings;
037    import org.ujmp.core.util.VerifyUtil;
038    import org.ujmp.core.util.concurrent.PForEquidistant;
039    
040    public class TimesMatrix {
041            public static final TimesMatrixCalculation<Matrix, Matrix, Matrix> MATRIX = new TimesMatrixMatrix();
042    
043            public static final TimesMatrixCalculation<DenseMatrix, DenseMatrix, DenseMatrix> DENSEMATRIX = new TimesMatrixDenseMatrix();
044    
045            public static final TimesMatrixCalculation<DenseMatrix2D, DenseMatrix2D, DenseMatrix2D> DENSEMATRIX2D = new TimesMatrixDenseMatrix2D();
046    
047            public static final TimesMatrixCalculation<DenseDoubleMatrix2D, DenseDoubleMatrix2D, DenseDoubleMatrix2D> DENSEDOUBLEMATRIX2D = new TimesMatrixDenseDoubleMatrix2D();
048    
049            public static final TimesMatrixCalculation<SparseMatrix, SparseMatrix, SparseMatrix> SPARSEMATRIX = new TimesMatrixSparseMatrix();
050    }
051    
052    class TimesMatrixMatrix implements TimesMatrixCalculation<Matrix, Matrix, Matrix> {
053    
054            public final void calc(final Matrix source1, final Matrix source2, final Matrix target) {
055                    if (source1 instanceof DenseMatrix && source2 instanceof DenseMatrix
056                                    && target instanceof DenseMatrix) {
057                            TimesMatrix.DENSEMATRIX.calc((DenseMatrix) source1, (DenseMatrix) source2,
058                                            (DenseMatrix) target);
059                    } else if (source1 instanceof SparseMatrix && source2 instanceof SparseMatrix
060                                    && target instanceof SparseMatrix) {
061                            TimesMatrix.SPARSEMATRIX.calc((SparseMatrix) source1, (SparseMatrix) source2,
062                                            (SparseMatrix) target);
063                    } else {
064                            VerifyUtil.assertSameSize(source1, source2, target);
065                            for (long[] c : source1.allCoordinates()) {
066                                    BigDecimal v1 = source1.getAsBigDecimal(c);
067                                    BigDecimal v2 = source2.getAsBigDecimal(c);
068                                    BigDecimal result = MathUtil.times(v1, v2);
069                                    target.setAsBigDecimal(result, c);
070                            }
071                    }
072            }
073    };
074    
075    class TimesMatrixDenseMatrix implements
076                    TimesMatrixCalculation<DenseMatrix, DenseMatrix, DenseMatrix> {
077    
078            public final void calc(final DenseMatrix source1, final DenseMatrix source2,
079                            final DenseMatrix target) {
080                    if (source1 instanceof DenseMatrix2D && source2 instanceof DenseMatrix2D
081                                    && target instanceof DenseMatrix2D) {
082                            TimesMatrix.DENSEMATRIX2D.calc((DenseMatrix2D) source1, (DenseMatrix2D) source2,
083                                            (DenseMatrix2D) target);
084                    } else {
085                            VerifyUtil.assertSameSize(source1, source2, target);
086                            for (long[] c : source1.allCoordinates()) {
087                                    BigDecimal v1 = source1.getAsBigDecimal(c);
088                                    BigDecimal v2 = source2.getAsBigDecimal(c);
089                                    BigDecimal result = MathUtil.times(v1, v2);
090                                    target.setAsBigDecimal(result, c);
091                            }
092                    }
093            }
094    };
095    
096    class TimesMatrixSparseMatrix implements
097                    TimesMatrixCalculation<SparseMatrix, SparseMatrix, SparseMatrix> {
098    
099            public void calc(final SparseMatrix source1, final SparseMatrix source2,
100                            final SparseMatrix target) {
101                    VerifyUtil.assertSameSize(source1, source2, target);
102                    // copy all elements in source1 to target
103                    for (long[] c : source1.availableCoordinates()) {
104                            BigDecimal v1 = source1.getAsBigDecimal(c);
105                            BigDecimal v2 = source2.getAsBigDecimal(c);
106                            target.setAsBigDecimal(MathUtil.times(v1, v2), c);
107                    }
108            }
109    
110    };
111    
112    class TimesMatrixDenseMatrix2D implements
113                    TimesMatrixCalculation<DenseMatrix2D, DenseMatrix2D, DenseMatrix2D> {
114    
115            public void calc(final DenseMatrix2D source1, final DenseMatrix2D source2,
116                            final DenseMatrix2D target) {
117                    if (source1 instanceof DenseDoubleMatrix2D && source2 instanceof DenseDoubleMatrix2D
118                                    && target instanceof DenseDoubleMatrix2D) {
119                            TimesMatrix.DENSEDOUBLEMATRIX2D.calc((DenseDoubleMatrix2D) source1,
120                                            (DenseDoubleMatrix2D) source2, (DenseDoubleMatrix2D) target);
121                    } else {
122                            VerifyUtil.assertSameSize(source1, source2, target);
123                            for (int r = (int) source1.getRowCount(); --r != -1;) {
124                                    for (int c = (int) source1.getColumnCount(); --c != -1;) {
125                                            BigDecimal v1 = source1.getAsBigDecimal(r, c);
126                                            BigDecimal v2 = source2.getAsBigDecimal(r, c);
127                                            BigDecimal result = MathUtil.times(v1, v2);
128                                            target.setAsBigDecimal(result, r, c);
129                                    }
130                            }
131                    }
132            }
133    };
134    
135    class TimesMatrixDenseDoubleMatrix2D implements
136                    TimesMatrixCalculation<DenseDoubleMatrix2D, DenseDoubleMatrix2D, DenseDoubleMatrix2D> {
137    
138            public void calc(final DenseDoubleMatrix2D source1, final DenseDoubleMatrix2D source2,
139                            final DenseDoubleMatrix2D target) {
140                    if (source1 instanceof HasColumnMajorDoubleArray1D
141                                    && source2 instanceof HasColumnMajorDoubleArray1D
142                                    && target instanceof HasColumnMajorDoubleArray1D) {
143                            calc(((HasColumnMajorDoubleArray1D) source1).getColumnMajorDoubleArray1D(),
144                                            ((HasColumnMajorDoubleArray1D) source2).getColumnMajorDoubleArray1D(),
145                                            ((HasColumnMajorDoubleArray1D) target).getColumnMajorDoubleArray1D());
146                    } else if (source1 instanceof HasRowMajorDoubleArray2D
147                                    && source2 instanceof HasRowMajorDoubleArray2D
148                                    && target instanceof HasRowMajorDoubleArray2D) {
149                            calc(((HasRowMajorDoubleArray2D) source1).getRowMajorDoubleArray2D(),
150                                            ((HasRowMajorDoubleArray2D) source2).getRowMajorDoubleArray2D(),
151                                            ((HasRowMajorDoubleArray2D) target).getRowMajorDoubleArray2D());
152                    } else {
153                            VerifyUtil.assertSameSize(source1, source2, target);
154                            for (int r = (int) source1.getRowCount(); --r != -1;) {
155                                    for (int c = (int) source1.getColumnCount(); --c != -1;) {
156                                            target.setDouble(source1.getDouble(r, c) * source2.getDouble(r, c), r, c);
157                                    }
158                            }
159                    }
160            }
161    
162            private final void calc(final double[][] source1, final double[][] source2,
163                            final double[][] target) {
164                    VerifyUtil.assertSameSize(source1, source2, target);
165                    if (UJMPSettings.getNumberOfThreads() > 1 && source1.length >= 100
166                                    && source1[0].length >= 100) {
167                            new PForEquidistant(0, source1.length - 1) {
168                                    public void step(int i) {
169                                            double[] v1 = source1[i];
170                                            double[] v2 = source2[i];
171                                            double[] t = target[i];
172                                            for (int c = source1[0].length; --c != -1;) {
173                                                    t[c] = v1[c] * v2[c];
174                                            }
175                                    }
176                            };
177                    } else {
178                            double[] v1 = null;
179                            double[] v2 = null;
180                            double[] t = null;
181                            for (int r = source1.length; --r != -1;) {
182                                    v1 = source1[r];
183                                    v2 = source2[r];
184                                    t = target[r];
185                                    for (int c = source1[0].length; --c != -1;) {
186                                            t[c] = v1[c] * v2[c];
187                                    }
188                            }
189                    }
190            }
191    
192            private final void calc(final double[] source1, final double[] source2, final double[] target) {
193                    VerifyUtil.assertSameSize(source1, source2, target);
194                    final int length = source1.length;
195                    for (int i = 0; i < length; i++) {
196                            target[i] = source1[i] * source2[i];
197                    }
198            }
199    
200    };