001: /*
002: Copyright © 2007 Stefano Chizzolini. http://clown.stefanochizzolini.it
003:
004: Contributors:
005: * Stefano Chizzolini (original code developer, http://www.stefanochizzolini.it):
006: contributed code is Copyright © 2007 by Stefano Chizzolini.
007:
008: This file should be part of the source code distribution of "PDF Clown library"
009: (the Program): see the accompanying README files for more info.
010:
011: This Program is free software; you can redistribute it and/or modify it under
012: the terms of the GNU General Public License as published by the Free Software
013: Foundation; either version 2 of the License, or (at your option) any later version.
014:
015: This Program is distributed in the hope that it will be useful, but WITHOUT ANY
016: WARRANTY, either expressed or implied; without even the implied warranty of
017: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the License for more details.
018:
019: You should have received a copy of the GNU General Public License along with this
020: Program (see README files); if not, go to the GNU website (http://www.gnu.org/).
021:
022: Redistribution and use, with or without modification, are permitted provided that such
023: redistributions retain the above copyright notice, license and disclaimer, along with
024: this list of conditions.
025: */
026:
027: package it.stefanochizzolini.clown.util.math;
028:
029: /**
030: Square matrix providing fundamental operations of linear algebra.
031: <h3>Remarks</h3>
032: <p>This class is a specialized adaptation from the original JAMA (Java Matrix) project,
033: brought to the public domain by The MathWorks, Inc. and the National Institute of Standards
034: and Technology (see <a href="http://math.nist.gov/javanumerics/jama/">JAMA home page</a>).</p>
035:
036: @author Stefano Chizzolini
037: @version 0.0.4, 07/12/07
038: @since 0.0.4
039: */
040: public final class SquareMatrix implements Cloneable {
041: // <class>
042: // <static>
043: /**
044: Gets the identity matrix.
045: @param size Matrix size.
046: */
047: public static SquareMatrix getIdentity(int size) {
048: SquareMatrix matrix = new SquareMatrix(size);
049: double[][] matrixData = matrix.getData();
050: for (int i = 0; i < size; i++) {
051: for (int j = 0; j < size; j++) {
052: matrixData[i][j] = (i == j ? 1.0 : 0.0);
053: }
054: }
055:
056: return matrix;
057: }
058:
059: //TODO: implement if necessary!!!
060: /*
061: [return] = [matrix1] + [matrix2]
062: @param matrix1 1st addend matrix.
063: @param matrix2 2nd addend matrix.
064: */
065: // public static SquareMatrix sum(
066: // SquareMatrix matrix1,
067: // SquareMatrix matrix2
068: // )
069: // {
070: // checkSize(matrix1,matrix2);
071: //
072: // SquareMatrix sumMatrix = new SquareMatrix(matrix1.size);
073: //
074: // sum(matrix1.data,matrix2.data,sumMatrix.data);
075: //
076: // return sumMatrix;
077: // }
078: // private static void checkSize(
079: // SquareMatrix matrix1,
080: // SquareMatrix matrix2
081: // )
082: // {
083: // if (matrix1.getSize() != matrix2.getSize())
084: // throw new IllegalArgumentException("SquareMatrix dimensions must agree.");
085: // }
086: // private static void sum(
087: // double[][] matrix1Data,
088: // double[][] matrix2Data,
089: // double[][] sumMatrixData
090: // )
091: // {
092: // for(int i = 0; i < matrix1Data.length; i++)
093: // {
094: // for(int j = 0; j < matrix1Data.length; j++)
095: // {sumMatrixData[i][j] = matrix1Data[i][j] + matrix2Data[i][j];}
096: // }
097: // }
098: // </static>
099: // <dynamic>
100: private double[][] data;
101: private int size;
102:
103: // <constructors>
104: public SquareMatrix(int size) {
105: this .size = size;
106: data = new double[size][size];
107: }
108:
109: /**
110: Construct a matrix from a 2-D array.
111: @param data Two-dimensional array of doubles.
112: @exception IllegalArgumentException All rows must have the same length
113: */
114: public SquareMatrix(double[][] data) {
115: size = data.length;
116: for (int i = 0; i < size; i++) {
117: if (data[i].length != size)
118: throw new IllegalArgumentException(
119: "All rows must have the same length.");
120: }
121: this .data = data;
122: }
123:
124: // </constructors>
125:
126: public Object clone() {
127: SquareMatrix clone = new SquareMatrix(size);
128: double[][] cloneData = clone.getData();
129: for (int i = 0; i < size; i++) {
130: for (int j = 0; j < size; j++) {
131: cloneData[i][j] = data[i][j];
132: }
133: }
134:
135: return clone;
136: }
137:
138: /**
139: Gets the internal two-dimensional array.
140: */
141: public double[][] getData() {
142: return data;
143: }
144:
145: /**
146: Gets a submatrix.
147: @param rowIndexes Array of row indices.
148: @param startColumnIndex Initial column index.
149: @exception ArrayIndexOutOfBoundsException Submatrix indices
150: */
151: public SquareMatrix getMatrix(int[] rowIndexes, int startColumnIndex) {
152: SquareMatrix subMatrix = new SquareMatrix(rowIndexes.length);
153: double[][] subMatrixData = subMatrix.getData();
154: int endColumnIndex = startColumnIndex + rowIndexes.length - 1;
155: try {
156: for (int i = 0; i < rowIndexes.length; i++) {
157: for (int j = startColumnIndex; j <= endColumnIndex; j++) {
158: subMatrixData[i][j - startColumnIndex] = data[rowIndexes[i]][j];
159: }
160: }
161: } catch (ArrayIndexOutOfBoundsException e) {
162: throw new ArrayIndexOutOfBoundsException(
163: "Submatrix indices");
164: }
165:
166: return subMatrix;
167: }
168:
169: /*
170: [this] = [this] + [matrix]
171: @param matrix Addend.
172: */
173: // public SquareMatrix sum(
174: // SquareMatrix matrix
175: // )
176: // {
177: // checkSize(matrix);
178: //
179: // sum(data,matrix.data,data);
180: //
181: // return this;
182: // }
183: /* C = data - B
184: @param B another matrix
185: @return data - B
186: */
187: // public SquareMatrix minus (SquareMatrix B) {
188: // checkSize(B);
189: // SquareMatrix X = new SquareMatrix(m,n);
190: // double[][] C = X.getData();
191: // for (int i = 0; i < m; i++) {
192: // for (int j = 0; j < n; j++) {
193: // C[i][j] = data[i][j] - B.data[i][j];
194: // }
195: // }
196: // return X;
197: // }
198: /* data = data - B
199: @param B another matrix
200: @return data - B
201: */
202: // public SquareMatrix minusEquals (SquareMatrix B) {
203: // checkSize(B);
204: // for (int i = 0; i < m; i++) {
205: // for (int j = 0; j < n; j++) {
206: // data[i][j] = data[i][j] - B.data[i][j];
207: // }
208: // }
209: // return this;
210: // }
211: /* Element-by-element multiplication, C = data.*B
212: @param B another matrix
213: @return data.*B
214: */
215: // public SquareMatrix arrayTimes (SquareMatrix B) {
216: // checkSize(B);
217: // SquareMatrix X = new SquareMatrix(m,n);
218: // double[][] C = X.getData();
219: // for (int i = 0; i < m; i++) {
220: // for (int j = 0; j < n; j++) {
221: // C[i][j] = data[i][j] * B.data[i][j];
222: // }
223: // }
224: // return X;
225: // }
226: /* Element-by-element multiplication in place, data = data.*B
227: @param B another matrix
228: @return data.*B
229: */
230: // public SquareMatrix arrayTimesEquals (SquareMatrix B) {
231: // checkSize(B);
232: // for (int i = 0; i < m; i++) {
233: // for (int j = 0; j < n; j++) {
234: // data[i][j] = data[i][j] * B.data[i][j];
235: // }
236: // }
237: // return this;
238: // }
239: /* Element-by-element right division, C = data./B
240: @param B another matrix
241: @return data./B
242: */
243: // public SquareMatrix arrayRightDivide (SquareMatrix B) {
244: // checkSize(B);
245: // SquareMatrix X = new SquareMatrix(m,n);
246: // double[][] C = X.getData();
247: // for (int i = 0; i < m; i++) {
248: // for (int j = 0; j < n; j++) {
249: // C[i][j] = data[i][j] / B.data[i][j];
250: // }
251: // }
252: // return X;
253: // }
254: /* Element-by-element right division in place, data = data./B
255: @param B another matrix
256: @return data./B
257: */
258: // public SquareMatrix arrayRightDivideEquals (SquareMatrix B) {
259: // checkSize(B);
260: // for (int i = 0; i < m; i++) {
261: // for (int j = 0; j < n; j++) {
262: // data[i][j] = data[i][j] / B.data[i][j];
263: // }
264: // }
265: // return this;
266: // }
267: /* Element-by-element left division, C = data.\B
268: @param B another matrix
269: @return data.\B
270: */
271: // public SquareMatrix arrayLeftDivide (SquareMatrix B) {
272: // checkSize(B);
273: // SquareMatrix X = new SquareMatrix(m,n);
274: // double[][] C = X.getData();
275: // for (int i = 0; i < m; i++) {
276: // for (int j = 0; j < n; j++) {
277: // C[i][j] = B.data[i][j] / data[i][j];
278: // }
279: // }
280: // return X;
281: // }
282: /* Element-by-element left division in place, data = data.\B
283: @param B another matrix
284: @return data.\B
285: */
286: // public SquareMatrix arrayLeftDivideEquals (SquareMatrix B) {
287: // checkSize(B);
288: // for (int i = 0; i < m; i++) {
289: // for (int j = 0; j < n; j++) {
290: // data[i][j] = B.data[i][j] / data[i][j];
291: // }
292: // }
293: // return this;
294: // }
295: /* Multiply a matrix by a scalar, C = s*data
296: @param s scalar
297: @return s*data
298: */
299: // public SquareMatrix times (double s) {
300: // SquareMatrix X = new SquareMatrix(m,n);
301: // double[][] C = X.getData();
302: // for (int i = 0; i < m; i++) {
303: // for (int j = 0; j < n; j++) {
304: // C[i][j] = s*data[i][j];
305: // }
306: // }
307: // return X;
308: // }
309: /* Multiply a matrix by a scalar in place, data = s*data
310: @param s scalar
311: @return replace data by s*data
312: */
313: // public SquareMatrix timesEquals (double s) {
314: // for (int i = 0; i < m; i++) {
315: // for (int j = 0; j < n; j++) {
316: // data[i][j] = s*data[i][j];
317: // }
318: // }
319: // return this;
320: // }
321: /* Linear algebraic matrix multiplication, data * B
322: @param B another matrix
323: @return SquareMatrix product, data * B
324: @exception IllegalArgumentException SquareMatrix inner dimensions must agree.
325: */
326: // public SquareMatrix times (SquareMatrix B) {
327: // if (B.m != n) {
328: // throw new IllegalArgumentException("SquareMatrix inner dimensions must agree.");
329: // }
330: // SquareMatrix X = new SquareMatrix(m,B.n);
331: // double[][] C = X.getData();
332: // double[] Bcolj = new double[n];
333: // for (int j = 0; j < B.n; j++) {
334: // for (int k = 0; k < n; k++) {
335: // Bcolj[k] = B.data[k][j];
336: // }
337: // for (int i = 0; i < m; i++) {
338: // double[] Arowi = data[i];
339: // double s = 0;
340: // for (int k = 0; k < n; k++) {
341: // s += Arowi[k]*Bcolj[k];
342: // }
343: // C[i][j] = s;
344: // }
345: // }
346: // return X;
347: // }
348: /**
349: Gets the matrix determinant.
350: */
351: public double getDet() {
352: return (new LUDecomposition(this )).getDet();
353: }
354:
355: /**
356: Gets the matrix inverse.
357: */
358: public SquareMatrix getInverse() {
359: return solve(getIdentity(size));
360: }
361:
362: /**
363: Get matrix size.
364: */
365: public int getSize() {
366: return size;
367: }
368:
369: /**
370: Solve [this] * [return] = [target]
371: @param target Resulting matrix.
372: @return Solution.
373: */
374: public SquareMatrix solve(SquareMatrix target) {
375: return (new LUDecomposition(this )).solve(target);
376: }
377: // </dynamic>
378: // </class>
379: }
|