1dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond/*
2dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * Licensed to the Apache Software Foundation (ASF) under one or more
3dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * contributor license agreements.  See the NOTICE file distributed with
4dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * this work for additional information regarding copyright ownership.
5dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * The ASF licenses this file to You under the Apache License, Version 2.0
6dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * (the "License"); you may not use this file except in compliance with
7dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * the License.  You may obtain a copy of the License at
8dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond *
9dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond *      http://www.apache.org/licenses/LICENSE-2.0
10dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond *
11dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * Unless required by applicable law or agreed to in writing, software
12dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * distributed under the License is distributed on an "AS IS" BASIS,
13dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * See the License for the specific language governing permissions and
15dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * limitations under the License.
16dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond */
17dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
18dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondpackage org.apache.commons.math.linear;
19dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport java.io.Serializable;
20dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport java.math.BigDecimal;
21dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
22dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport org.apache.commons.math.MathRuntimeException;
23dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport org.apache.commons.math.exception.util.LocalizedFormats;
24dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
25dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond/**
26dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * Implementation of {@link BigMatrix} using a BigDecimal[][] array to store entries
27dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * and <a href="http://www.math.gatech.edu/~bourbaki/math2601/Web-notes/2num.pdf">
28dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * LU decompostion</a> to support linear system
29dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * solution and inverse.
30dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * <p>
31dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * The LU decompostion is performed as needed, to support the following operations: <ul>
32dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * <li>solve</li>
33dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * <li>isSingular</li>
34dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * <li>getDeterminant</li>
35dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * <li>inverse</li> </ul></p>
36dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * <p>
37dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond* <strong>Usage notes</strong>:<br>
38dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * <ul><li>
39dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * The LU decomposition is stored and reused on subsequent calls.  If matrix
40dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * data are modified using any of the public setXxx methods, the saved
41dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * decomposition is discarded.  If data are modified via references to the
42dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * underlying array obtained using <code>getDataRef()</code>, then the stored
43dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * LU decomposition will not be discarded.  In this case, you need to
44dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * explicitly invoke <code>LUDecompose()</code> to recompute the decomposition
45dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * before using any of the methods above.</li>
46dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * <li>
47dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * As specified in the {@link BigMatrix} interface, matrix element indexing
48dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * is 0-based -- e.g., <code>getEntry(0, 0)</code>
49dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * returns the element in the first row, first column of the matrix.</li></ul></p>
50dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond *
51dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * @deprecated as of 2.0, replaced by {@link Array2DRowFieldMatrix} with a {@link
52dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * org.apache.commons.math.util.BigReal} parameter
53dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * @version $Revision: 1042376 $ $Date: 2010-12-05 16:54:55 +0100 (dim. 05 déc. 2010) $
54dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond */
55dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond@Deprecated
56dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondpublic class BigMatrixImpl implements BigMatrix, Serializable {
57dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
58dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** BigDecimal 0 */
59dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    static final BigDecimal ZERO = new BigDecimal(0);
60dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
61dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** BigDecimal 1 */
62dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    static final BigDecimal ONE = new BigDecimal(1);
63dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
64dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Bound to determine effective singularity in LU decomposition */
65dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private static final BigDecimal TOO_SMALL = new BigDecimal(10E-12);
66dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
67dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Serialization id */
68dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private static final long serialVersionUID = -1011428905656140431L;
69dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
70dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Entries of the matrix */
71dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    protected BigDecimal data[][] = null;
72dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
73dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Entries of cached LU decomposition.
74dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *  All updates to data (other than luDecompose()) *must* set this to null
75dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
76dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    protected BigDecimal lu[][] = null;
77dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
78dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Permutation associated with LU decomposition */
79dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    protected int[] permutation = null;
80dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
81dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Parity of the permutation associated with the LU decomposition */
82dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    protected int parity = 1;
83dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
84dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Rounding mode for divisions **/
85dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private int roundingMode = BigDecimal.ROUND_HALF_UP;
86dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
87dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /*** BigDecimal scale ***/
88dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private int scale = 64;
89dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
90dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
91dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Creates a matrix with no data
92dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
93dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigMatrixImpl() {
94dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
95dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
96dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
97dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Create a new BigMatrix with the supplied row and column dimensions.
98dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
99dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param rowDimension      the number of rows in the new matrix
100dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param columnDimension   the number of columns in the new matrix
101dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws IllegalArgumentException if row or column dimension is not
102dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *  positive
103dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
104dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigMatrixImpl(int rowDimension, int columnDimension) {
105dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (rowDimension < 1 ) {
106dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            throw MathRuntimeException.createIllegalArgumentException(
107dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    LocalizedFormats.INSUFFICIENT_DIMENSION, rowDimension, 1);
108dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
109dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (columnDimension < 1) {
110dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            throw MathRuntimeException.createIllegalArgumentException(
111dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    LocalizedFormats.INSUFFICIENT_DIMENSION, columnDimension, 1);
112dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
113dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        data = new BigDecimal[rowDimension][columnDimension];
114dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        lu = null;
115dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
116dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
117dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
118dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Create a new BigMatrix using <code>d</code> as the underlying
119dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * data array.
120dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>The input array is copied, not referenced. This constructor has
121dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * the same effect as calling {@link #BigMatrixImpl(BigDecimal[][], boolean)}
122dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * with the second argument set to <code>true</code>.</p>
123dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
124dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param d data for new matrix
125dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws IllegalArgumentException if <code>d</code> is not rectangular
126dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *  (not all rows have the same length) or empty
127dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws NullPointerException if <code>d</code> is null
128dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
129dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigMatrixImpl(BigDecimal[][] d) {
130dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        this.copyIn(d);
131dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        lu = null;
132dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
133dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
134dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
135dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Create a new BigMatrix using the input array as the underlying
136dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * data array.
137dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>If an array is built specially in order to be embedded in a
138dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * BigMatrix and not used directly, the <code>copyArray</code> may be
139dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * set to <code>false</code. This will prevent the copying and improve
140dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * performance as no new array will be built and no data will be copied.</p>
141dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param d data for new matrix
142dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param copyArray if true, the input array will be copied, otherwise
143dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * it will be referenced
144dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws IllegalArgumentException if <code>d</code> is not rectangular
145dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *  (not all rows have the same length) or empty
146dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws NullPointerException if <code>d</code> is null
147dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @see #BigMatrixImpl(BigDecimal[][])
148dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
149dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigMatrixImpl(BigDecimal[][] d, boolean copyArray) {
150dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (copyArray) {
151dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            copyIn(d);
152dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        } else {
153dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            if (d == null) {
154dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                throw new NullPointerException();
155dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
156dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final int nRows = d.length;
157dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            if (nRows == 0) {
158dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.AT_LEAST_ONE_ROW);
159dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
160dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
161dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final int nCols = d[0].length;
162dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            if (nCols == 0) {
163dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.AT_LEAST_ONE_COLUMN);
164dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
165dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int r = 1; r < nRows; r++) {
166dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                if (d[r].length != nCols) {
167dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    throw MathRuntimeException.createIllegalArgumentException(
168dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                          LocalizedFormats.DIFFERENT_ROWS_LENGTHS,
169dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                          nCols, d[r].length);
170dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                }
171dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
172dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            data = d;
173dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
174dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        lu = null;
175dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
176dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
177dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
178dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Create a new BigMatrix using <code>d</code> as the underlying
179dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * data array.
180dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>Since the underlying array will hold <code>BigDecimal</code>
181dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * instances, it will be created.</p>
182dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
183dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param d data for new matrix
184dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws IllegalArgumentException if <code>d</code> is not rectangular
185dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *  (not all rows have the same length) or empty
186dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws NullPointerException if <code>d</code> is null
187dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
188dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigMatrixImpl(double[][] d) {
189dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int nRows = d.length;
190dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (nRows == 0) {
191dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.AT_LEAST_ONE_ROW);
192dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
193dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
194dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int nCols = d[0].length;
195dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (nCols == 0) {
196dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.AT_LEAST_ONE_COLUMN);
197dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
198dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int row = 1; row < nRows; row++) {
199dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            if (d[row].length != nCols) {
200dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                throw MathRuntimeException.createIllegalArgumentException(
201dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                      LocalizedFormats.DIFFERENT_ROWS_LENGTHS,
202dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                      nCols, d[row].length);
203dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
204dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
205dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        this.copyIn(d);
206dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        lu = null;
207dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
208dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
209dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
210dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Create a new BigMatrix using the values represented by the strings in
211dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <code>d</code> as the underlying data array.
212dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
213dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param d data for new matrix
214dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws IllegalArgumentException if <code>d</code> is not rectangular
215dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *  (not all rows have the same length) or empty
216dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws NullPointerException if <code>d</code> is null
217dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
218dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigMatrixImpl(String[][] d) {
219dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int nRows = d.length;
220dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (nRows == 0) {
221dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.AT_LEAST_ONE_ROW);
222dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
223dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
224dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int nCols = d[0].length;
225dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (nCols == 0) {
226dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.AT_LEAST_ONE_COLUMN);
227dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
228dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int row = 1; row < nRows; row++) {
229dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            if (d[row].length != nCols) {
230dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                throw MathRuntimeException.createIllegalArgumentException(
231dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                      LocalizedFormats.DIFFERENT_ROWS_LENGTHS,
232dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                      nCols, d[row].length);
233dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
234dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
235dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        this.copyIn(d);
236dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        lu = null;
237dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
238dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
239dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
240dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Create a new (column) BigMatrix using <code>v</code> as the
241dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * data for the unique column of the <code>v.length x 1</code> matrix
242dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * created.
243dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>
244dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * The input array is copied, not referenced.</p>
245dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
246dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param v column vector holding data for new matrix
247dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
248dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigMatrixImpl(BigDecimal[] v) {
249dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int nRows = v.length;
250dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        data = new BigDecimal[nRows][1];
251dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int row = 0; row < nRows; row++) {
252dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            data[row][0] = v[row];
253dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
254dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
255dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
256dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
257dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Create a new BigMatrix which is a copy of this.
258dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
259dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return  the cloned matrix
260dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
261dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigMatrix copy() {
262dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return new BigMatrixImpl(this.copyOut(), false);
263dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
264dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
265dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
266dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Compute the sum of this and <code>m</code>.
267dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
268dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param m    matrix to be added
269dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return     this + m
270dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws  IllegalArgumentException if m is not the same size as this
271dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
272dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigMatrix add(BigMatrix m) throws IllegalArgumentException {
273dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        try {
274dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            return add((BigMatrixImpl) m);
275dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        } catch (ClassCastException cce) {
276dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
277dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            // safety check
278dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            MatrixUtils.checkAdditionCompatible(this, m);
279dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
280dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final int rowCount    = getRowDimension();
281dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final int columnCount = getColumnDimension();
282dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final BigDecimal[][] outData = new BigDecimal[rowCount][columnCount];
283dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int row = 0; row < rowCount; row++) {
284dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                final BigDecimal[] dataRow    = data[row];
285dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                final BigDecimal[] outDataRow = outData[row];
286dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                for (int col = 0; col < columnCount; col++) {
287dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    outDataRow[col] = dataRow[col].add(m.getEntry(row, col));
288dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                }
289dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
290dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            return new BigMatrixImpl(outData, false);
291dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
292dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
293dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
294dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
295dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Compute the sum of this and <code>m</code>.
296dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
297dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param m    matrix to be added
298dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return     this + m
299dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws  IllegalArgumentException if m is not the same size as this
300dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
301dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigMatrixImpl add(BigMatrixImpl m) throws IllegalArgumentException {
302dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
303dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        // safety check
304dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        MatrixUtils.checkAdditionCompatible(this, m);
305dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
306dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int rowCount    = getRowDimension();
307dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int columnCount = getColumnDimension();
308dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final BigDecimal[][] outData = new BigDecimal[rowCount][columnCount];
309dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int row = 0; row < rowCount; row++) {
310dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final BigDecimal[] dataRow    = data[row];
311dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final BigDecimal[] mRow       = m.data[row];
312dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final BigDecimal[] outDataRow = outData[row];
313dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int col = 0; col < columnCount; col++) {
314dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                outDataRow[col] = dataRow[col].add(mRow[col]);
315dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
316dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
317dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return new BigMatrixImpl(outData, false);
318dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
319dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
320dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
321dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Compute  this minus <code>m</code>.
322dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
323dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param m    matrix to be subtracted
324dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return     this + m
325dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws  IllegalArgumentException if m is not the same size as this
326dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
327dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigMatrix subtract(BigMatrix m) throws IllegalArgumentException {
328dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        try {
329dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            return subtract((BigMatrixImpl) m);
330dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        } catch (ClassCastException cce) {
331dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
332dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            // safety check
333dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            MatrixUtils.checkSubtractionCompatible(this, m);
334dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
335dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final int rowCount    = getRowDimension();
336dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final int columnCount = getColumnDimension();
337dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final BigDecimal[][] outData = new BigDecimal[rowCount][columnCount];
338dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int row = 0; row < rowCount; row++) {
339dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                final BigDecimal[] dataRow    = data[row];
340dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                final BigDecimal[] outDataRow = outData[row];
341dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                for (int col = 0; col < columnCount; col++) {
342dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    outDataRow[col] = dataRow[col].subtract(getEntry(row, col));
343dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                }
344dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
345dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            return new BigMatrixImpl(outData, false);
346dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
347dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
348dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
349dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
350dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Compute  this minus <code>m</code>.
351dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
352dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param m    matrix to be subtracted
353dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return     this + m
354dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws  IllegalArgumentException if m is not the same size as this
355dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
356dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigMatrixImpl subtract(BigMatrixImpl m) throws IllegalArgumentException {
357dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
358dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        // safety check
359dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        MatrixUtils.checkSubtractionCompatible(this, m);
360dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
361dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int rowCount    = getRowDimension();
362dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int columnCount = getColumnDimension();
363dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final BigDecimal[][] outData = new BigDecimal[rowCount][columnCount];
364dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int row = 0; row < rowCount; row++) {
365dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final BigDecimal[] dataRow    = data[row];
366dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final BigDecimal[] mRow       = m.data[row];
367dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final BigDecimal[] outDataRow = outData[row];
368dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int col = 0; col < columnCount; col++) {
369dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                outDataRow[col] = dataRow[col].subtract(mRow[col]);
370dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
371dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
372dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return new BigMatrixImpl(outData, false);
373dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
374dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
375dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
376dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns the result of adding d to each entry of this.
377dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
378dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param d    value to be added to each entry
379dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return     d + this
380dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
381dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigMatrix scalarAdd(BigDecimal d) {
382dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int rowCount    = getRowDimension();
383dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int columnCount = getColumnDimension();
384dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final BigDecimal[][] outData = new BigDecimal[rowCount][columnCount];
385dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int row = 0; row < rowCount; row++) {
386dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final BigDecimal[] dataRow    = data[row];
387dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final BigDecimal[] outDataRow = outData[row];
388dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int col = 0; col < columnCount; col++) {
389dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                outDataRow[col] = dataRow[col].add(d);
390dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
391dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
392dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return new BigMatrixImpl(outData, false);
393dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
394dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
395dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
396dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns the result of multiplying each entry of this by <code>d</code>
397dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param d  value to multiply all entries by
398dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return d * this
399dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
400dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigMatrix scalarMultiply(BigDecimal d) {
401dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int rowCount    = getRowDimension();
402dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int columnCount = getColumnDimension();
403dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final BigDecimal[][] outData = new BigDecimal[rowCount][columnCount];
404dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int row = 0; row < rowCount; row++) {
405dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final BigDecimal[] dataRow    = data[row];
406dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final BigDecimal[] outDataRow = outData[row];
407dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int col = 0; col < columnCount; col++) {
408dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                outDataRow[col] = dataRow[col].multiply(d);
409dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
410dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
411dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return new BigMatrixImpl(outData, false);
412dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
413dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
414dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
415dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns the result of postmultiplying this by <code>m</code>.
416dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param m    matrix to postmultiply by
417dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return     this*m
418dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws     IllegalArgumentException
419dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *             if columnDimension(this) != rowDimension(m)
420dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
421dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigMatrix multiply(BigMatrix m) throws IllegalArgumentException {
422dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        try {
423dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            return multiply((BigMatrixImpl) m);
424dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        } catch (ClassCastException cce) {
425dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
426dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            // safety check
427dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            MatrixUtils.checkMultiplicationCompatible(this, m);
428dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
429dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final int nRows = this.getRowDimension();
430dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final int nCols = m.getColumnDimension();
431dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final int nSum = this.getColumnDimension();
432dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final BigDecimal[][] outData = new BigDecimal[nRows][nCols];
433dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int row = 0; row < nRows; row++) {
434dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                final BigDecimal[] dataRow    = data[row];
435dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                final BigDecimal[] outDataRow = outData[row];
436dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                for (int col = 0; col < nCols; col++) {
437dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    BigDecimal sum = ZERO;
438dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    for (int i = 0; i < nSum; i++) {
439dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                        sum = sum.add(dataRow[i].multiply(m.getEntry(i, col)));
440dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    }
441dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    outDataRow[col] = sum;
442dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                }
443dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
444dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            return new BigMatrixImpl(outData, false);
445dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
446dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
447dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
448dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
449dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns the result of postmultiplying this by <code>m</code>.
450dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param m    matrix to postmultiply by
451dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return     this*m
452dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws     IllegalArgumentException
453dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *             if columnDimension(this) != rowDimension(m)
454dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
455dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigMatrixImpl multiply(BigMatrixImpl m) throws IllegalArgumentException {
456dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
457dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        // safety check
458dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        MatrixUtils.checkMultiplicationCompatible(this, m);
459dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
460dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int nRows = this.getRowDimension();
461dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int nCols = m.getColumnDimension();
462dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int nSum = this.getColumnDimension();
463dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final BigDecimal[][] outData = new BigDecimal[nRows][nCols];
464dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int row = 0; row < nRows; row++) {
465dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final BigDecimal[] dataRow    = data[row];
466dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final BigDecimal[] outDataRow = outData[row];
467dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int col = 0; col < nCols; col++) {
468dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                BigDecimal sum = ZERO;
469dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                for (int i = 0; i < nSum; i++) {
470dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    sum = sum.add(dataRow[i].multiply(m.data[i][col]));
471dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                }
472dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                outDataRow[col] = sum;
473dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
474dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
475dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return new BigMatrixImpl(outData, false);
476dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
477dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
478dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
479dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns the result premultiplying this by <code>m</code>.
480dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param m    matrix to premultiply by
481dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return     m * this
482dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws     IllegalArgumentException
483dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *             if rowDimension(this) != columnDimension(m)
484dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
485dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigMatrix preMultiply(BigMatrix m) throws IllegalArgumentException {
486dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return m.multiply(this);
487dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
488dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
489dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
490dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns matrix entries as a two-dimensional array.
491dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>
492dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Makes a fresh copy of the underlying data.</p>
493dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
494dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return    2-dimensional array of entries
495dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
496dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigDecimal[][] getData() {
497dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return copyOut();
498dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
499dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
500dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
501dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns matrix entries as a two-dimensional array.
502dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>
503dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Makes a fresh copy of the underlying data converted to
504dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <code>double</code> values.</p>
505dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
506dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return    2-dimensional array of entries
507dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
508dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public double[][] getDataAsDoubleArray() {
509dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int nRows = getRowDimension();
510dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int nCols = getColumnDimension();
511dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final double d[][] = new double[nRows][nCols];
512dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int i = 0; i < nRows; i++) {
513dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int j = 0; j < nCols; j++) {
514dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                d[i][j] = data[i][j].doubleValue();
515dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
516dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
517dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return d;
518dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
519dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
520dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
521dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns a reference to the underlying data array.
522dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>
523dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Does not make a fresh copy of the underlying data.</p>
524dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
525dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return 2-dimensional array of entries
526dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
527dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigDecimal[][] getDataRef() {
528dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return data;
529dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
530dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
531dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /***
532dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Gets the rounding mode for division operations
533dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * The default is {@link java.math.BigDecimal#ROUND_HALF_UP}
534dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @see BigDecimal
535dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return the rounding mode.
536dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
537dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public int getRoundingMode() {
538dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return roundingMode;
539dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
540dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
541dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /***
542dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Sets the rounding mode for decimal divisions.
543dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @see BigDecimal
544dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param roundingMode rounding mode for decimal divisions
545dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
546dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public void setRoundingMode(int roundingMode) {
547dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        this.roundingMode = roundingMode;
548dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
549dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
550dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /***
551dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Sets the scale for division operations.
552dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * The default is 64
553dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @see BigDecimal
554dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return the scale
555dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
556dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public int getScale() {
557dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return scale;
558dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
559dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
560dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /***
561dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Sets the scale for division operations.
562dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @see BigDecimal
563dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param scale scale for division operations
564dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
565dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public void setScale(int scale) {
566dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        this.scale = scale;
567dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
568dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
569dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
570dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns the <a href="http://mathworld.wolfram.com/MaximumAbsoluteRowSumNorm.html">
571dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * maximum absolute row sum norm</a> of the matrix.
572dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
573dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return norm
574dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
575dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigDecimal getNorm() {
576dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        BigDecimal maxColSum = ZERO;
577dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int col = 0; col < this.getColumnDimension(); col++) {
578dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            BigDecimal sum = ZERO;
579dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int row = 0; row < this.getRowDimension(); row++) {
580dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                sum = sum.add(data[row][col].abs());
581dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
582dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            maxColSum = maxColSum.max(sum);
583dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
584dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return maxColSum;
585dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
586dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
587dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
588dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Gets a submatrix. Rows and columns are indicated
589dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * counting from 0 to n-1.
590dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
591dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param startRow Initial row index
592dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param endRow Final row index
593dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param startColumn Initial column index
594dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param endColumn Final column index
595dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return The subMatrix containing the data of the
596dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *         specified rows and columns
597dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @exception MatrixIndexException if row or column selections are not valid
598dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
599dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigMatrix getSubMatrix(int startRow, int endRow,
600dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                                  int startColumn, int endColumn)
601dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        throws MatrixIndexException {
602dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
603dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        MatrixUtils.checkRowIndex(this, startRow);
604dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        MatrixUtils.checkRowIndex(this, endRow);
605dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (startRow > endRow) {
606dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            throw new MatrixIndexException(LocalizedFormats.INITIAL_ROW_AFTER_FINAL_ROW,
607dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                                           startRow, endRow);
608dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
609dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
610dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        MatrixUtils.checkColumnIndex(this, startColumn);
611dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        MatrixUtils.checkColumnIndex(this, endColumn);
612dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (startColumn > endColumn) {
613dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            throw new MatrixIndexException(LocalizedFormats.INITIAL_COLUMN_AFTER_FINAL_COLUMN,
614dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                                           startColumn, endColumn);
615dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
616dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
617dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final BigDecimal[][] subMatrixData =
618dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            new BigDecimal[endRow - startRow + 1][endColumn - startColumn + 1];
619dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int i = startRow; i <= endRow; i++) {
620dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            System.arraycopy(data[i], startColumn,
621dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                             subMatrixData[i - startRow], 0,
622dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                             endColumn - startColumn + 1);
623dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
624dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
625dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return new BigMatrixImpl(subMatrixData, false);
626dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
627dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
628dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
629dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
630dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Gets a submatrix. Rows and columns are indicated
631dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * counting from 0 to n-1.
632dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
633dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param selectedRows Array of row indices must be non-empty
634dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param selectedColumns Array of column indices must be non-empty
635dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return The subMatrix containing the data in the
636dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *     specified rows and columns
637dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @exception MatrixIndexException  if supplied row or column index arrays
638dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *     are not valid
639dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
640dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigMatrix getSubMatrix(int[] selectedRows, int[] selectedColumns)
641dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        throws MatrixIndexException {
642dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
643dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (selectedRows.length * selectedColumns.length == 0) {
644dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            if (selectedRows.length == 0) {
645dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                throw new MatrixIndexException(LocalizedFormats.EMPTY_SELECTED_ROW_INDEX_ARRAY);
646dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
647dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            throw new MatrixIndexException(LocalizedFormats.EMPTY_SELECTED_COLUMN_INDEX_ARRAY);
648dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
649dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
650dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final BigDecimal[][] subMatrixData =
651dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            new BigDecimal[selectedRows.length][selectedColumns.length];
652dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        try  {
653dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int i = 0; i < selectedRows.length; i++) {
654dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                final BigDecimal[] subI = subMatrixData[i];
655dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                final BigDecimal[] dataSelectedI = data[selectedRows[i]];
656dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                for (int j = 0; j < selectedColumns.length; j++) {
657dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    subI[j] = dataSelectedI[selectedColumns[j]];
658dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                }
659dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
660dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        } catch (ArrayIndexOutOfBoundsException e) {
661dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            // we redo the loop with checks enabled
662dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            // in order to generate an appropriate message
663dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (final int row : selectedRows) {
664dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                MatrixUtils.checkRowIndex(this, row);
665dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
666dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (final int column : selectedColumns) {
667dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                MatrixUtils.checkColumnIndex(this, column);
668dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
669dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
670dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return new BigMatrixImpl(subMatrixData, false);
671dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
672dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
673dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
674dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Replace the submatrix starting at <code>row, column</code> using data in
675dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * the input <code>subMatrix</code> array. Indexes are 0-based.
676dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>
677dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Example:<br>
678dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Starting with <pre>
679dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * 1  2  3  4
680dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * 5  6  7  8
681dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * 9  0  1  2
682dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * </pre>
683dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * and <code>subMatrix = {{3, 4} {5,6}}</code>, invoking
684dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <code>setSubMatrix(subMatrix,1,1))</code> will result in <pre>
685dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * 1  2  3  4
686dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * 5  3  4  8
687dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * 9  5  6  2
688dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * </pre></p>
689dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
690dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param subMatrix  array containing the submatrix replacement data
691dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param row  row coordinate of the top, left element to be replaced
692dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param column  column coordinate of the top, left element to be replaced
693dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws MatrixIndexException  if subMatrix does not fit into this
694dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *    matrix from element in (row, column)
695dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws IllegalArgumentException if <code>subMatrix</code> is not rectangular
696dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *  (not all rows have the same length) or empty
697dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws NullPointerException if <code>subMatrix</code> is null
698dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @since 1.1
699dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
700dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public void setSubMatrix(BigDecimal[][] subMatrix, int row, int column)
701dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    throws MatrixIndexException {
702dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
703dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int nRows = subMatrix.length;
704dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (nRows == 0) {
705dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.AT_LEAST_ONE_ROW);
706dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
707dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
708dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int nCols = subMatrix[0].length;
709dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (nCols == 0) {
710dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.AT_LEAST_ONE_COLUMN);
711dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
712dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
713dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int r = 1; r < nRows; r++) {
714dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            if (subMatrix[r].length != nCols) {
715dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                throw MathRuntimeException.createIllegalArgumentException(
716dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                      LocalizedFormats.DIFFERENT_ROWS_LENGTHS,
717dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                      nCols, subMatrix[r].length);
718dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
719dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
720dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
721dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (data == null) {
722dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            if (row > 0) {
723dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                throw MathRuntimeException.createIllegalStateException(
724dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                        LocalizedFormats.FIRST_ROWS_NOT_INITIALIZED_YET,
725dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                        row);
726dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
727dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            if (column > 0) {
728dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                throw MathRuntimeException.createIllegalStateException(
729dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                        LocalizedFormats.FIRST_COLUMNS_NOT_INITIALIZED_YET,
730dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                        column);
731dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
732dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            data = new BigDecimal[nRows][nCols];
733dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            System.arraycopy(subMatrix, 0, data, 0, subMatrix.length);
734dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        } else {
735dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            MatrixUtils.checkRowIndex(this, row);
736dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            MatrixUtils.checkColumnIndex(this, column);
737dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            MatrixUtils.checkRowIndex(this, nRows + row - 1);
738dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            MatrixUtils.checkColumnIndex(this, nCols + column - 1);
739dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
740dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int i = 0; i < nRows; i++) {
741dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            System.arraycopy(subMatrix[i], 0, data[row + i], column, nCols);
742dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
743dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
744dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        lu = null;
745dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
746dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
747dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
748dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
749dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns the entries in row number <code>row</code>
750dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * as a row matrix.  Row indices start at 0.
751dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
752dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param row the row to be fetched
753dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return row matrix
754dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws MatrixIndexException if the specified row index is invalid
755dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
756dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigMatrix getRowMatrix(int row) throws MatrixIndexException {
757dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        MatrixUtils.checkRowIndex(this, row);
758dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int ncols = this.getColumnDimension();
759dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final BigDecimal[][] out = new BigDecimal[1][ncols];
760dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        System.arraycopy(data[row], 0, out[0], 0, ncols);
761dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return new BigMatrixImpl(out, false);
762dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
763dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
764dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
765dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns the entries in column number <code>column</code>
766dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * as a column matrix.  Column indices start at 0.
767dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
768dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param column the column to be fetched
769dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return column matrix
770dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws MatrixIndexException if the specified column index is invalid
771dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
772dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigMatrix getColumnMatrix(int column) throws MatrixIndexException {
773dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        MatrixUtils.checkColumnIndex(this, column);
774dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int nRows = this.getRowDimension();
775dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final BigDecimal[][] out = new BigDecimal[nRows][1];
776dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int row = 0; row < nRows; row++) {
777dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            out[row][0] = data[row][column];
778dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
779dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return new BigMatrixImpl(out, false);
780dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
781dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
782dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
783dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns the entries in row number <code>row</code> as an array.
784dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>
785dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Row indices start at 0.  A <code>MatrixIndexException</code> is thrown
786dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * unless <code>0 <= row < rowDimension.</code></p>
787dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
788dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param row the row to be fetched
789dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return array of entries in the row
790dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws MatrixIndexException if the specified row index is not valid
791dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
792dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigDecimal[] getRow(int row) throws MatrixIndexException {
793dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        MatrixUtils.checkRowIndex(this, row);
794dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int ncols = this.getColumnDimension();
795dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final BigDecimal[] out = new BigDecimal[ncols];
796dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        System.arraycopy(data[row], 0, out, 0, ncols);
797dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return out;
798dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
799dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
800dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     /**
801dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns the entries in row number <code>row</code> as an array
802dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * of double values.
803dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>
804dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Row indices start at 0.  A <code>MatrixIndexException</code> is thrown
805dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * unless <code>0 <= row < rowDimension.</code></p>
806dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
807dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param row the row to be fetched
808dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return array of entries in the row
809dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws MatrixIndexException if the specified row index is not valid
810dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
811dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public double[] getRowAsDoubleArray(int row) throws MatrixIndexException {
812dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        MatrixUtils.checkRowIndex(this, row);
813dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int ncols = this.getColumnDimension();
814dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final double[] out = new double[ncols];
815dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int i=0;i<ncols;i++) {
816dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            out[i] = data[row][i].doubleValue();
817dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
818dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return out;
819dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
820dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
821dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     /**
822dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns the entries in column number <code>col</code> as an array.
823dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>
824dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Column indices start at 0.  A <code>MatrixIndexException</code> is thrown
825dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * unless <code>0 <= column < columnDimension.</code></p>
826dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
827dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param col the column to be fetched
828dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return array of entries in the column
829dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws MatrixIndexException if the specified column index is not valid
830dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
831dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigDecimal[] getColumn(int col) throws MatrixIndexException {
832dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        MatrixUtils.checkColumnIndex(this, col);
833dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int nRows = this.getRowDimension();
834dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final BigDecimal[] out = new BigDecimal[nRows];
835dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int i = 0; i < nRows; i++) {
836dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            out[i] = data[i][col];
837dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
838dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return out;
839dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
840dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
841dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
842dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns the entries in column number <code>col</code> as an array
843dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * of double values.
844dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>
845dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Column indices start at 0.  A <code>MatrixIndexException</code> is thrown
846dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * unless <code>0 <= column < columnDimension.</code></p>
847dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
848dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param col the column to be fetched
849dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return array of entries in the column
850dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws MatrixIndexException if the specified column index is not valid
851dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
852dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public double[] getColumnAsDoubleArray(int col) throws MatrixIndexException {
853dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        MatrixUtils.checkColumnIndex(this, col);
854dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int nrows = this.getRowDimension();
855dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final double[] out = new double[nrows];
856dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int i=0;i<nrows;i++) {
857dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            out[i] = data[i][col].doubleValue();
858dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
859dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return out;
860dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
861dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
862dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     /**
863dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns the entry in the specified row and column.
864dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>
865dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Row and column indices start at 0 and must satisfy
866dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <ul>
867dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <li><code>0 <= row < rowDimension</code></li>
868dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <li><code> 0 <= column < columnDimension</code></li>
869dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * </ul>
870dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * otherwise a <code>MatrixIndexException</code> is thrown.</p>
871dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
872dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param row  row location of entry to be fetched
873dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param column  column location of entry to be fetched
874dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return matrix entry in row,column
875dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws MatrixIndexException if the row or column index is not valid
876dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
877dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigDecimal getEntry(int row, int column)
878dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    throws MatrixIndexException {
879dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        try {
880dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            return data[row][column];
881dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        } catch (ArrayIndexOutOfBoundsException e) {
882dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            throw new MatrixIndexException(
883dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    LocalizedFormats.NO_SUCH_MATRIX_ENTRY,
884dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    row, column, getRowDimension(), getColumnDimension());
885dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
886dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
887dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
888dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
889dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns the entry in the specified row and column as a double.
890dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>
891dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Row and column indices start at 0 and must satisfy
892dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <ul>
893dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <li><code>0 <= row < rowDimension</code></li>
894dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <li><code> 0 <= column < columnDimension</code></li>
895dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * </ul>
896dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * otherwise a <code>MatrixIndexException</code> is thrown.</p>
897dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
898dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param row  row location of entry to be fetched
899dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param column  column location of entry to be fetched
900dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return matrix entry in row,column
901dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws MatrixIndexException if the row
902dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * or column index is not valid
903dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
904dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public double getEntryAsDouble(int row, int column) throws MatrixIndexException {
905dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return getEntry(row,column).doubleValue();
906dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
907dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
908dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
909dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns the transpose matrix.
910dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
911dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return transpose matrix
912dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
913dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigMatrix transpose() {
914dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int nRows = this.getRowDimension();
915dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int nCols = this.getColumnDimension();
916dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final BigDecimal[][] outData = new BigDecimal[nCols][nRows];
917dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int row = 0; row < nRows; row++) {
918dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final BigDecimal[] dataRow = data[row];
919dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int col = 0; col < nCols; col++) {
920dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                outData[col][row] = dataRow[col];
921dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
922dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
923dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return new BigMatrixImpl(outData, false);
924dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
925dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
926dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
927dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns the inverse matrix if this matrix is invertible.
928dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
929dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return inverse matrix
930dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws InvalidMatrixException if this is not invertible
931dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
932dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigMatrix inverse() throws InvalidMatrixException {
933dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return solve(MatrixUtils.createBigIdentityMatrix(getRowDimension()));
934dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
935dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
936dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
937dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns the determinant of this matrix.
938dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
939dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return determinant
940dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws InvalidMatrixException if matrix is not square
941dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
942dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigDecimal getDeterminant() throws InvalidMatrixException {
943dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (!isSquare()) {
944dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            throw new NonSquareMatrixException(getRowDimension(), getColumnDimension());
945dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
946dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (isSingular()) {   // note: this has side effect of attempting LU decomp if lu == null
947dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            return ZERO;
948dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        } else {
949dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            BigDecimal det = (parity == 1) ? ONE : ONE.negate();
950dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int i = 0; i < getRowDimension(); i++) {
951dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                det = det.multiply(lu[i][i]);
952dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
953dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            return det;
954dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
955dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
956dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
957dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     /**
958dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Is this a square matrix?
959dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return true if the matrix is square (rowDimension = columnDimension)
960dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
961dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public boolean isSquare() {
962dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return getColumnDimension() == getRowDimension();
963dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
964dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
965dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
966dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Is this a singular matrix?
967dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return true if the matrix is singular
968dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
969dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public boolean isSingular() {
970dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (lu == null) {
971dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            try {
972dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                luDecompose();
973dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                return false;
974dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            } catch (InvalidMatrixException ex) {
975dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                return true;
976dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
977dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        } else { // LU decomp must have been successfully performed
978dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            return false; // so the matrix is not singular
979dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
980dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
981dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
982dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
983dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns the number of rows in the matrix.
984dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
985dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return rowDimension
986dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
987dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public int getRowDimension() {
988dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return data.length;
989dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
990dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
991dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
992dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns the number of columns in the matrix.
993dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
994dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return columnDimension
995dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
996dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public int getColumnDimension() {
997dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return data[0].length;
998dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
999dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1000dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     /**
1001dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns the <a href="http://mathworld.wolfram.com/MatrixTrace.html">
1002dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * trace</a> of the matrix (the sum of the elements on the main diagonal).
1003dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
1004dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return trace
1005dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
1006dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws IllegalArgumentException if this matrix is not square.
1007dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
1008dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigDecimal getTrace() throws IllegalArgumentException {
1009dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (!isSquare()) {
1010dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            throw new NonSquareMatrixException(getRowDimension(), getColumnDimension());
1011dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
1012dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        BigDecimal trace = data[0][0];
1013dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int i = 1; i < this.getRowDimension(); i++) {
1014dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            trace = trace.add(data[i][i]);
1015dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
1016dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return trace;
1017dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
1018dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1019dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
1020dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns the result of multiplying this by the vector <code>v</code>.
1021dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
1022dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param v the vector to operate on
1023dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return this*v
1024dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws IllegalArgumentException if columnDimension != v.size()
1025dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
1026dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigDecimal[] operate(BigDecimal[] v) throws IllegalArgumentException {
1027dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (v.length != getColumnDimension()) {
1028dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            throw MathRuntimeException.createIllegalArgumentException(
1029dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    LocalizedFormats.VECTOR_LENGTH_MISMATCH,
1030dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    v.length, getColumnDimension() );
1031dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
1032dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int nRows = this.getRowDimension();
1033dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int nCols = this.getColumnDimension();
1034dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final BigDecimal[] out = new BigDecimal[nRows];
1035dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int row = 0; row < nRows; row++) {
1036dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            BigDecimal sum = ZERO;
1037dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int i = 0; i < nCols; i++) {
1038dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                sum = sum.add(data[row][i].multiply(v[i]));
1039dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
1040dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            out[row] = sum;
1041dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
1042dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return out;
1043dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
1044dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1045dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
1046dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns the result of multiplying this by the vector <code>v</code>.
1047dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
1048dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param v the vector to operate on
1049dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return this*v
1050dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws IllegalArgumentException if columnDimension != v.size()
1051dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
1052dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigDecimal[] operate(double[] v) throws IllegalArgumentException {
1053dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final BigDecimal bd[] = new BigDecimal[v.length];
1054dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int i = 0; i < bd.length; i++) {
1055dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            bd[i] = new BigDecimal(v[i]);
1056dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
1057dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return operate(bd);
1058dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
1059dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1060dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
1061dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns the (row) vector result of premultiplying this by the vector <code>v</code>.
1062dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
1063dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param v the row vector to premultiply by
1064dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return v*this
1065dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws IllegalArgumentException if rowDimension != v.size()
1066dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
1067dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigDecimal[] preMultiply(BigDecimal[] v) throws IllegalArgumentException {
1068dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int nRows = this.getRowDimension();
1069dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (v.length != nRows) {
1070dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            throw MathRuntimeException.createIllegalArgumentException(
1071dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    LocalizedFormats.VECTOR_LENGTH_MISMATCH,
1072dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    v.length, nRows );
1073dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
1074dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int nCols = this.getColumnDimension();
1075dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final BigDecimal[] out = new BigDecimal[nCols];
1076dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int col = 0; col < nCols; col++) {
1077dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            BigDecimal sum = ZERO;
1078dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int i = 0; i < nRows; i++) {
1079dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                sum = sum.add(data[i][col].multiply(v[i]));
1080dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
1081dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            out[col] = sum;
1082dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
1083dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return out;
1084dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
1085dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1086dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
1087dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns a matrix of (column) solution vectors for linear systems with
1088dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * coefficient matrix = this and constant vectors = columns of
1089dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <code>b</code>.
1090dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
1091dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param b  array of constants forming RHS of linear systems to
1092dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * to solve
1093dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return solution array
1094dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws IllegalArgumentException if this.rowDimension != row dimension
1095dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws InvalidMatrixException if this matrix is not square or is singular
1096dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
1097dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigDecimal[] solve(BigDecimal[] b) throws IllegalArgumentException, InvalidMatrixException {
1098dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int nRows = this.getRowDimension();
1099dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (b.length != nRows) {
1100dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            throw MathRuntimeException.createIllegalArgumentException(
1101dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    LocalizedFormats.VECTOR_LENGTH_MISMATCH,
1102dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    b.length, nRows);
1103dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
1104dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final BigMatrix bMatrix = new BigMatrixImpl(b);
1105dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final BigDecimal[][] solution = ((BigMatrixImpl) (solve(bMatrix))).getDataRef();
1106dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final BigDecimal[] out = new BigDecimal[nRows];
1107dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int row = 0; row < nRows; row++) {
1108dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            out[row] = solution[row][0];
1109dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
1110dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return out;
1111dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
1112dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1113dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
1114dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns a matrix of (column) solution vectors for linear systems with
1115dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * coefficient matrix = this and constant vectors = columns of
1116dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <code>b</code>.
1117dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
1118dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param b  array of constants forming RHS of linear systems to
1119dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * to solve
1120dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return solution array
1121dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws IllegalArgumentException if this.rowDimension != row dimension
1122dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws InvalidMatrixException if this matrix is not square or is singular
1123dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
1124dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigDecimal[] solve(double[] b) throws IllegalArgumentException, InvalidMatrixException {
1125dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final BigDecimal bd[] = new BigDecimal[b.length];
1126dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int i = 0; i < bd.length; i++) {
1127dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            bd[i] = new BigDecimal(b[i]);
1128dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
1129dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return solve(bd);
1130dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
1131dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1132dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
1133dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns a matrix of (column) solution vectors for linear systems with
1134dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * coefficient matrix = this and constant vectors = columns of
1135dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <code>b</code>.
1136dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
1137dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param b  matrix of constant vectors forming RHS of linear systems to
1138dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * to solve
1139dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return matrix of solution vectors
1140dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws IllegalArgumentException if this.rowDimension != row dimension
1141dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws InvalidMatrixException if this matrix is not square or is singular
1142dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
1143dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigMatrix solve(BigMatrix b) throws IllegalArgumentException, InvalidMatrixException  {
1144dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (b.getRowDimension() != getRowDimension()) {
1145dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            throw MathRuntimeException.createIllegalArgumentException(
1146dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    LocalizedFormats.DIMENSIONS_MISMATCH_2x2,
1147dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    b.getRowDimension(), b.getColumnDimension(), getRowDimension(), "n");
1148dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
1149dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (!isSquare()) {
1150dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            throw new NonSquareMatrixException(getRowDimension(), getColumnDimension());
1151dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
1152dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (this.isSingular()) { // side effect: compute LU decomp
1153dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            throw new SingularMatrixException();
1154dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
1155dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1156dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int nCol = this.getColumnDimension();
1157dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int nColB = b.getColumnDimension();
1158dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int nRowB = b.getRowDimension();
1159dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1160dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        // Apply permutations to b
1161dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final BigDecimal[][] bp = new BigDecimal[nRowB][nColB];
1162dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int row = 0; row < nRowB; row++) {
1163dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final BigDecimal[] bpRow = bp[row];
1164dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int col = 0; col < nColB; col++) {
1165dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                bpRow[col] = b.getEntry(permutation[row], col);
1166dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
1167dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
1168dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1169dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        // Solve LY = b
1170dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int col = 0; col < nCol; col++) {
1171dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int i = col + 1; i < nCol; i++) {
1172dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                final BigDecimal[] bpI = bp[i];
1173dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                final BigDecimal[] luI = lu[i];
1174dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                for (int j = 0; j < nColB; j++) {
1175dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    bpI[j] = bpI[j].subtract(bp[col][j].multiply(luI[col]));
1176dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                }
1177dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
1178dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
1179dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1180dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        // Solve UX = Y
1181dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int col = nCol - 1; col >= 0; col--) {
1182dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final BigDecimal[] bpCol = bp[col];
1183dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final BigDecimal luDiag = lu[col][col];
1184dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int j = 0; j < nColB; j++) {
1185dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                bpCol[j] = bpCol[j].divide(luDiag, scale, roundingMode);
1186dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
1187dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int i = 0; i < col; i++) {
1188dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                final BigDecimal[] bpI = bp[i];
1189dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                final BigDecimal[] luI = lu[i];
1190dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                for (int j = 0; j < nColB; j++) {
1191dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    bpI[j] = bpI[j].subtract(bp[col][j].multiply(luI[col]));
1192dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                }
1193dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
1194dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
1195dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1196dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return new BigMatrixImpl(bp, false);
1197dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1198dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
1199dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1200dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
1201dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Computes a new
1202dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <a href="http://www.math.gatech.edu/~bourbaki/math2601/Web-notes/2num.pdf">
1203dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * LU decompostion</a> for this matrix, storing the result for use by other methods.
1204dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>
1205dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <strong>Implementation Note</strong>:<br>
1206dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Uses <a href="http://www.damtp.cam.ac.uk/user/fdl/people/sd/lectures/nummeth98/linear.htm">
1207dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Crout's algortithm</a>, with partial pivoting.</p>
1208dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>
1209dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <strong>Usage Note</strong>:<br>
1210dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * This method should rarely be invoked directly. Its only use is
1211dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * to force recomputation of the LU decomposition when changes have been
1212dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * made to the underlying data using direct array references. Changes
1213dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * made using setXxx methods will trigger recomputation when needed
1214dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * automatically.</p>
1215dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
1216dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws InvalidMatrixException if the matrix is non-square or singular.
1217dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
1218dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public void luDecompose() throws InvalidMatrixException {
1219dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1220dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int nRows = this.getRowDimension();
1221dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int nCols = this.getColumnDimension();
1222dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (nRows != nCols) {
1223dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            throw new NonSquareMatrixException(getRowDimension(), getColumnDimension());
1224dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
1225dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        lu = this.getData();
1226dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1227dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        // Initialize permutation array and parity
1228dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        permutation = new int[nRows];
1229dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int row = 0; row < nRows; row++) {
1230dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            permutation[row] = row;
1231dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
1232dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        parity = 1;
1233dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1234dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        // Loop over columns
1235dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int col = 0; col < nCols; col++) {
1236dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1237dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            BigDecimal sum = ZERO;
1238dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1239dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            // upper
1240dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int row = 0; row < col; row++) {
1241dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                final BigDecimal[] luRow = lu[row];
1242dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                sum = luRow[col];
1243dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                for (int i = 0; i < row; i++) {
1244dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    sum = sum.subtract(luRow[i].multiply(lu[i][col]));
1245dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                }
1246dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                luRow[col] = sum;
1247dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
1248dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1249dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            // lower
1250dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            int max = col; // permutation row
1251dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            BigDecimal largest = ZERO;
1252dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int row = col; row < nRows; row++) {
1253dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                final BigDecimal[] luRow = lu[row];
1254dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                sum = luRow[col];
1255dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                for (int i = 0; i < col; i++) {
1256dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    sum = sum.subtract(luRow[i].multiply(lu[i][col]));
1257dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                }
1258dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                luRow[col] = sum;
1259dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1260dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                // maintain best permutation choice
1261dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                if (sum.abs().compareTo(largest) == 1) {
1262dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    largest = sum.abs();
1263dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    max = row;
1264dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                }
1265dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
1266dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1267dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            // Singularity check
1268dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            if (lu[max][col].abs().compareTo(TOO_SMALL) <= 0) {
1269dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                lu = null;
1270dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                throw new SingularMatrixException();
1271dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
1272dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1273dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            // Pivot if necessary
1274dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            if (max != col) {
1275dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                BigDecimal tmp = ZERO;
1276dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                for (int i = 0; i < nCols; i++) {
1277dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    tmp = lu[max][i];
1278dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    lu[max][i] = lu[col][i];
1279dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    lu[col][i] = tmp;
1280dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                }
1281dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                int temp = permutation[max];
1282dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                permutation[max] = permutation[col];
1283dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                permutation[col] = temp;
1284dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                parity = -parity;
1285dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
1286dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1287dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            // Divide the lower elements by the "winning" diagonal elt.
1288dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final BigDecimal luDiag = lu[col][col];
1289dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int row = col + 1; row < nRows; row++) {
1290dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                final BigDecimal[] luRow = lu[row];
1291dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                luRow[col] = luRow[col].divide(luDiag, scale, roundingMode);
1292dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
1293dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1294dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
1295dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1296dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
1297dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1298dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
1299dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Get a string representation for this matrix.
1300dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return a string representation for this matrix
1301dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
1302dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    @Override
1303dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public String toString() {
1304dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        StringBuilder res = new StringBuilder();
1305dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        res.append("BigMatrixImpl{");
1306dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (data != null) {
1307dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int i = 0; i < data.length; i++) {
1308dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                if (i > 0) {
1309dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    res.append(",");
1310dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                }
1311dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                res.append("{");
1312dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                for (int j = 0; j < data[0].length; j++) {
1313dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    if (j > 0) {
1314dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                        res.append(",");
1315dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    }
1316dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    res.append(data[i][j]);
1317dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                }
1318dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                res.append("}");
1319dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
1320dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
1321dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        res.append("}");
1322dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return res.toString();
1323dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
1324dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1325dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
1326dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns true iff <code>object</code> is a
1327dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <code>BigMatrixImpl</code> instance with the same dimensions as this
1328dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * and all corresponding matrix entries are equal.  BigDecimal.equals
1329dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * is used to compare corresponding entries.
1330dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
1331dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param object the object to test equality against.
1332dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return true if object equals this
1333dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
1334dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    @Override
1335dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public boolean equals(Object object) {
1336dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (object == this ) {
1337dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            return true;
1338dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
1339dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (object instanceof BigMatrixImpl == false) {
1340dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            return false;
1341dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
1342dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final BigMatrix m = (BigMatrix) object;
1343dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int nRows = getRowDimension();
1344dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int nCols = getColumnDimension();
1345dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (m.getColumnDimension() != nCols || m.getRowDimension() != nRows) {
1346dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            return false;
1347dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
1348dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int row = 0; row < nRows; row++) {
1349dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final BigDecimal[] dataRow = data[row];
1350dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int col = 0; col < nCols; col++) {
1351dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                if (!dataRow[col].equals(m.getEntry(row, col))) {
1352dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    return false;
1353dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                }
1354dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
1355dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
1356dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return true;
1357dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
1358dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1359dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
1360dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Computes a hashcode for the matrix.
1361dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
1362dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return hashcode for matrix
1363dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
1364dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    @Override
1365dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public int hashCode() {
1366dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        int ret = 7;
1367dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int nRows = getRowDimension();
1368dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int nCols = getColumnDimension();
1369dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        ret = ret * 31 + nRows;
1370dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        ret = ret * 31 + nCols;
1371dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int row = 0; row < nRows; row++) {
1372dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final BigDecimal[] dataRow = data[row];
1373dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int col = 0; col < nCols; col++) {
1374dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                ret = ret * 31 + (11 * (row+1) + 17 * (col+1)) *
1375dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                dataRow[col].hashCode();
1376dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
1377dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
1378dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return ret;
1379dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
1380dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1381dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    //------------------------ Protected methods
1382dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1383dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
1384dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *  Returns the LU decomposition as a BigMatrix.
1385dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *  Returns a fresh copy of the cached LU matrix if this has been computed;
1386dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *  otherwise the composition is computed and cached for use by other methods.
1387dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *  Since a copy is returned in either case, changes to the returned matrix do not
1388dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *  affect the LU decomposition property.
1389dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>
1390dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * The matrix returned is a compact representation of the LU decomposition.
1391dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Elements below the main diagonal correspond to entries of the "L" matrix;
1392dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * elements on and above the main diagonal correspond to entries of the "U"
1393dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * matrix.</p>
1394dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>
1395dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Example: <pre>
1396dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
1397dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *     Returned matrix                L                  U
1398dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *         2  3  1                   1  0  0            2  3  1
1399dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *         5  4  6                   5  1  0            0  4  6
1400dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *         1  7  8                   1  7  1            0  0  8
1401dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * </pre>
1402dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
1403dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * The L and U matrices satisfy the matrix equation LU = permuteRows(this), <br>
1404dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *  where permuteRows reorders the rows of the matrix to follow the order determined
1405dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *  by the <a href=#getPermutation()>permutation</a> property.</p>
1406dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
1407dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return LU decomposition matrix
1408dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws InvalidMatrixException if the matrix is non-square or singular.
1409dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
1410dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    protected BigMatrix getLUMatrix() throws InvalidMatrixException {
1411dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (lu == null) {
1412dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            luDecompose();
1413dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
1414dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return new BigMatrixImpl(lu);
1415dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
1416dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1417dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
1418dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns the permutation associated with the lu decomposition.
1419dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * The entries of the array represent a permutation of the numbers 0, ... , nRows - 1.
1420dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>
1421dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Example:
1422dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * permutation = [1, 2, 0] means current 2nd row is first, current third row is second
1423dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * and current first row is last.</p>
1424dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>
1425dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns a fresh copy of the array.</p>
1426dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
1427dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return the permutation
1428dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
1429dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    protected int[] getPermutation() {
1430dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int[] out = new int[permutation.length];
1431dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        System.arraycopy(permutation, 0, out, 0, permutation.length);
1432dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return out;
1433dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
1434dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1435dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    //------------------------ Private methods
1436dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1437dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
1438dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns a fresh copy of the underlying data array.
1439dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
1440dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return a copy of the underlying data array.
1441dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
1442dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private BigDecimal[][] copyOut() {
1443dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int nRows = this.getRowDimension();
1444dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final BigDecimal[][] out = new BigDecimal[nRows][this.getColumnDimension()];
1445dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        // can't copy 2-d array in one shot, otherwise get row references
1446dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int i = 0; i < nRows; i++) {
1447dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            System.arraycopy(data[i], 0, out[i], 0, data[i].length);
1448dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
1449dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return out;
1450dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
1451dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1452dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
1453dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Replaces data with a fresh copy of the input array.
1454dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>
1455dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Verifies that the input array is rectangular and non-empty.</p>
1456dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
1457dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param in data to copy in
1458dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws IllegalArgumentException if input array is emtpy or not
1459dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *    rectangular
1460dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws NullPointerException if input array is null
1461dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
1462dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private void copyIn(BigDecimal[][] in) {
1463dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        setSubMatrix(in,0,0);
1464dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
1465dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1466dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
1467dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Replaces data with a fresh copy of the input array.
1468dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
1469dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param in data to copy in
1470dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
1471dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private void copyIn(double[][] in) {
1472dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int nRows = in.length;
1473dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int nCols = in[0].length;
1474dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        data = new BigDecimal[nRows][nCols];
1475dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int i = 0; i < nRows; i++) {
1476dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final BigDecimal[] dataI = data[i];
1477dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final double[] inI = in[i];
1478dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int j = 0; j < nCols; j++) {
1479dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                dataI[j] = new BigDecimal(inI[j]);
1480dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
1481dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
1482dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        lu = null;
1483dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
1484dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1485dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
1486dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Replaces data with BigDecimals represented by the strings in the input
1487dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * array.
1488dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
1489dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param in data to copy in
1490dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
1491dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private void copyIn(String[][] in) {
1492dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int nRows = in.length;
1493dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int nCols = in[0].length;
1494dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        data = new BigDecimal[nRows][nCols];
1495dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int i = 0; i < nRows; i++) {
1496dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final BigDecimal[] dataI = data[i];
1497dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final String[] inI = in[i];
1498dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int j = 0; j < nCols; j++) {
1499dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                dataI[j] = new BigDecimal(inI[j]);
1500dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
1501dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
1502dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        lu = null;
1503dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
1504dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
1505dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond}
1506