1require 'test/unit'
2require 'matrix'
3
4class TestMatrix < Test::Unit::TestCase
5  def setup
6    @m1 = Matrix[[1,2,3], [4,5,6]]
7    @m2 = Matrix[[1,2,3], [4,5,6]]
8    @m3 = @m1.clone
9    @m4 = Matrix[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]
10    @n1 = Matrix[[2,3,4], [5,6,7]]
11  end
12
13  def test_matrix
14    assert_equal(1, @m1[0, 0])
15    assert_equal(2, @m1[0, 1])
16    assert_equal(3, @m1[0, 2])
17    assert_equal(4, @m1[1, 0])
18    assert_equal(5, @m1[1, 1])
19    assert_equal(6, @m1[1, 2])
20  end
21
22  def test_identity
23    assert_same @m1, @m1
24    assert_not_same @m1, @m2
25    assert_not_same @m1, @m3
26    assert_not_same @m1, @m4
27    assert_not_same @m1, @n1
28  end
29
30  def test_equality
31    assert_equal @m1, @m1
32    assert_equal @m1, @m2
33    assert_equal @m1, @m3
34    assert_equal @m1, @m4
35    assert_not_equal @m1, @n1
36  end
37
38  def test_hash_equality
39    assert @m1.eql?(@m1)
40    assert @m1.eql?(@m2)
41    assert @m1.eql?(@m3)
42    assert !@m1.eql?(@m4)
43    assert !@m1.eql?(@n1)
44
45    hash = { @m1 => :value }
46    assert hash.key?(@m1)
47    assert hash.key?(@m2)
48    assert hash.key?(@m3)
49    assert !hash.key?(@m4)
50    assert !hash.key?(@n1)
51  end
52
53  def test_hash
54    assert_equal @m1.hash, @m1.hash
55    assert_equal @m1.hash, @m2.hash
56    assert_equal @m1.hash, @m3.hash
57  end
58
59  def test_rank
60    [
61      [[0]],
62      [[0], [0]],
63      [[0, 0], [0, 0]],
64      [[0, 0], [0, 0], [0, 0]],
65      [[0, 0, 0]],
66      [[0, 0, 0], [0, 0, 0]],
67      [[0, 0, 0], [0, 0, 0], [0, 0, 0]],
68      [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]],
69    ].each do |rows|
70      assert_equal 0, Matrix[*rows].rank
71    end
72
73    [
74      [[1], [0]],
75      [[1, 0], [0, 0]],
76      [[1, 0], [1, 0]],
77      [[0, 0], [1, 0]],
78      [[1, 0], [0, 0], [0, 0]],
79      [[0, 0], [1, 0], [0, 0]],
80      [[0, 0], [0, 0], [1, 0]],
81      [[1, 0], [1, 0], [0, 0]],
82      [[0, 0], [1, 0], [1, 0]],
83      [[1, 0], [1, 0], [1, 0]],
84      [[1, 0, 0]],
85      [[1, 0, 0], [0, 0, 0]],
86      [[0, 0, 0], [1, 0, 0]],
87      [[1, 0, 0], [1, 0, 0]],
88      [[1, 0, 0], [1, 0, 0]],
89      [[1, 0, 0], [0, 0, 0], [0, 0, 0]],
90      [[0, 0, 0], [1, 0, 0], [0, 0, 0]],
91      [[0, 0, 0], [0, 0, 0], [1, 0, 0]],
92      [[1, 0, 0], [1, 0, 0], [0, 0, 0]],
93      [[0, 0, 0], [1, 0, 0], [1, 0, 0]],
94      [[1, 0, 0], [0, 0, 0], [1, 0, 0]],
95      [[1, 0, 0], [1, 0, 0], [1, 0, 0]],
96      [[1, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]],
97      [[1, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]],
98      [[1, 0, 0], [1, 0, 0], [0, 0, 0], [0, 0, 0]],
99      [[1, 0, 0], [0, 0, 0], [1, 0, 0], [0, 0, 0]],
100      [[1, 0, 0], [0, 0, 0], [0, 0, 0], [1, 0, 0]],
101      [[1, 0, 0], [1, 0, 0], [1, 0, 0], [0, 0, 0]],
102      [[1, 0, 0], [0, 0, 0], [1, 0, 0], [1, 0, 0]],
103      [[1, 0, 0], [1, 0, 0], [0, 0, 0], [1, 0, 0]],
104      [[1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0]],
105
106      [[1]],
107      [[1], [1]],
108      [[1, 1]],
109      [[1, 1], [1, 1]],
110      [[1, 1], [1, 1], [1, 1]],
111      [[1, 1, 1]],
112      [[1, 1, 1], [1, 1, 1]],
113      [[1, 1, 1], [1, 1, 1], [1, 1, 1]],
114      [[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]],
115    ].each do |rows|
116      matrix = Matrix[*rows]
117      assert_equal 1, matrix.rank
118      assert_equal 1, matrix.transpose.rank
119    end
120
121    [
122      [[1, 0], [0, 1]],
123      [[1, 0], [0, 1], [0, 0]],
124      [[1, 0], [0, 1], [0, 1]],
125      [[1, 0], [0, 1], [1, 1]],
126      [[1, 0, 0], [0, 1, 0]],
127      [[1, 0, 0], [0, 0, 1]],
128      [[1, 0, 0], [0, 1, 0], [0, 0, 0]],
129      [[1, 0, 0], [0, 0, 1], [0, 0, 0]],
130
131      [[1, 0, 0], [0, 0, 0], [0, 1, 0]],
132      [[1, 0, 0], [0, 0, 0], [0, 0, 1]],
133
134      [[1, 0], [1, 1]],
135      [[1, 2], [1, 1]],
136      [[1, 2], [0, 1], [1, 1]],
137    ].each do |rows|
138      m = Matrix[*rows]
139      assert_equal 2, m.rank
140      assert_equal 2, m.transpose.rank
141    end
142
143    [
144      [[1, 0, 0], [0, 1, 0], [0, 0, 1]],
145      [[1, 1, 0], [0, 1, 1], [1, 0, 1]],
146      [[1, 1, 0], [0, 1, 1], [1, 0, 1]],
147      [[1, 1, 0], [0, 1, 1], [1, 0, 1], [0, 0, 0]],
148      [[1, 1, 0], [0, 1, 1], [1, 0, 1], [1, 1, 1]],
149      [[1, 1, 1], [1, 1, 2], [1, 3, 1], [4, 1, 1]],
150    ].each do |rows|
151      m = Matrix[*rows]
152      assert_equal 3, m.rank
153      assert_equal 3, m.transpose.rank
154    end
155  end
156
157  def test_inverse
158    assert_equal(Matrix[[-1, 1], [0, -1]], Matrix[[-1, -1], [0, -1]].inverse)
159  end
160
161  def test_determinant
162    assert_equal(45, Matrix[[7,6], [3,9]].determinant)
163    assert_equal(-18, Matrix[[2,0,1],[0,-2,2],[1,2,3]].determinant)
164  end
165
166  def test_new_matrix
167    assert_raise(TypeError) { Matrix[Object.new] }
168    o = Object.new
169    def o.to_ary; [1,2,3]; end
170    assert_equal(@m1, Matrix[o, [4,5,6]])
171  end
172
173  def test_rows
174    assert_equal(@m1, Matrix.rows([[1, 2, 3], [4, 5, 6]]))
175  end
176
177  def test_columns
178    assert_equal(@m1, Matrix.columns([[1, 4], [2, 5], [3, 6]]))
179  end
180
181  def test_diagonal
182    assert_equal(Matrix[[3,0,0],[0,2,0],[0,0,1]], Matrix.diagonal(3, 2, 1))
183    assert_equal(Matrix[[4,0,0,0],[0,3,0,0],[0,0,2,0],[0,0,0,1]], Matrix.diagonal(4, 3, 2, 1))
184  end
185
186  def test_scalar
187    assert_equal(Matrix[[2,0,0],[0,2,0],[0,0,2]], Matrix.scalar(3, 2))
188    assert_equal(Matrix[[2,0,0,0],[0,2,0,0],[0,0,2,0],[0,0,0,2]], Matrix.scalar(4, 2))
189  end
190
191  def test_identity2
192    assert_equal(Matrix[[1,0,0],[0,1,0],[0,0,1]], Matrix.identity(3))
193    assert_equal(Matrix[[1,0,0],[0,1,0],[0,0,1]], Matrix.unit(3))
194    assert_equal(Matrix[[1,0,0],[0,1,0],[0,0,1]], Matrix.I(3))
195    assert_equal(Matrix[[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]], Matrix.identity(4))
196  end
197
198  def test_zero
199    assert_equal(Matrix[[0,0,0],[0,0,0],[0,0,0]], Matrix.zero(3))
200    assert_equal(Matrix[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]], Matrix.zero(4))
201    assert_equal(Matrix[[0]], Matrix.zero(1))
202  end
203
204  def test_row_vector
205    assert_equal(Matrix[[1,2,3,4]], Matrix.row_vector([1,2,3,4]))
206  end
207
208  def test_column_vector
209    assert_equal(Matrix[[1],[2],[3],[4]], Matrix.column_vector([1,2,3,4]))
210  end
211
212  def test_empty
213    m = Matrix.empty(2, 0)
214    assert_equal(Matrix[ [], [] ], m)
215    n = Matrix.empty(0, 3)
216    assert_equal(Matrix.columns([ [], [], [] ]), n)
217    assert_equal(Matrix[[0, 0, 0], [0, 0, 0]], m * n)
218  end
219
220  def test_row
221    assert_equal(Vector[1, 2, 3], @m1.row(0))
222    assert_equal(Vector[4, 5, 6], @m1.row(1))
223    a = []; @m1.row(0) {|x| a << x }
224    assert_equal([1, 2, 3], a)
225  end
226
227  def test_column
228    assert_equal(Vector[1, 4], @m1.column(0))
229    assert_equal(Vector[2, 5], @m1.column(1))
230    assert_equal(Vector[3, 6], @m1.column(2))
231    a = []; @m1.column(0) {|x| a << x }
232    assert_equal([1, 4], a)
233  end
234
235  def test_collect
236    assert_equal(Matrix[[1, 4, 9], [16, 25, 36]], @m1.collect {|x| x ** 2 })
237  end
238
239  def test_minor
240    assert_equal(Matrix[[1, 2], [4, 5]], @m1.minor(0..1, 0..1))
241    assert_equal(Matrix[[2], [5]], @m1.minor(0..1, 1..1))
242    assert_equal(Matrix[[4, 5]], @m1.minor(1..1, 0..1))
243    assert_equal(Matrix[[1, 2], [4, 5]], @m1.minor(0, 2, 0, 2))
244    assert_equal(Matrix[[4, 5]], @m1.minor(1, 1, 0, 2))
245    assert_equal(Matrix[[2], [5]], @m1.minor(0, 2, 1, 1))
246    assert_raise(ArgumentError) { @m1.minor(0) }
247  end
248
249  def test_regular?
250    assert(Matrix[[1, 0], [0, 1]].regular?)
251    assert(Matrix[[1, 0, 0], [0, 1, 0], [0, 0, 1]].regular?)
252    assert(!Matrix[[1, 0, 0], [0, 0, 1], [0, 0, 1]].regular?)
253  end
254
255  def test_singular?
256    assert(!Matrix[[1, 0], [0, 1]].singular?)
257    assert(!Matrix[[1, 0, 0], [0, 1, 0], [0, 0, 1]].singular?)
258    assert(Matrix[[1, 0, 0], [0, 0, 1], [0, 0, 1]].singular?)
259  end
260
261  def test_square?
262    assert(Matrix[[1, 0], [0, 1]].square?)
263    assert(Matrix[[1, 0, 0], [0, 1, 0], [0, 0, 1]].square?)
264    assert(Matrix[[1, 0, 0], [0, 0, 1], [0, 0, 1]].square?)
265    assert(!Matrix[[1, 0, 0], [0, 1, 0]].square?)
266  end
267
268  def test_mul
269    assert_equal(Matrix[[2,4],[6,8]], Matrix[[2,4],[6,8]] * Matrix.I(2))
270    assert_equal(Matrix[[4,8],[12,16]], Matrix[[2,4],[6,8]] * 2)
271    assert_equal(Matrix[[4,8],[12,16]], 2 * Matrix[[2,4],[6,8]])
272    assert_equal(Matrix[[14,32],[32,77]], @m1 * @m1.transpose)
273    assert_equal(Matrix[[17,22,27],[22,29,36],[27,36,45]], @m1.transpose * @m1)
274    assert_equal(Vector[14,32], @m1 * Vector[1,2,3])
275    o = Object.new
276    def o.coerce(m)
277      [m, m.transpose]
278    end
279    assert_equal(Matrix[[14,32],[32,77]], @m1 * o)
280  end
281
282  def test_add
283    assert_equal(Matrix[[6,0],[-4,12]], Matrix.scalar(2,5) + Matrix[[1,0],[-4,7]])
284    assert_equal(Matrix[[3,5,7],[9,11,13]], @m1 + @n1)
285    assert_equal(Matrix[[3,5,7],[9,11,13]], @n1 + @m1)
286    assert_equal(Matrix[[2],[4],[6]], Matrix[[1],[2],[3]] + Vector[1,2,3])
287    assert_raise(Matrix::ErrOperationNotDefined) { @m1 + 1 }
288    o = Object.new
289    def o.coerce(m)
290      [m, m]
291    end
292    assert_equal(Matrix[[2,4,6],[8,10,12]], @m1 + o)
293  end
294
295  def test_sub
296    assert_equal(Matrix[[4,0],[4,-2]], Matrix.scalar(2,5) - Matrix[[1,0],[-4,7]])
297    assert_equal(Matrix[[-1,-1,-1],[-1,-1,-1]], @m1 - @n1)
298    assert_equal(Matrix[[1,1,1],[1,1,1]], @n1 - @m1)
299    assert_equal(Matrix[[0],[0],[0]], Matrix[[1],[2],[3]] - Vector[1,2,3])
300    assert_raise(Matrix::ErrOperationNotDefined) { @m1 - 1 }
301    o = Object.new
302    def o.coerce(m)
303      [m, m]
304    end
305    assert_equal(Matrix[[0,0,0],[0,0,0]], @m1 - o)
306  end
307
308  def test_div
309    assert_equal(Matrix[[0,1,1],[2,2,3]], @m1 / 2)
310    assert_equal(Matrix[[1,1],[1,1]], Matrix[[2,2],[2,2]] / Matrix.scalar(2,2))
311    o = Object.new
312    def o.coerce(m)
313      [m, Matrix.scalar(2,2)]
314    end
315    assert_equal(Matrix[[1,1],[1,1]], Matrix[[2,2],[2,2]] / o)
316  end
317
318  def test_exp
319    assert_equal(Matrix[[67,96],[48,99]], Matrix[[7,6],[3,9]] ** 2)
320    assert_equal(Matrix.I(5), Matrix.I(5) ** -1)
321    assert_raise(Matrix::ErrOperationNotDefined) { Matrix.I(5) ** Object.new }
322  end
323
324  def test_det
325    assert_equal(45, Matrix[[7,6],[3,9]].det)
326    assert_equal(0, Matrix[[0,0],[0,0]].det)
327    assert_equal(-7, Matrix[[0,0,1],[0,7,6],[1,3,9]].det)
328    assert_equal(42, Matrix[[7,0,1,0,12],[8,1,1,9,1],[4,0,0,-7,17],[-1,0,0,-4,8],[10,1,1,8,6]].det)
329  end
330
331  def test_rank2
332    assert_equal(2, Matrix[[7,6],[3,9]].rank)
333    assert_equal(0, Matrix[[0,0],[0,0]].rank)
334    assert_equal(3, Matrix[[0,0,1],[0,7,6],[1,3,9]].rank)
335    assert_equal(1, Matrix[[0,1],[0,1],[0,1]].rank)
336    assert_equal(2, @m1.rank)
337  end
338
339  def test_trace
340    assert_equal(1+5+9, Matrix[[1,2,3],[4,5,6],[7,8,9]].trace)
341  end
342
343  def test_transpose
344    assert_equal(Matrix[[1,4],[2,5],[3,6]], @m1.transpose)
345  end
346
347  def test_row_vectors
348    assert_equal([Vector[1,2,3], Vector[4,5,6]], @m1.row_vectors)
349  end
350
351  def test_column_vectors
352    assert_equal([Vector[1,4], Vector[2,5], Vector[3,6]], @m1.column_vectors)
353  end
354
355  def test_to_s
356    assert_equal("Matrix[[1, 2, 3], [4, 5, 6]]", @m1.to_s)
357    assert_equal("Matrix.empty(0, 0)", Matrix[].to_s)
358    assert_equal("Matrix.empty(1, 0)", Matrix[[]].to_s)
359  end
360
361  def test_inspect
362    assert_equal("Matrix[[1, 2, 3], [4, 5, 6]]", @m1.inspect)
363    assert_equal("Matrix.empty(0, 0)", Matrix[].inspect)
364    assert_equal("Matrix.empty(1, 0)", Matrix[[]].inspect)
365  end
366
367  def test_scalar_add
368    s1 = @m1.coerce(1).first
369    assert_equal(Matrix[[1]], (s1 + 0) * Matrix[[1]])
370    assert_raise(Matrix::ErrOperationNotDefined) { s1 + Vector[0] }
371    assert_raise(Matrix::ErrOperationNotDefined) { s1 + Matrix[[0]] }
372    o = Object.new
373    def o.coerce(x)
374      [1, 1]
375    end
376    assert_equal(2, s1 + o)
377  end
378
379  def test_scalar_sub
380    s1 = @m1.coerce(1).first
381    assert_equal(Matrix[[1]], (s1 - 0) * Matrix[[1]])
382    assert_raise(Matrix::ErrOperationNotDefined) { s1 - Vector[0] }
383    assert_raise(Matrix::ErrOperationNotDefined) { s1 - Matrix[[0]] }
384    o = Object.new
385    def o.coerce(x)
386      [1, 1]
387    end
388    assert_equal(0, s1 - o)
389  end
390
391  def test_scalar_mul
392    s1 = @m1.coerce(1).first
393    assert_equal(Matrix[[1]], (s1 * 1) * Matrix[[1]])
394    assert_equal(Vector[2], s1 * Vector[2])
395    assert_equal(Matrix[[2]], s1 * Matrix[[2]])
396    o = Object.new
397    def o.coerce(x)
398      [1, 1]
399    end
400    assert_equal(1, s1 * o)
401  end
402
403  def test_scalar_div
404    s1 = @m1.coerce(1).first
405    assert_equal(Matrix[[1]], (s1 / 1) * Matrix[[1]])
406    assert_raise(Matrix::ErrOperationNotDefined) { s1 / Vector[0] }
407    assert_equal(Matrix[[Rational(1,2)]], s1 / Matrix[[2]])
408    o = Object.new
409    def o.coerce(x)
410      [1, 1]
411    end
412    assert_equal(1, s1 / o)
413  end
414
415  def test_scalar_pow
416    s1 = @m1.coerce(1).first
417    assert_equal(Matrix[[1]], (s1 ** 1) * Matrix[[1]])
418    assert_raise(Matrix::ErrOperationNotDefined) { s1 ** Vector[0] }
419    assert_raise(Matrix::ErrOperationNotImplemented) { s1 ** Matrix[[1]] }
420    o = Object.new
421    def o.coerce(x)
422      [1, 1]
423    end
424    assert_equal(1, s1 ** o)
425  end
426end
427