001         package com.croftsoft.core.math;
002    
003         /*********************************************************************
004         *
005         * A mathematical matrix class.
006         *
007         * @version
008         *   1998-12-27
009         * @author
010         *   <a href="https://www.croftsoft.com/">David Wallace Croft</a>
011         *********************************************************************/
012    
013         public class  Matrix
014         //////////////////////////////////////////////////////////////////////
015         //////////////////////////////////////////////////////////////////////
016         {
017    
018         public int             rows;
019         public int             cols;
020         public double [ ] [ ]  data;
021    
022         //////////////////////////////////////////////////////////////////////
023         //////////////////////////////////////////////////////////////////////
024    
025         /*********************************************************************
026         * Test/demo method.
027         *********************************************************************/
028         public static void  main ( )
029         //////////////////////////////////////////////////////////////////////
030         {
031           Matrix  left  = new Matrix ( 2, 3 );
032           Matrix  right = new Matrix ( 3, 4 );
033    
034           for ( int index_row = 0; index_row < left.rows; index_row++ )
035           for ( int index_col = 0; index_col < left.cols; index_col++ )
036           {
037             left.data [ index_row ] [ index_col ] = index_row + index_col;
038           }
039    
040           for ( int index_row = 0; index_row < right.rows; index_row++ )
041           for ( int index_col = 0; index_col < right.cols; index_col++ )
042           {
043             right.data [ index_row ] [ index_col ] = index_row + index_col;
044           }
045    
046           left.display ( );
047           System.out.println ( "" );
048           right.display ( );
049           System.out.println ( "" );
050           Matrix  product = multiply ( left, right );
051           product.display ( );
052           System.out.println ( "" );
053           Matrix  transposed = product.transpose ( );
054           transposed.display ( );
055           System.out.println ( "" );
056           Matrix  sigmoided = transposed.sigmoid ( );
057           sigmoided.display ( );
058         }
059    
060         //////////////////////////////////////////////////////////////////////
061         // Static methods
062         //////////////////////////////////////////////////////////////////////
063    
064         /*********************************************************************
065         * Returns a square matrix with the diagonal values set to 1.0 and
066         * all others set to 0.0.
067         *
068         * @param rows_cols
069         *   The number of rows and columns on a side.
070         *********************************************************************/
071         public static Matrix  identity ( int  rows_cols )
072         //////////////////////////////////////////////////////////////////////
073         {
074           Matrix  m = new Matrix ( rows_cols, rows_cols );
075    
076           for ( int  i = 0; i < rows_cols; i++ )
077           {
078             m.data [ i ] [ i ] = 1.0;
079           }
080    
081           return m;
082         }
083    
084         public static Matrix  multiply ( Matrix  left, Matrix  right )
085         //////////////////////////////////////////////////////////////////////
086         {
087           if ( left.cols != right.rows )
088           {
089             throw new ArrayIndexOutOfBoundsException (
090               "Matrix.multiply:  left.cols != right.rows" );
091           }
092    
093           Matrix  product = new Matrix ( left.rows, right.cols );
094    
095           for ( int index_row = 0; index_row < product.rows; index_row++ )
096           for ( int index_col = 0; index_col < product.cols; index_col++ )
097           {
098             product.data [ index_row ] [ index_col ] = 0.0;
099             for ( int index = 0; index < left.cols; index++ )
100             {
101               product.data [ index_row ] [ index_col ]
102                 += left.data [ index_row ] [ index ]
103                 * right.data [ index ] [ index_col ];
104             }
105           }
106    
107           return product;
108         }
109    
110         public static Matrix  multiplyPairwise ( Matrix  a, Matrix  b )
111         //////////////////////////////////////////////////////////////////////
112         {
113           if ( ( a.rows != b.rows ) || ( a.cols != b.cols ) )
114           {
115             throw new ArrayIndexOutOfBoundsException (
116               "Matrix.multiply_pairwise:  rows or columns not equal" );
117           }
118    
119           Matrix  product = new Matrix ( a.rows, a.cols );
120    
121           for ( int index_row = 0; index_row < a.rows; index_row++ )
122           for ( int index_col = 0; index_col < a.cols; index_col++ )
123           {
124             product.data [ index_row ] [ index_col ]
125               = a.data [ index_row ] [ index_col ]
126               * b.data [ index_row ] [ index_col ];
127           }
128    
129           return product;
130         }
131    
132         //////////////////////////////////////////////////////////////////////
133         // Constructor methods
134         //////////////////////////////////////////////////////////////////////
135    
136         /*********************************************************************
137         * Constructs a Matrix with all of the element values set to zero.
138         *********************************************************************/
139         public  Matrix ( int  rows, int  cols )
140         //////////////////////////////////////////////////////////////////////
141         {
142           this.rows = rows;
143           this.cols = cols;
144           this.data = new double [ rows ] [ cols ];
145         }
146    
147         /*********************************************************************
148         * Constructs a Matrix with all of the element values set to a
149         * specified constant.
150         *
151         * @param value
152         *   All of the element values will be set to this constant.
153         *********************************************************************/
154         public  Matrix ( int  rows, int  cols, double  value )
155         //////////////////////////////////////////////////////////////////////
156         {
157           this ( rows, cols );
158    
159           for ( int  row = 0; row < rows; row++ )
160           for ( int  col = 0; col < cols; col++ )
161           {
162             data [ row ] [ col ] = value;
163           }
164         }
165    
166         public Matrix ( Matrix  old )
167         //////////////////////////////////////////////////////////////////////
168         {
169           this ( old.rows, old.cols );
170           for ( int index_row = 0; index_row < this.rows; index_row++ )
171           for ( int index_col = 0; index_col < this.cols; index_col++ )
172           {
173             this.data [ index_row ] [ index_col ]
174               = old.data [ index_row ] [ index_col ];
175           }
176         }
177    
178         //////////////////////////////////////////////////////////////////////
179         //////////////////////////////////////////////////////////////////////
180    
181         public Matrix  add ( double  addend )
182         //////////////////////////////////////////////////////////////////////
183         {
184           Matrix  new_Matrix = new Matrix ( this );
185    
186           for ( int index_row = 0; index_row < this.rows; index_row++ )
187           for ( int index_col = 0; index_col < this.cols; index_col++ )
188           {
189             new_Matrix.data [ index_row ] [ index_col ] += addend;
190           }
191           return new_Matrix;
192         }
193    
194         public Matrix  add ( Matrix  addend )
195         //////////////////////////////////////////////////////////////////////
196         {
197           if ( ( this.rows!= addend.rows    )
198             || ( this.cols != addend.cols ) )
199           {
200             throw new ArrayIndexOutOfBoundsException (
201               "Matrix.add ( Matrix ):  columns and rows not equal" );
202           }
203    
204           Matrix  new_Matrix = new Matrix ( this );
205    
206           for ( int index_row = 0; index_row < this.rows; index_row++ )
207           for ( int index_col = 0; index_col < this.cols; index_col++ )
208           {
209             new_Matrix.data [ index_row ] [ index_col ]
210               += addend.data [ index_row ] [ index_col ];
211           }
212           return new_Matrix;
213         }
214    
215         public Matrix  clip ( double  min, double  max )
216         //////////////////////////////////////////////////////////////////////
217         {
218           Matrix  new_Matrix = new Matrix ( this );
219    
220           for ( int index_row = 0; index_row < this.rows; index_row++ )
221           for ( int index_col = 0; index_col < this.cols; index_col++ )
222           {
223             if ( this.data [ index_row ] [ index_col ] < min )
224               new_Matrix.data [ index_row ] [ index_col ] = min;
225             else if ( this.data [ index_row ] [ index_col ] > max )
226               new_Matrix.data [ index_row ] [ index_col ] = max;
227           }
228           return new_Matrix;
229         }
230    
231         public void  display ( )
232         //////////////////////////////////////////////////////////////////////
233         {
234           for ( int index_row = 0; index_row < this.rows; index_row++ )
235           {
236             String  line_String = "";
237             for ( int index_col = 0; index_col < this.cols; index_col++ )
238             {
239               line_String += this.data [ index_row ] [ index_col ] + " ";
240             }
241             System.out.println ( line_String );
242           }
243         }
244    
245         public Matrix  multiply ( double  factor )
246         //////////////////////////////////////////////////////////////////////
247         {
248           Matrix  new_Matrix = new Matrix ( this );
249    
250           for ( int index_row = 0; index_row < this.rows; index_row++ )
251           for ( int index_col = 0; index_col < this.cols; index_col++ )
252           {
253             new_Matrix.data [ index_row ] [ index_col ] *= factor;
254           }
255    
256           return new_Matrix;
257         }
258    
259         public Matrix  multiply ( Matrix  right )
260         //////////////////////////////////////////////////////////////////////
261         {
262           return multiply ( this, right );
263         }
264    
265         public Matrix  randomizeUniform ( double  min, double  max )
266         //////////////////////////////////////////////////////////////////////
267         {
268           Matrix  new_Matrix = new Matrix ( this.rows, this.cols );
269    
270           for ( int index_row = 0; index_row < this.rows; index_row++ )
271           for ( int index_col = 0; index_col < this.cols; index_col++ )
272           {
273             new_Matrix.data [ index_row ] [ index_col ]
274               = RandomLib.uniform ( min, max );
275           }
276    
277           return new_Matrix;
278         }
279    
280         public Matrix  sigmoid ( )
281         //////////////////////////////////////////////////////////////////////
282         {
283           Matrix  new_Matrix = new Matrix ( this.rows, this.cols );
284    
285           for ( int index_row = 0; index_row < this.rows; index_row++ )
286           for ( int index_col = 0; index_col < this.cols; index_col++ )
287           {
288             new_Matrix.data [ index_row ] [ index_col ]
289               = MathLib.sigmoid ( this.data [ index_row ] [ index_col ] );
290           }
291    
292           return new_Matrix;
293         }
294    
295         public Matrix  sigmoidDerivative ( )
296         //////////////////////////////////////////////////////////////////////
297         {
298           Matrix  new_Matrix = new Matrix ( this.rows, this.cols );
299    
300           for ( int index_row = 0; index_row < this.rows; index_row++ )
301           for ( int index_col = 0; index_col < this.cols; index_col++ )
302           {
303             new_Matrix.data [ index_row ] [ index_col ]
304               = MathLib.sigmoidDerivative
305               ( this.data [ index_row ] [ index_col ] );
306           }
307    
308           return new_Matrix;
309         }
310    
311         public Matrix  submatrix (
312           int  row_start, int  row_end,
313           int  col_start, int  col_end )
314         //////////////////////////////////////////////////////////////////////
315         //  Note that the first row is row 0.
316         //////////////////////////////////////////////////////////////////////
317         {
318           Matrix  sub
319             = new Matrix ( row_end - row_start + 1, col_end - col_start + 1 );
320           for ( int index_row = 0; index_row < sub.rows; index_row++ )
321           for ( int index_col = 0; index_col < sub.cols; index_col++ )
322           {
323             sub.data [ index_row ] [ index_col ]
324               = this.data [ index_row + row_start ] [ index_col + col_start ];
325           }
326    
327           return sub;
328         }
329    
330         public Matrix  subtract ( Matrix  subtractor )
331         //////////////////////////////////////////////////////////////////////
332         {
333           if ( ( this.rows    != subtractor.rows    )
334             || ( this.cols != subtractor.cols ) )
335           {
336             throw new ArrayIndexOutOfBoundsException (
337               "Matrix.subtract ( Matrix ):  columns and rows not equal" );
338           }
339    
340           Matrix  new_Matrix = new Matrix ( this );
341    
342           for ( int index_row = 0; index_row < this.rows; index_row++ )
343           for ( int index_col = 0; index_col < this.cols; index_col++ )
344           {
345             new_Matrix.data [ index_row ] [ index_col ]
346               -= subtractor.data [ index_row ] [ index_col ];
347           }
348    
349           return new_Matrix;
350         }
351    
352         public double  sum ( )
353         //////////////////////////////////////////////////////////////////////
354         {
355           double  temp = 0.0;
356    
357           for ( int index_row = 0; index_row < this.rows; index_row++ )
358           for ( int index_col = 0; index_col < this.cols; index_col++ )
359           {
360             temp += this.data [ index_row ] [ index_col ];
361           }
362    
363           return temp;
364         }
365    
366         public Matrix  transpose ( )
367         //////////////////////////////////////////////////////////////////////
368         {
369           Matrix  transposed = new Matrix ( this.cols, this.rows );
370    
371           for ( int index_row = 0;
372                     index_row < transposed.rows;
373                     index_row++ )
374           for ( int index_col = 0;
375                     index_col < transposed.cols;
376                     index_col++ )
377           {
378             transposed.data [ index_row ] [ index_col ]
379               = this.data [ index_col ] [ index_row ];
380           }
381    
382           return transposed;
383         }
384    
385         //////////////////////////////////////////////////////////////////////
386         //////////////////////////////////////////////////////////////////////
387         }