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