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 TimesScalar {
041            public static final TimesScalarCalculation<Matrix, Matrix> MATRIX = new TimesScalarMatrix();
042    
043            public static final TimesScalarCalculation<DenseMatrix, DenseMatrix> DENSEMATRIX = new TimesScalarDenseMatrix();
044    
045            public static final TimesScalarCalculation<DenseMatrix2D, DenseMatrix2D> DENSEMATRIX2D = new TimesScalarDenseMatrix2D();
046    
047            public static final TimesScalarCalculation<DenseDoubleMatrix2D, DenseDoubleMatrix2D> DENSEDOUBLEMATRIX2D = new TimesScalarDenseDoubleMatrix2D();
048    
049            public static final TimesScalarCalculation<SparseMatrix, SparseMatrix> SPARSEMATRIX = new TimesScalarSparseMatrix();
050    }
051    
052    class TimesScalarMatrix implements TimesScalarCalculation<Matrix, Matrix> {
053    
054            public final void calc(final Matrix source, final BigDecimal factor, final Matrix target) {
055                    if (source instanceof DenseDoubleMatrix2D && target instanceof DenseDoubleMatrix2D) {
056                            TimesScalar.DENSEDOUBLEMATRIX2D.calc((DenseDoubleMatrix2D) source, factor,
057                                            (DenseDoubleMatrix2D) target);
058                    } else if (source instanceof DenseMatrix2D && target instanceof DenseMatrix2D) {
059                            TimesScalar.DENSEMATRIX2D.calc((DenseMatrix2D) source, factor,
060                                            (DenseDoubleMatrix2D) target);
061                    } else if (source instanceof DenseMatrix && target instanceof DenseMatrix) {
062                            TimesScalar.DENSEMATRIX.calc((DenseMatrix) source, factor, (DenseMatrix) target);
063                    } else if (source instanceof SparseMatrix && target instanceof SparseMatrix) {
064                            TimesScalar.SPARSEMATRIX.calc((SparseMatrix) source, factor, (SparseMatrix) target);
065                    } else {
066                            VerifyUtil.assertSameSize(source, target);
067                            for (long[] c : source.allCoordinates()) {
068                                    BigDecimal value = source.getAsBigDecimal(c);
069                                    BigDecimal result = MathUtil.times(value, factor);
070                                    target.setAsBigDecimal(result, c);
071                            }
072                    }
073            }
074    
075            public final void calc(final Matrix source, final double factor, final Matrix target) {
076                    if (source instanceof DenseMatrix && target instanceof DenseMatrix) {
077                            TimesScalar.DENSEMATRIX.calc((DenseMatrix) source, factor, (DenseMatrix) target);
078                    } else if (source instanceof SparseMatrix && target instanceof SparseMatrix) {
079                            TimesScalar.SPARSEMATRIX.calc((SparseMatrix) source, factor, (SparseMatrix) target);
080                    } else {
081                            calc(source, new BigDecimal(factor, MathUtil.getDefaultMathContext()), target);
082                    }
083            }
084    };
085    
086    class TimesScalarDenseMatrix implements TimesScalarCalculation<DenseMatrix, DenseMatrix> {
087    
088            public final void calc(final DenseMatrix source, final BigDecimal factor,
089                            final DenseMatrix target) {
090                    if (source instanceof DenseMatrix2D && target instanceof DenseMatrix2D) {
091                            TimesScalar.DENSEMATRIX2D.calc((DenseMatrix2D) source, factor, (DenseMatrix2D) target);
092                    } else {
093                            VerifyUtil.assertSameSize(source, target);
094                            for (long[] c : source.allCoordinates()) {
095                                    BigDecimal value = source.getAsBigDecimal(c);
096                                    BigDecimal result = MathUtil.times(value, factor);
097                                    target.setAsBigDecimal(result, c);
098                            }
099                    }
100            }
101    
102            public final void calc(final DenseMatrix source, final double factor, final DenseMatrix target) {
103                    if (source instanceof DenseMatrix2D && target instanceof DenseMatrix2D) {
104                            TimesScalar.DENSEMATRIX2D.calc((DenseMatrix2D) source, factor, (DenseMatrix2D) target);
105                    } else {
106                            calc(source, new BigDecimal(factor, MathUtil.getDefaultMathContext()), target);
107                    }
108            }
109    };
110    
111    class TimesScalarSparseMatrix implements TimesScalarCalculation<SparseMatrix, SparseMatrix> {
112    
113            public final void calc(final SparseMatrix source, final BigDecimal factor,
114                            final SparseMatrix target) {
115                    VerifyUtil.assertSameSize(source, target);
116                    for (long[] c : source.availableCoordinates()) {
117                            BigDecimal value = source.getAsBigDecimal(c);
118                            BigDecimal result = MathUtil.times(value, factor);
119                            target.setAsBigDecimal(result, c);
120                    }
121            }
122    
123            public final void calc(final SparseMatrix source, final double factor, final SparseMatrix target) {
124                    calc(source, new BigDecimal(factor, MathUtil.getDefaultMathContext()), target);
125            }
126    };
127    
128    class TimesScalarDenseMatrix2D implements TimesScalarCalculation<DenseMatrix2D, DenseMatrix2D> {
129    
130            public final void calc(final DenseMatrix2D source, final BigDecimal factor,
131                            final DenseMatrix2D target) {
132                    if (source instanceof DenseDoubleMatrix2D && target instanceof DenseDoubleMatrix2D) {
133                            TimesScalar.DENSEDOUBLEMATRIX2D.calc((DenseDoubleMatrix2D) source, factor,
134                                            (DenseDoubleMatrix2D) target);
135                    } else {
136                            VerifyUtil.assertSameSize(source, target);
137                            for (int r = (int) source.getRowCount(); --r != -1;) {
138                                    for (int c = (int) source.getColumnCount(); --c != -1;) {
139                                            BigDecimal value = source.getAsBigDecimal(r, c);
140                                            BigDecimal result = MathUtil.times(value, factor);
141                                            target.setAsBigDecimal(result, r, c);
142                                    }
143                            }
144                    }
145            }
146    
147            public final void calc(final DenseMatrix2D source, final double factor,
148                            final DenseMatrix2D target) {
149                    if (source instanceof DenseDoubleMatrix2D && target instanceof DenseDoubleMatrix2D) {
150                            TimesScalar.DENSEDOUBLEMATRIX2D.calc((DenseDoubleMatrix2D) source, factor,
151                                            (DenseDoubleMatrix2D) target);
152                    } else {
153                            calc(source, new BigDecimal(factor, MathUtil.getDefaultMathContext()), target);
154                    }
155            }
156    };
157    
158    class TimesScalarDenseDoubleMatrix2D implements
159                    TimesScalarCalculation<DenseDoubleMatrix2D, DenseDoubleMatrix2D> {
160    
161            public final void calc(final DenseDoubleMatrix2D source, final BigDecimal factor,
162                            final DenseDoubleMatrix2D target) {
163                    calc(source, factor.doubleValue(), target);
164            }
165    
166            public final void calc(final DenseDoubleMatrix2D source, final double factor,
167                            final DenseDoubleMatrix2D target) {
168                    if (source instanceof HasColumnMajorDoubleArray1D
169                                    && target instanceof HasColumnMajorDoubleArray1D) {
170                            calc(((HasColumnMajorDoubleArray1D) source).getColumnMajorDoubleArray1D(), factor,
171                                            ((HasColumnMajorDoubleArray1D) target).getColumnMajorDoubleArray1D());
172                    } else if (source instanceof HasRowMajorDoubleArray2D
173                                    && target instanceof HasRowMajorDoubleArray2D) {
174                            calc(((HasRowMajorDoubleArray2D) source).getRowMajorDoubleArray2D(), factor,
175                                            ((HasRowMajorDoubleArray2D) target).getRowMajorDoubleArray2D());
176                    } else {
177                            VerifyUtil.assertSameSize(source, target);
178                            for (int r = (int) source.getRowCount(); --r != -1;) {
179                                    for (int c = (int) source.getColumnCount(); --c != -1;) {
180                                            target.setDouble(factor * source.getDouble(r, c), r, c);
181                                    }
182                            }
183                    }
184            }
185    
186            private final void calc(final double[][] source, final double factor, final double[][] target) {
187                    VerifyUtil.assertSameSize(source, target);
188                    final int rows = source.length;
189                    final int cols = source[0].length;
190                    if (UJMPSettings.getNumberOfThreads() > 1 && rows >= 100 && cols >= 100) {
191                            new PForEquidistant(0, rows - 1) {
192    
193                                    public void step(int i) {
194                                            double[] tsource = source[i];
195                                            double[] ttarget = target[i];
196                                            for (int c = 0; c < cols; c++) {
197                                                    ttarget[c] = tsource[c] * factor;
198                                            }
199                                    }
200                            };
201                    } else {
202                            double[] tsource = null;
203                            double[] ttarget = null;
204                            for (int r = 0; r < rows; r++) {
205                                    tsource = source[r];
206                                    ttarget = target[r];
207                                    for (int c = 0; c < cols; c++) {
208                                            ttarget[c] = tsource[c] * factor;
209                                    }
210                            }
211                    }
212            }
213    
214            private final void calc(final double[] source, final double factor, final double[] target) {
215                    VerifyUtil.assertSameSize(source, target);
216                    final int length = source.length;
217                    for (int i = 0; i < length; i++) {
218                            target[i] = source[i] * factor;
219                    }
220            }
221    };