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;
19dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
20dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport java.lang.reflect.Array;
21dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
22dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport org.apache.commons.math.Field;
23dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport org.apache.commons.math.FieldElement;
24dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport org.apache.commons.math.MathRuntimeException;
25dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport org.apache.commons.math.exception.util.LocalizedFormats;
26dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
27dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond/**
28dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * Calculates the LUP-decomposition of a square matrix.
29dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * <p>The LUP-decomposition of a matrix A consists of three matrices
30dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * L, U and P that satisfy: PA = LU, L is lower triangular, and U is
31dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * upper triangular and P is a permutation matrix. All matrices are
32dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * m&times;m.</p>
33dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * <p>Since {@link FieldElement field elements} do not provide an ordering
34dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * operator, the permutation matrix is computed here only in order to avoid
35dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * a zero pivot element, no attempt is done to get the largest pivot element.</p>
36dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond *
37dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * @param <T> the type of the field elements
38dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * @version $Revision: 983921 $ $Date: 2010-08-10 12:46:06 +0200 (mar. 10 août 2010) $
39dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * @since 2.0
40dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond */
41dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondpublic class FieldLUDecompositionImpl<T extends FieldElement<T>> implements FieldLUDecomposition<T> {
42dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
43dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Field to which the elements belong. */
44dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private final Field<T> field;
45dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
46dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Entries of LU decomposition. */
47dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private T lu[][];
48dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
49dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Pivot permutation associated with LU decomposition */
50dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private int[] pivot;
51dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
52dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Parity of the permutation associated with the LU decomposition */
53dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private boolean even;
54dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
55dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Singularity indicator. */
56dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private boolean singular;
57dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
58dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Cached value of L. */
59dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private FieldMatrix<T> cachedL;
60dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
61dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Cached value of U. */
62dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private FieldMatrix<T> cachedU;
63dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
64dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Cached value of P. */
65dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private FieldMatrix<T> cachedP;
66dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
67dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
68dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Calculates the LU-decomposition of the given matrix.
69dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param matrix The matrix to decompose.
70dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @exception NonSquareMatrixException if matrix is not square
71dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
72dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public FieldLUDecompositionImpl(FieldMatrix<T> matrix)
73dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        throws NonSquareMatrixException {
74dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
75dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (!matrix.isSquare()) {
76dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            throw new NonSquareMatrixException(matrix.getRowDimension(), matrix.getColumnDimension());
77dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
78dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
79dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int m = matrix.getColumnDimension();
80dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        field = matrix.getField();
81dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        lu = matrix.getData();
82dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        pivot = new int[m];
83dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        cachedL = null;
84dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        cachedU = null;
85dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        cachedP = null;
86dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
87dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        // Initialize permutation array and parity
88dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int row = 0; row < m; row++) {
89dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            pivot[row] = row;
90dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
91dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        even     = true;
92dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        singular = false;
93dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
94dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        // Loop over columns
95dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int col = 0; col < m; col++) {
96dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
97dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            T sum = field.getZero();
98dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
99dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            // upper
100dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int row = 0; row < col; row++) {
101dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                final T[] luRow = lu[row];
102dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                sum = luRow[col];
103dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                for (int i = 0; i < row; i++) {
104dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    sum = sum.subtract(luRow[i].multiply(lu[i][col]));
105dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                }
106dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                luRow[col] = sum;
107dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
108dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
109dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            // lower
110dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            int nonZero = col; // permutation row
111dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int row = col; row < m; row++) {
112dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                final T[] luRow = lu[row];
113dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                sum = luRow[col];
114dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                for (int i = 0; i < col; i++) {
115dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    sum = sum.subtract(luRow[i].multiply(lu[i][col]));
116dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                }
117dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                luRow[col] = sum;
118dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
119dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                if (lu[nonZero][col].equals(field.getZero())) {
120dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    // try to select a better permutation choice
121dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    ++nonZero;
122dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                }
123dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
124dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
125dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            // Singularity check
126dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            if (nonZero >= m) {
127dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                singular = true;
128dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                return;
129dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
130dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
131dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            // Pivot if necessary
132dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            if (nonZero != col) {
133dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                T tmp = field.getZero();
134dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                for (int i = 0; i < m; i++) {
135dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    tmp = lu[nonZero][i];
136dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    lu[nonZero][i] = lu[col][i];
137dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    lu[col][i] = tmp;
138dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                }
139dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                int temp = pivot[nonZero];
140dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                pivot[nonZero] = pivot[col];
141dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                pivot[col] = temp;
142dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                even = !even;
143dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
144dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
145dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            // Divide the lower elements by the "winning" diagonal elt.
146dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final T luDiag = lu[col][col];
147dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int row = col + 1; row < m; row++) {
148dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                final T[] luRow = lu[row];
149dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                luRow[col] = luRow[col].divide(luDiag);
150dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
151dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
152dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
153dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
154dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
155dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** {@inheritDoc} */
156dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public FieldMatrix<T> getL() {
157dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if ((cachedL == null) && !singular) {
158dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final int m = pivot.length;
159dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            cachedL = new Array2DRowFieldMatrix<T>(field, m, m);
160dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int i = 0; i < m; ++i) {
161dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                final T[] luI = lu[i];
162dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                for (int j = 0; j < i; ++j) {
163dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    cachedL.setEntry(i, j, luI[j]);
164dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                }
165dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                cachedL.setEntry(i, i, field.getOne());
166dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
167dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
168dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return cachedL;
169dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
170dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
171dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** {@inheritDoc} */
172dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public FieldMatrix<T> getU() {
173dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if ((cachedU == null) && !singular) {
174dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final int m = pivot.length;
175dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            cachedU = new Array2DRowFieldMatrix<T>(field, m, m);
176dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int i = 0; i < m; ++i) {
177dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                final T[] luI = lu[i];
178dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                for (int j = i; j < m; ++j) {
179dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    cachedU.setEntry(i, j, luI[j]);
180dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                }
181dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
182dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
183dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return cachedU;
184dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
185dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
186dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** {@inheritDoc} */
187dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public FieldMatrix<T> getP() {
188dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if ((cachedP == null) && !singular) {
189dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final int m = pivot.length;
190dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            cachedP = new Array2DRowFieldMatrix<T>(field, m, m);
191dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int i = 0; i < m; ++i) {
192dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                cachedP.setEntry(i, pivot[i], field.getOne());
193dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
194dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
195dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return cachedP;
196dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
197dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
198dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** {@inheritDoc} */
199dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public int[] getPivot() {
200dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return pivot.clone();
201dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
202dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
203dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** {@inheritDoc} */
204dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public T getDeterminant() {
205dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (singular) {
206dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            return field.getZero();
207dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        } else {
208dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final int m = pivot.length;
209dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            T determinant = even ? field.getOne() : field.getZero().subtract(field.getOne());
210dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int i = 0; i < m; i++) {
211dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                determinant = determinant.multiply(lu[i][i]);
212dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
213dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            return determinant;
214dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
215dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
216dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
217dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** {@inheritDoc} */
218dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public FieldDecompositionSolver<T> getSolver() {
219dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return new Solver<T>(field, lu, pivot, singular);
220dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
221dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
222dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Specialized solver. */
223dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private static class Solver<T extends FieldElement<T>> implements FieldDecompositionSolver<T> {
224dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
225dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        /** Serializable version identifier. */
226dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        private static final long serialVersionUID = -6353105415121373022L;
227dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
228dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        /** Field to which the elements belong. */
229dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        private final Field<T> field;
230dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
231dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        /** Entries of LU decomposition. */
232dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        private final T lu[][];
233dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
234dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        /** Pivot permutation associated with LU decomposition. */
235dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        private final int[] pivot;
236dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
237dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        /** Singularity indicator. */
238dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        private final boolean singular;
239dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
240dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        /**
241dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond         * Build a solver from decomposed matrix.
242dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond         * @param field field to which the matrix elements belong
243dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond         * @param lu entries of LU decomposition
244dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond         * @param pivot pivot permutation associated with LU decomposition
245dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond         * @param singular singularity indicator
246dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond         */
247dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        private Solver(final Field<T> field, final T[][] lu,
248dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                       final int[] pivot, final boolean singular) {
249dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            this.field    = field;
250dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            this.lu       = lu;
251dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            this.pivot    = pivot;
252dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            this.singular = singular;
253dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
254dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
255dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        /** {@inheritDoc} */
256dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        public boolean isNonSingular() {
257dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            return !singular;
258dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
259dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
260dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        /** {@inheritDoc} */
261dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        public T[] solve(T[] b)
262dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            throws IllegalArgumentException, InvalidMatrixException {
263dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
264dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final int m = pivot.length;
265dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            if (b.length != m) {
266dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                throw MathRuntimeException.createIllegalArgumentException(
267dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                        LocalizedFormats.VECTOR_LENGTH_MISMATCH,
268dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                        b.length, m);
269dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
270dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            if (singular) {
271dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                throw new SingularMatrixException();
272dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
273dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
274dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            @SuppressWarnings("unchecked") // field is of type T
275dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final T[] bp = (T[]) Array.newInstance(field.getZero().getClass(), m);
276dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
277dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            // Apply permutations to b
278dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int row = 0; row < m; row++) {
279dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                bp[row] = b[pivot[row]];
280dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
281dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
282dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            // Solve LY = b
283dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int col = 0; col < m; col++) {
284dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                final T bpCol = bp[col];
285dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                for (int i = col + 1; i < m; i++) {
286dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    bp[i] = bp[i].subtract(bpCol.multiply(lu[i][col]));
287dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                }
288dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
289dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
290dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            // Solve UX = Y
291dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int col = m - 1; col >= 0; col--) {
292dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                bp[col] = bp[col].divide(lu[col][col]);
293dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                final T bpCol = bp[col];
294dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                for (int i = 0; i < col; i++) {
295dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    bp[i] = bp[i].subtract(bpCol.multiply(lu[i][col]));
296dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                }
297dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
298dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
299dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            return bp;
300dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
301dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
302dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
303dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        /** {@inheritDoc} */
304dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        public FieldVector<T> solve(FieldVector<T> b)
305dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            throws IllegalArgumentException, InvalidMatrixException {
306dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            try {
307dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                return solve((ArrayFieldVector<T>) b);
308dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            } catch (ClassCastException cce) {
309dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
310dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                final int m = pivot.length;
311dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                if (b.getDimension() != m) {
312dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    throw MathRuntimeException.createIllegalArgumentException(
313dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                            LocalizedFormats.VECTOR_LENGTH_MISMATCH,
314dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                            b.getDimension(), m);
315dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                }
316dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                if (singular) {
317dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    throw new SingularMatrixException();
318dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                }
319dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
320dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                @SuppressWarnings("unchecked") // field is of type T
321dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                final T[] bp = (T[]) Array.newInstance(field.getZero().getClass(), m);
322dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
323dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                // Apply permutations to b
324dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                for (int row = 0; row < m; row++) {
325dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    bp[row] = b.getEntry(pivot[row]);
326dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                }
327dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
328dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                // Solve LY = b
329dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                for (int col = 0; col < m; col++) {
330dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    final T bpCol = bp[col];
331dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    for (int i = col + 1; i < m; i++) {
332dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                        bp[i] = bp[i].subtract(bpCol.multiply(lu[i][col]));
333dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    }
334dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                }
335dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
336dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                // Solve UX = Y
337dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                for (int col = m - 1; col >= 0; col--) {
338dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    bp[col] = bp[col].divide(lu[col][col]);
339dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    final T bpCol = bp[col];
340dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    for (int i = 0; i < col; i++) {
341dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                        bp[i] = bp[i].subtract(bpCol.multiply(lu[i][col]));
342dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    }
343dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                }
344dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
345dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                return new ArrayFieldVector<T>(bp, false);
346dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
347dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
348dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
349dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
350dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        /** Solve the linear equation A &times; X = B.
351dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond         * <p>The A matrix is implicit here. It is </p>
352dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond         * @param b right-hand side of the equation A &times; X = B
353dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond         * @return a vector X such that A &times; X = B
354dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond         * @exception IllegalArgumentException if matrices dimensions don't match
355dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond         * @exception InvalidMatrixException if decomposed matrix is singular
356dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond         */
357dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        public ArrayFieldVector<T> solve(ArrayFieldVector<T> b)
358dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            throws IllegalArgumentException, InvalidMatrixException {
359dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            return new ArrayFieldVector<T>(solve(b.getDataRef()), false);
360dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
361dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
362dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        /** {@inheritDoc} */
363dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        public FieldMatrix<T> solve(FieldMatrix<T> b)
364dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            throws IllegalArgumentException, InvalidMatrixException {
365dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
366dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final int m = pivot.length;
367dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            if (b.getRowDimension() != m) {
368dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                throw MathRuntimeException.createIllegalArgumentException(
369dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                        LocalizedFormats.DIMENSIONS_MISMATCH_2x2,
370dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                        b.getRowDimension(), b.getColumnDimension(), m, "n");
371dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
372dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            if (singular) {
373dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                throw new SingularMatrixException();
374dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
375dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
376dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final int nColB = b.getColumnDimension();
377dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
378dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            // Apply permutations to b
379dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            @SuppressWarnings("unchecked") // field is of type T
380dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final T[][] bp = (T[][]) Array.newInstance(field.getZero().getClass(), new int[] { m, nColB });
381dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int row = 0; row < m; row++) {
382dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                final T[] bpRow = bp[row];
383dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                final int pRow = pivot[row];
384dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                for (int col = 0; col < nColB; col++) {
385dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    bpRow[col] = b.getEntry(pRow, col);
386dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                }
387dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
388dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
389dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            // Solve LY = b
390dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int col = 0; col < m; col++) {
391dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                final T[] bpCol = bp[col];
392dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                for (int i = col + 1; i < m; i++) {
393dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    final T[] bpI = bp[i];
394dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    final T luICol = lu[i][col];
395dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    for (int j = 0; j < nColB; j++) {
396dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                        bpI[j] = bpI[j].subtract(bpCol[j].multiply(luICol));
397dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    }
398dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                }
399dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
400dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
401dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            // Solve UX = Y
402dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int col = m - 1; col >= 0; col--) {
403dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                final T[] bpCol = bp[col];
404dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                final T luDiag = lu[col][col];
405dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                for (int j = 0; j < nColB; j++) {
406dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    bpCol[j] = bpCol[j].divide(luDiag);
407dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                }
408dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                for (int i = 0; i < col; i++) {
409dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    final T[] bpI = bp[i];
410dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    final T luICol = lu[i][col];
411dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    for (int j = 0; j < nColB; j++) {
412dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                        bpI[j] = bpI[j].subtract(bpCol[j].multiply(luICol));
413dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    }
414dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                }
415dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
416dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
417dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            return new Array2DRowFieldMatrix<T>(bp, false);
418dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
419dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
420dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
421dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        /** {@inheritDoc} */
422dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        public FieldMatrix<T> getInverse() throws InvalidMatrixException {
423dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final int m = pivot.length;
424dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final T one = field.getOne();
425dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            FieldMatrix<T> identity = new Array2DRowFieldMatrix<T>(field, m, m);
426dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int i = 0; i < m; ++i) {
427dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                identity.setEntry(i, i, one);
428dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
429dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            return solve(identity);
430dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
431dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
432dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
433dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
434dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond}
435