1
+ /**
2
+ * Matrix -- represents a matrix of numerical values.
3
+ */
4
+ function Matrix ( h , w , zero ) {
5
+ h = h === undefined ? 1 : h ;
6
+ w = w === undefined ? 1 : w ;
7
+ zero = zero === undefined ? false : zero ;
8
+
9
+ this . rows = h ;
10
+ this . cols = w ;
11
+ this . data = new Array ( ) ;
12
+
13
+ for ( var i = 0 ; i < h ; ++ i ) {
14
+ this . data . push ( new Array ( w ) ) ;
15
+
16
+ for ( var j = 0 ; ( zero && j < this . data [ i ] . length ) ; ++ j )
17
+ this . data [ i ] [ j ] = 0 ;
18
+ }
19
+
20
+ this . set = function ( row , col , value ) {
21
+ this . _checkIndex ( row , col ) ;
22
+ if ( typeof value !== "number" )
23
+ throw new TypeError ( "`value' must be a number" ) ;
24
+
25
+ this . data [ row ] [ col ] = value ;
26
+ } ;
27
+ this . setRow = function ( row , rowValues ) {
28
+ this . _checkRow ( row ) ;
29
+
30
+ if ( rowValues . constructor !== Array )
31
+ throw new TypeError ( "`rowValues' must be an array of numbers" ) ;
32
+
33
+ if ( rowValues . length !== this . cols )
34
+ throw new RangeError ( "Row must be of length " + this . cols . toString ( ) ) ;
35
+
36
+ this . data [ row ] = rowValues . slice ( 0 ) ;
37
+ } ;
38
+ this . setCol = function ( col , colValues ) {
39
+ this . _checkCol ( col ) ;
40
+
41
+ if ( colValues . constructor !== Array )
42
+ throw new TypeError ( "`colValues' must be an array of numbers." ) ;
43
+
44
+ if ( colValues . length !== this . rows )
45
+ throw new RangeError ( "Column must be of length " + this . rows . toString ( ) ) ;
46
+
47
+ for ( var row = 0 ; row < this . rows ; ++ row )
48
+ this . data [ row ] [ col ] = colValues [ row ] ;
49
+ } ;
50
+ this . get = function ( row , col ) {
51
+ this . _checkIndex ( row , col ) ;
52
+ return this . data [ row ] [ col ] ;
53
+ } ;
54
+ this . getRow = function ( row ) {
55
+ this . _checkRow ( row ) ;
56
+ return this . data [ row ] ;
57
+ } ;
58
+ this . getCol = function ( col ) {
59
+ this . _checkCol ( col ) ;
60
+ var column = new Array ( ) ;
61
+ for ( var row = 0 ; row < this . rows ; ++ row ) column . push ( this . data [ row ] [ col ] ) ;
62
+ return column ;
63
+ } ;
64
+ this . print = function ( ) {
65
+ console . table ( this . data ) ;
66
+ } ;
67
+ this . equals = function ( other ) {
68
+ if ( other . rows !== this . rows || other . cols !== this . cols ) return false ;
69
+
70
+ for ( var row = 0 ; row < this . rows ; ++ row ) {
71
+ for ( var col = 0 ; col < this . cols ; ++ col ) {
72
+ if ( this . get ( row , col ) !== other . get ( row , col ) ) return false ;
73
+ }
74
+ }
75
+
76
+ return true ;
77
+ } ;
78
+ this . rref = function ( augment ) {
79
+ if ( augment && augment . rows !== this . rows )
80
+ throw new RangeError ( "Augment dimension mismatch" ) ;
81
+
82
+ var result = {
83
+ "rref" :Matrix . copy ( this ) ,
84
+ "augment" :( augment !== undefined ) ? Matrix . copy ( augment ) : augment
85
+ } ;
86
+
87
+ var diagLength = ( result . rref . rows < result . rref . cols ) ?
88
+ result . rref . rows : result . rref . cols ;
89
+ var scaleFactor ;
90
+
91
+ //Loop over diagonal entries
92
+ for ( var i = 0 ; i < diagLength ; ++ i ) {
93
+ //Find the leading one for this diagonal index
94
+ var leadingOne = i ;
95
+
96
+ while ( leadingOne < diagLength && result . rref . get ( leadingOne , i ) === 0 )
97
+ ++ leadingOne ;
98
+
99
+ //A leading one was found, continue with elimination
100
+ if ( leadingOne < result . rref . rows ) {
101
+ if ( leadingOne !== i && leadingOne < result . rref . rows ) {
102
+ result . rref . _swapRows ( i , leadingOne ) ;
103
+
104
+ if ( augment ) result . augment . _swapRows ( i , leadingOne ) ;
105
+ }
106
+
107
+ scaleFactor = ( 1. / result . rref . get ( i , i ) ) ;
108
+ result . rref . _scaleRow ( i , scaleFactor ) ;
109
+ if ( augment ) result . augment . _scaleRow ( i , scaleFactor ) ;
110
+
111
+ for ( var row = 0 ; row < result . rref . rows ; ++ row ) {
112
+ if ( row === i ) continue ;
113
+
114
+ scaleFactor = - 1 * ( result . rref . get ( row , i ) ) ;
115
+
116
+ if ( scaleFactor !== 0 ) {
117
+ result . rref . _addRow ( row , result . rref . getRow ( i ) , scaleFactor ) ;
118
+ if ( augment )
119
+ result . augment . _addRow ( row , result . augment . getRow ( i ) , scaleFactor ) ;
120
+ }
121
+ }
122
+ }
123
+ }
124
+
125
+ return result ;
126
+ } ;
127
+ this . transpose = function ( ) {
128
+ var transMatrx = new Matrix ( this . cols , this . rows ) ;
129
+
130
+ for ( var row = 0 ; row < this . rows ; ++ row ) {
131
+ transMatrx . setCol ( row , this . getRow ( ) ) ;
132
+ }
133
+
134
+ return transMatrx ;
135
+ } ;
136
+ this . inverse = function ( ) {
137
+ if ( this . rows !== this . cols ) throw new RangeError ( "Matrix not square" ) ;
138
+
139
+ if ( this . rows === 1 && this . cols === 1 ) return ( 1. / this . get ( 0 , 0 ) ) ;
140
+ else {
141
+ var eye = Matrix . identity ( this . rows ) ;
142
+ var rrefData = this . rref ( eye ) ;
143
+
144
+ if ( rrefData . rref . equals ( eye ) ) return rrefData . augment ;
145
+ else throw new Error ( "Matrix not invertible" ) ;
146
+ }
147
+ } ;
148
+ this . scale = function ( scaleFactor ) {
149
+ var scaled = new Matrix ( this . rows , this . cols ) ;
150
+
151
+ for ( var row = 0 ; row < this . rows ; ++ row ) {
152
+ for ( var col = 0 ; col < this . cols ; ++ col )
153
+ scaled . set ( row , col , this . get ( row , col ) * scaleFactor ) ;
154
+ }
155
+ } ;
156
+ this . multiply = function ( other ) {
157
+ if ( other . cols === 1 && other . rows === 1 ) return this . scale ( other . get ( 0 , 0 ) ) ;
158
+ else if ( this . cols !== other . rows )
159
+ throw new RangeError ( "Dimension mismatch" ) ;
160
+
161
+ var multiplied = new Matrix ( this . rows , other . cols ) ;
162
+
163
+ for ( var row = 0 ; row < this . rows ; ++ row ) {
164
+ for ( var col = 0 ; col < other . cols ; ++ col ) {
165
+ multiplied . set ( row , col , Matrix . dot ( this . getRow ( row ) , other . getCol ( col ) ) ) ;
166
+ }
167
+ }
168
+
169
+ return multiplied ;
170
+ } ;
171
+ this . _checkRow = function ( row ) {
172
+ if ( row < 0 || row >= this . rows )
173
+ throw new RangeError ( "Row index out of range" ) ;
174
+ } ;
175
+ this . _checkCol = function ( col ) {
176
+ if ( col < 0 || col >= this . cols )
177
+ throw new RangeError ( "Column index out of range" ) ;
178
+ } ;
179
+ this . _checkIndex = function ( row , col ) {
180
+ this . _checkRow ( row ) ;
181
+ this . _checkCol ( col ) ;
182
+ }
183
+ this . _scaleRow = function ( row , scaleFactor ) {
184
+ this . _checkRow ( row ) ;
185
+ for ( var col = 0 ; col < this . cols ; ++ col )
186
+ this . data [ row ] [ col ] *= scaleFactor ;
187
+ } ;
188
+ this . _addRow = function ( row , added , scaleFactor ) {
189
+ this . _checkRow ( row ) ;
190
+ if ( added . length !== this . cols )
191
+ throw new RangeError ( "Added row must be of length " + cols . toString ( ) ) ;
192
+
193
+ scaleFactor = scaleFactor === undefined ? 1 : scaleFactor ;
194
+ for ( var col = 0 ; col < this . cols ; ++ col )
195
+ this . data [ row ] [ col ] += added [ col ] * scaleFactor ;
196
+ } ;
197
+ this . _swapRows = function ( row1 , row2 ) {
198
+ this . _checkRow ( row1 ) ;
199
+ this . _checkRow ( row2 ) ;
200
+
201
+ var tmp = this . getRow ( row1 ) . slice ( ) ;
202
+ this . setRow ( row1 , this . getRow ( row2 ) ) ;
203
+ this . setRow ( row2 , tmp ) ;
204
+ } ;
205
+ } ;
206
+
207
+ Matrix . copy = function ( matrix ) {
208
+ var clone = new Matrix ( matrix . rows , matrix . cols ) ;
209
+ for ( var row = 0 ; row < clone . rows ; ++ row )
210
+ clone . setRow ( row , matrix . getRow ( row ) ) ;
211
+ return clone ;
212
+ } ;
213
+ Matrix . colFromArray = function ( vec ) {
214
+ colVec = new Matrix ( vec . length , 1 ) ;
215
+ colVec . setCol ( 0 , vec ) ;
216
+ return colVec ;
217
+ } ;
218
+ Matrix . rowFromArray = function ( vec ) {
219
+ rowVec = new Matrix ( 1 , vec . length ) ;
220
+ rowVec . setRow ( 0 , vec ) ;
221
+ return rowVec ;
222
+ } ;
223
+ Matrix . dot = function ( vec1 , vec2 ) {
224
+ if ( vec1 . length !== vec2 . length )
225
+ throw new RangeError ( "Input vectors of unequal lengths" ) ;
226
+
227
+ var result ;
228
+
229
+ for ( var i = 0 ; i < vec1 . length ; ++ i ) result += vec1 [ i ] * vec2 [ i ] ;
230
+
231
+ return result ;
232
+ } ;
233
+ Matrix . identity = function ( w ) {
234
+ var eye = new Matrix ( w , w , true ) ;
235
+
236
+ for ( var i = 0 ; i < w ; ++ i ) eye . set ( i , i , 1 ) ;
237
+
238
+ return eye ;
239
+ } ;
0 commit comments