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.jscience;
025    
026    import java.io.IOException;
027    import java.io.ObjectInputStream;
028    import java.io.ObjectOutputStream;
029    
030    import javolution.util.FastTable;
031    import javolution.util.Index;
032    
033    import org.jscience.mathematics.number.Float64;
034    import org.jscience.mathematics.vector.DenseMatrix;
035    import org.jscience.mathematics.vector.Float64Matrix;
036    import org.jscience.mathematics.vector.Float64Vector;
037    import org.jscience.mathematics.vector.LUDecomposition;
038    import org.jscience.mathematics.vector.SparseMatrix;
039    import org.ujmp.core.Coordinates;
040    import org.ujmp.core.Matrix;
041    import org.ujmp.core.doublematrix.stub.AbstractDenseDoubleMatrix2D;
042    import org.ujmp.core.exceptions.MatrixException;
043    import org.ujmp.core.interfaces.Wrapper;
044    import org.ujmp.core.util.ReflectionUtil;
045    
046    public class JScienceDenseDoubleMatrix2D extends AbstractDenseDoubleMatrix2D
047                    implements Wrapper<Float64Matrix> {
048            private static final long serialVersionUID = -7874694468839411484L;
049    
050            private transient Float64Matrix matrix = null;
051    
052            private Boolean transposed = false;
053    
054            private transient FastTable<Float64Vector> rows = null;
055    
056            public JScienceDenseDoubleMatrix2D(long... size) {
057                    if (Coordinates.product(size) != 0) {
058                            this.matrix = Float64Matrix
059                                            .valueOf(new double[(int) size[ROW]][(int) size[COLUMN]]);
060                    }
061            }
062    
063            public JScienceDenseDoubleMatrix2D(Float64Matrix matrix) {
064                    this.matrix = matrix;
065            }
066    
067            public JScienceDenseDoubleMatrix2D(double[][] values) {
068                    this.matrix = Float64Matrix.valueOf(values);
069            }
070    
071            public JScienceDenseDoubleMatrix2D(double[] values) {
072                    this.matrix = Float64Matrix.valueOf(Float64Vector.valueOf(values));
073            }
074    
075            public JScienceDenseDoubleMatrix2D(Matrix matrix) throws MatrixException {
076                    this.matrix = Float64Matrix.valueOf(matrix.toDoubleArray());
077            }
078    
079            public JScienceDenseDoubleMatrix2D(DenseMatrix<Float64> matrix) {
080                    this.matrix = Float64Matrix.valueOf(matrix);
081            }
082    
083            public JScienceDenseDoubleMatrix2D(SparseMatrix<Float64> matrix) {
084                    this.matrix = Float64Matrix.valueOf(matrix);
085            }
086    
087            public double getDouble(long row, long column) {
088                    return matrix.get((int) row, (int) column).doubleValue();
089            }
090    
091            public double getDouble(int row, int column) {
092                    return matrix.get(row, column).doubleValue();
093            }
094    
095            public long[] getSize() {
096                    return matrix == null ? Coordinates.ZERO2D : new long[] {
097                                    matrix.getNumberOfRows(), matrix.getNumberOfColumns() };
098            }
099    
100            public void setDouble(double value, long row, long column) {
101                    if (getTransposed()) {
102                            Float64Vector f = getRowsTable().get((int) column);
103                            double[] data = (double[]) ReflectionUtil.extractPrivateField(f,
104                                            "_values");
105                            data[(int) row] = value;
106                    } else {
107                            Float64Vector f = getRowsTable().get((int) row);
108                            double[] data = (double[]) ReflectionUtil.extractPrivateField(f,
109                                            "_values");
110                            data[(int) column] = value;
111                    }
112            }
113    
114            private boolean getTransposed() {
115                    if (transposed == null) {
116                            transposed = (Boolean) ReflectionUtil.extractPrivateField(
117                                            Float64Matrix.class, matrix, "_transposed");
118                    }
119                    return transposed;
120            }
121    
122            @SuppressWarnings("unchecked")
123            private FastTable<Float64Vector> getRowsTable() {
124                    if (rows == null) {
125                            rows = (FastTable<Float64Vector>) ReflectionUtil
126                                            .extractPrivateField(Float64Matrix.class, matrix, "_rows");
127                    }
128                    return rows;
129            }
130    
131            public void setDouble(double value, int row, int column) {
132                    if (getTransposed()) {
133                            Float64Vector f = getRowsTable().get(column);
134                            double[] data = (double[]) ReflectionUtil.extractPrivateField(
135                                            Float64Vector.class, f, "_values");
136                            data[row] = value;
137                    } else {
138                            Float64Vector f = getRowsTable().get(row);
139                            double[] data = (double[]) ReflectionUtil.extractPrivateField(
140                                            Float64Vector.class, f, "_values");
141                            data[column] = value;
142                    }
143            }
144    
145            public Matrix mtimes(Matrix that) {
146                    if (that instanceof JScienceDenseDoubleMatrix2D) {
147                            return new JScienceDenseDoubleMatrix2D(matrix
148                                            .times(((JScienceDenseDoubleMatrix2D) that).matrix));
149                    } else {
150                            return super.mtimes(that);
151                    }
152            }
153    
154            public Matrix plus(Matrix that) {
155                    if (that instanceof JScienceDenseDoubleMatrix2D) {
156                            return new JScienceDenseDoubleMatrix2D(matrix
157                                            .plus(((JScienceDenseDoubleMatrix2D) that).matrix));
158                    } else {
159                            return super.plus(that);
160                    }
161            }
162    
163            public Matrix minus(Matrix that) {
164                    if (that instanceof JScienceDenseDoubleMatrix2D) {
165                            return new JScienceDenseDoubleMatrix2D(matrix
166                                            .minus(((JScienceDenseDoubleMatrix2D) that).matrix));
167                    } else {
168                            return super.minus(that);
169                    }
170            }
171    
172            public Matrix times(double value) {
173                    return new JScienceDenseDoubleMatrix2D(matrix.times(Float64
174                                    .valueOf(value)));
175            }
176    
177            public Matrix divide(double value) {
178                    return new JScienceDenseDoubleMatrix2D(matrix.times(Float64
179                                    .valueOf(1.0 / value)));
180            }
181    
182            public Matrix transpose() {
183                    return new JScienceDenseDoubleMatrix2D(matrix.transpose().copy());
184            }
185    
186            public Matrix inv() {
187                    return new JScienceDenseDoubleMatrix2D(matrix.inverse());
188            }
189    
190            public Matrix[] lu() {
191                    if (isSquare()) {
192                            LUDecomposition<Float64> lu = LUDecomposition.valueOf(matrix);
193                            int m = (int) getRowCount();
194                            DenseMatrix<Float64> lt = lu.getLower(Float64.ZERO, Float64.ONE);
195                            DenseMatrix<Float64> ut = lu.getUpper(Float64.ZERO);
196                            FastTable<Index> piv = lu.getPivots();
197                            Matrix l = new JScienceDenseDoubleMatrix2D(lt);
198                            Matrix u = new JScienceDenseDoubleMatrix2D(ut);
199                            Matrix p = new JScienceDenseDoubleMatrix2D(m, m);
200                            for (int i = 0; i < m; i++) {
201                                    p.setAsDouble(1, i, piv.get(i).intValue());
202                            }
203                            return new Matrix[] { l, u, p };
204                    } else {
205                            throw new MatrixException("matrix must be square");
206                    }
207            }
208    
209            public Float64Matrix getWrappedObject() {
210                    return matrix;
211            }
212    
213            public void setWrappedObject(Float64Matrix object) {
214                    this.matrix = object;
215            }
216    
217            private void readObject(ObjectInputStream s) throws IOException,
218                            ClassNotFoundException {
219                    s.defaultReadObject();
220                    double[][] values = (double[][]) s.readObject();
221                    matrix = Float64Matrix.valueOf(values);
222            }
223    
224            private void writeObject(ObjectOutputStream s) throws IOException,
225                            MatrixException {
226                    s.defaultWriteObject();
227                    s.writeObject(this.toDoubleArray());
228            }
229    
230            public Matrix solve(Matrix b) {
231                    if (b instanceof JScienceDenseDoubleMatrix2D) {
232                            JScienceDenseDoubleMatrix2D b2 = (JScienceDenseDoubleMatrix2D) b;
233                            Float64Matrix x = Float64Matrix.valueOf(matrix.solve(b2.matrix));
234                            return new JScienceDenseDoubleMatrix2D(x);
235                    } else {
236                            return super.solve(b);
237                    }
238            }
239    }