stick 1.3.2 → 1.3.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,1408 @@
1
+ #!/usr/local/bin/ruby
2
+ #--
3
+ # matrix.rb -
4
+ # $Release Version: 1.0$
5
+ # $Revision: 1.13 $
6
+ # $Date: 2001/12/09 14:22:23 $
7
+ # Original Version from Smalltalk-80 version
8
+ # on July 23, 1985 at 8:37:17 am
9
+ # by Keiju ISHITSUKA
10
+ #++
11
+ #
12
+ # = matrix.rb
13
+ #
14
+ # An implementation of Matrix and Vector classes.
15
+ #
16
+ # Author:: Keiju ISHITSUKA
17
+ # Documentation:: Gavin Sinclair (sourced from <i>Ruby in a Nutshell</i> (Matsumoto, O'Reilly))
18
+ #
19
+ # See classes Matrix and Vector for documentation.
20
+ #
21
+
22
+
23
+ require "e2mmap.rb"
24
+
25
+ module Stick
26
+
27
+ module ExceptionForMatrix # :nodoc:
28
+ extend Exception2MessageMapper
29
+ def_e2message(TypeError, "wrong argument type %s (expected %s)")
30
+ def_e2message(ArgumentError, "Wrong # of arguments(%d for %d)")
31
+
32
+ def_exception("ErrDimensionMismatch", "\#{self.name} dimension mismatch")
33
+ def_exception("ErrNotRegular", "Not Regular Matrix")
34
+ def_exception("ErrOperationNotDefined", "This operation(%s) can\\'t defined")
35
+ end
36
+
37
+ #
38
+ # The +Matrix+ class represents a mathematical matrix, and provides methods for creating
39
+ # special-case matrices (zero, identity, diagonal, singular, vector), operating on them
40
+ # arithmetically and algebraically, and determining their mathematical properties (trace, rank,
41
+ # inverse, determinant).
42
+ #
43
+ # Note that although matrices should theoretically be rectangular, this is not
44
+ # enforced by the class.
45
+ #
46
+ # Also note that the determinant of integer matrices may be incorrectly calculated unless you
47
+ # also <tt>require 'mathn'</tt>. This may be fixed in the future.
48
+ #
49
+ # == Method Catalogue
50
+ #
51
+ # To create a matrix:
52
+ # * <tt> Matrix[*rows] </tt>
53
+ # * <tt> Matrix.[](*rows) </tt>
54
+ # * <tt> Matrix.rows(rows, copy = true) </tt>
55
+ # * <tt> Matrix.columns(columns) </tt>
56
+ # * <tt> Matrix.diagonal(*values) </tt>
57
+ # * <tt> Matrix.scalar(n, value) </tt>
58
+ # * <tt> Matrix.scalar(n, value) </tt>
59
+ # * <tt> Matrix.identity(n) </tt>
60
+ # * <tt> Matrix.unit(n) </tt>
61
+ # * <tt> Matrix.I(n) </tt>
62
+ # * <tt> Matrix.zero(n) </tt>
63
+ # * <tt> Matrix.row_vector(row) </tt>
64
+ # * <tt> Matrix.column_vector(column) </tt>
65
+ #
66
+ # To access Matrix elements/columns/rows/submatrices/properties:
67
+ # * <tt> [](i, j) </tt>
68
+ # * <tt> #row_size </tt>
69
+ # * <tt> #column_size </tt>
70
+ # * <tt> #row(i) </tt>
71
+ # * <tt> #column(j) </tt>
72
+ # * <tt> #collect </tt>
73
+ # * <tt> #map </tt>
74
+ # * <tt> #minor(*param) </tt>
75
+ #
76
+ # Properties of a matrix:
77
+ # * <tt> #regular? </tt>
78
+ # * <tt> #singular? </tt>
79
+ # * <tt> #square? </tt>
80
+ #
81
+ # Matrix arithmetic:
82
+ # * <tt> *(m) </tt>
83
+ # * <tt> +(m) </tt>
84
+ # * <tt> -(m) </tt>
85
+ # * <tt> #/(m) </tt>
86
+ # * <tt> #inverse </tt>
87
+ # * <tt> #inv </tt>
88
+ # * <tt> ** </tt>
89
+ #
90
+ # Matrix functions:
91
+ # * <tt> #determinant </tt>
92
+ # * <tt> #det </tt>
93
+ # * <tt> #rank </tt>
94
+ # * <tt> #trace </tt>
95
+ # * <tt> #tr </tt>
96
+ # * <tt> #transpose </tt>
97
+ # * <tt> #t </tt>
98
+ #
99
+ # Conversion to other data types:
100
+ # * <tt> #coerce(other) </tt>
101
+ # * <tt> #row_vectors </tt>
102
+ # * <tt> #column_vectors </tt>
103
+ # * <tt> #to_a </tt>
104
+ #
105
+ # String representations:
106
+ # * <tt> #to_s </tt>
107
+ # * <tt> #inspect </tt>
108
+ #
109
+ class Matrix
110
+ @RCS_ID='-$Id: matrix.rb,v 1.13 2001/12/09 14:22:23 keiju Exp keiju $-'
111
+
112
+ # extend Exception2MessageMapper
113
+ include ExceptionForMatrix
114
+
115
+ # instance creations
116
+ private_class_method :new
117
+
118
+ #
119
+ # Creates a matrix where each argument is a row.
120
+ # Matrix[ [25, 93], [-1, 66] ]
121
+ # => 25 93
122
+ # -1 66
123
+ #
124
+ def Matrix.[](*rows)
125
+ new(:init_rows, rows, false)
126
+ end
127
+
128
+ #
129
+ # Creates a matrix where +rows+ is an array of arrays, each of which is a row
130
+ # to the matrix. If the optional argument +copy+ is false, use the given
131
+ # arrays as the internal structure of the matrix without copying.
132
+ # Matrix.rows([[25, 93], [-1, 66]])
133
+ # => 25 93
134
+ # -1 66
135
+ def Matrix.rows(rows, copy = true)
136
+ new(:init_rows, rows, copy)
137
+ end
138
+
139
+ #
140
+ # Creates a matrix using +columns+ as an array of column vectors.
141
+ # Matrix.columns([[25, 93], [-1, 66]])
142
+ # => 25 -1
143
+ # 93 66
144
+ #
145
+ #
146
+ def Matrix.columns(columns)
147
+ rows = (0 .. columns[0].size - 1).collect {
148
+ |i|
149
+ (0 .. columns.size - 1).collect {
150
+ |j|
151
+ columns[j][i]
152
+ }
153
+ }
154
+ Matrix.rows(rows, false)
155
+ end
156
+
157
+ #
158
+ # Creates a matrix where the diagonal elements are composed of +values+.
159
+ # Matrix.diagonal(9, 5, -3)
160
+ # => 9 0 0
161
+ # 0 5 0
162
+ # 0 0 -3
163
+ #
164
+ def Matrix.diagonal(*values)
165
+ size = values.size
166
+ rows = (0 .. size - 1).collect {
167
+ |j|
168
+ row = Array.new(size).fill(0, 0, size)
169
+ row[j] = values[j]
170
+ row
171
+ }
172
+ rows(rows, false)
173
+ end
174
+
175
+ #
176
+ # Creates an +n+ by +n+ diagonal matrix where each diagonal element is
177
+ # +value+.
178
+ # Matrix.scalar(2, 5)
179
+ # => 5 0
180
+ # 0 5
181
+ #
182
+ def Matrix.scalar(n, value)
183
+ Matrix.diagonal(*Array.new(n).fill(value, 0, n))
184
+ end
185
+
186
+ #
187
+ # Creates an +n+ by +n+ identity matrix.
188
+ # Matrix.identity(2)
189
+ # => 1 0
190
+ # 0 1
191
+ #
192
+ def Matrix.identity(n)
193
+ Matrix.scalar(n, 1)
194
+ end
195
+ class << Matrix
196
+ alias unit identity
197
+ alias I identity
198
+ end
199
+
200
+ #
201
+ # Creates an +n+ by +n+ zero matrix.
202
+ # Matrix.zero(2)
203
+ # => 0 0
204
+ # 0 0
205
+ #
206
+ def Matrix.zero(n)
207
+ Matrix.scalar(n, 0)
208
+ end
209
+
210
+ #
211
+ # Creates a single-row matrix where the values of that row are as given in
212
+ # +row+.
213
+ # Matrix.row_vector([4,5,6])
214
+ # => 4 5 6
215
+ #
216
+ def Matrix.row_vector(row)
217
+ case row
218
+ when Vector
219
+ Matrix.rows([row.to_a], false)
220
+ when Array
221
+ Matrix.rows([row.dup], false)
222
+ else
223
+ Matrix.rows([[row]], false)
224
+ end
225
+ end
226
+
227
+ #
228
+ # Creates a single-column matrix where the values of that column are as given
229
+ # in +column+.
230
+ # Matrix.column_vector([4,5,6])
231
+ # => 4
232
+ # 5
233
+ # 6
234
+ #
235
+ def Matrix.column_vector(column)
236
+ case column
237
+ when Vector
238
+ Matrix.columns([column.to_a])
239
+ when Array
240
+ Matrix.columns([column])
241
+ else
242
+ Matrix.columns([[column]])
243
+ end
244
+ end
245
+
246
+ #
247
+ # This method is used by the other methods that create matrices, and is of no
248
+ # use to general users.
249
+ #
250
+ def initialize(init_method, *argv)
251
+ self.send(init_method, *argv)
252
+ end
253
+
254
+ def init_rows(rows, copy)
255
+ if copy
256
+ @rows = rows.collect{|row| row.dup}
257
+ else
258
+ @rows = rows
259
+ end
260
+ self
261
+ end
262
+ private :init_rows
263
+
264
+ #
265
+ # Returns element (+i+,+j+) of the matrix. That is: row +i+, column +j+.
266
+ #
267
+ def [](i, j)
268
+ @rows[i][j]
269
+ end
270
+ alias element []
271
+ alias component []
272
+
273
+ def []=(i, j, v)
274
+ @rows[i][j] = v
275
+ end
276
+ alias set_element []=
277
+ alias set_component []=
278
+ private :[]=, :set_element, :set_component
279
+
280
+ #
281
+ # Returns the number of rows.
282
+ #
283
+ def row_size
284
+ @rows.size
285
+ end
286
+
287
+ #
288
+ # Returns the number of columns. Note that it is possible to construct a
289
+ # matrix with uneven columns (e.g. Matrix[ [1,2,3], [4,5] ]), but this is
290
+ # mathematically unsound. This method uses the first row to determine the
291
+ # result.
292
+ #
293
+ def column_size
294
+ @rows[0].size
295
+ end
296
+
297
+ #
298
+ # Returns row vector number +i+ of the matrix as a Vector (starting at 0 like
299
+ # an array). When a block is given, the elements of that vector are iterated.
300
+ #
301
+ def row(i) # :yield: e
302
+ if block_given?
303
+ for e in @rows[i]
304
+ yield e
305
+ end
306
+ else
307
+ Vector.elements(@rows[i])
308
+ end
309
+ end
310
+
311
+ #
312
+ # Returns column vector number +j+ of the matrix as a Vector (starting at 0
313
+ # like an array). When a block is given, the elements of that vector are
314
+ # iterated.
315
+ #
316
+ def column(j) # :yield: e
317
+ if block_given?
318
+ 0.upto(row_size - 1) do
319
+ |i|
320
+ yield @rows[i][j]
321
+ end
322
+ else
323
+ col = (0 .. row_size - 1).collect {
324
+ |i|
325
+ @rows[i][j]
326
+ }
327
+ Vector.elements(col, false)
328
+ end
329
+ end
330
+
331
+ #
332
+ # Returns a matrix that is the result of iteration of the given block over all
333
+ # elements of the matrix.
334
+ # Matrix[ [1,2], [3,4] ].collect { |e| e**2 }
335
+ # => 1 4
336
+ # 9 16
337
+ #
338
+ def collect # :yield: e
339
+ rows = @rows.collect{|row| row.collect{|e| yield e}}
340
+ Matrix.rows(rows, false)
341
+ end
342
+ alias map collect
343
+
344
+ #
345
+ # Returns a section of the matrix. The parameters are either:
346
+ # * start_row, nrows, start_col, ncols; OR
347
+ # * col_range, row_range
348
+ #
349
+ # Matrix.diagonal(9, 5, -3).minor(0..1, 0..2)
350
+ # => 9 0 0
351
+ # 0 5 0
352
+ #
353
+ def minor(*param)
354
+ case param.size
355
+ when 2
356
+ from_row = param[0].first
357
+ size_row = param[0].end - from_row
358
+ size_row += 1 unless param[0].exclude_end?
359
+ from_col = param[1].first
360
+ size_col = param[1].end - from_col
361
+ size_col += 1 unless param[1].exclude_end?
362
+ when 4
363
+ from_row = param[0]
364
+ size_row = param[1]
365
+ from_col = param[2]
366
+ size_col = param[3]
367
+ else
368
+ Matrix.Raise ArgumentError, param.inspect
369
+ end
370
+
371
+ rows = @rows[from_row, size_row].collect{
372
+ |row|
373
+ row[from_col, size_col]
374
+ }
375
+ Matrix.rows(rows, false)
376
+ end
377
+
378
+ #--
379
+ # TESTING -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
380
+ #++
381
+
382
+ #
383
+ # Returns +true+ if this is a regular matrix.
384
+ #
385
+ def regular?
386
+ square? and rank == column_size
387
+ end
388
+
389
+ #
390
+ # Returns +true+ is this is a singular (i.e. non-regular) matrix.
391
+ #
392
+ def singular?
393
+ not regular?
394
+ end
395
+
396
+ #
397
+ # Returns +true+ is this is a square matrix. See note in column_size about this
398
+ # being unreliable, though.
399
+ #
400
+ def square?
401
+ column_size == row_size
402
+ end
403
+
404
+ #--
405
+ # OBJECT METHODS -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
406
+ #++
407
+
408
+ #
409
+ # Returns +true+ if and only if the two matrices contain equal elements.
410
+ #
411
+ def ==(other)
412
+ return false unless Matrix === other
413
+
414
+ other.compare_by_row_vectors(@rows)
415
+ end
416
+ alias eql? ==
417
+
418
+ #
419
+ # Not really intended for general consumption.
420
+ #
421
+ def compare_by_row_vectors(rows)
422
+ return false unless @rows.size == rows.size
423
+
424
+ 0.upto(@rows.size - 1) do
425
+ |i|
426
+ return false unless @rows[i] == rows[i]
427
+ end
428
+ true
429
+ end
430
+
431
+ #
432
+ # Returns a clone of the matrix, so that the contents of each do not reference
433
+ # identical objects.
434
+ #
435
+ def clone
436
+ Matrix.rows(@rows)
437
+ end
438
+
439
+ #
440
+ # Returns a hash-code for the matrix.
441
+ #
442
+ def hash
443
+ value = 0
444
+ for row in @rows
445
+ for e in row
446
+ value ^= e.hash
447
+ end
448
+ end
449
+ return value
450
+ end
451
+
452
+ #--
453
+ # ARITHMETIC -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
454
+ #++
455
+
456
+ #
457
+ # Matrix multiplication.
458
+ # Matrix[[2,4], [6,8]] * Matrix.identity(2)
459
+ # => 2 4
460
+ # 6 8
461
+ #
462
+ def *(m) # m is matrix or vector or number
463
+ case(m)
464
+ when Numeric
465
+ rows = @rows.collect {
466
+ |row|
467
+ row.collect {
468
+ |e|
469
+ e * m
470
+ }
471
+ }
472
+ return Matrix.rows(rows, false)
473
+ when Vector
474
+ m = Matrix.column_vector(m)
475
+ r = self * m
476
+ return r.column(0)
477
+ when Matrix
478
+ Matrix.Raise ErrDimensionMismatch if column_size != m.row_size
479
+
480
+ rows = (0 .. row_size - 1).collect {
481
+ |i|
482
+ (0 .. m.column_size - 1).collect {
483
+ |j|
484
+ vij = 0
485
+ 0.upto(column_size - 1) do
486
+ |k|
487
+ vij += self[i, k] * m[k, j]
488
+ end
489
+ vij
490
+ }
491
+ }
492
+ return Matrix.rows(rows, false)
493
+ else
494
+ x, y = m.coerce(self)
495
+ return x * y
496
+ end
497
+ end
498
+
499
+ #
500
+ # Matrix addition.
501
+ # Matrix.scalar(2,5) + Matrix[[1,0], [-4,7]]
502
+ # => 6 0
503
+ # -4 12
504
+ #
505
+ def +(m)
506
+ case m
507
+ when Numeric
508
+ Matrix.Raise ErrOperationNotDefined, "+"
509
+ when Vector
510
+ m = Matrix.column_vector(m)
511
+ when Matrix
512
+ else
513
+ x, y = m.coerce(self)
514
+ return x + y
515
+ end
516
+
517
+ Matrix.Raise ErrDimensionMismatch unless row_size == m.row_size and column_size == m.column_size
518
+
519
+ rows = (0 .. row_size - 1).collect {
520
+ |i|
521
+ (0 .. column_size - 1).collect {
522
+ |j|
523
+ self[i, j] + m[i, j]
524
+ }
525
+ }
526
+ Matrix.rows(rows, false)
527
+ end
528
+
529
+ #
530
+ # Matrix subtraction.
531
+ # Matrix[[1,5], [4,2]] - Matrix[[9,3], [-4,1]]
532
+ # => -8 2
533
+ # 8 1
534
+ #
535
+ def -(m)
536
+ case m
537
+ when Numeric
538
+ Matrix.Raise ErrOperationNotDefined, "-"
539
+ when Vector
540
+ m = Matrix.column_vector(m)
541
+ when Matrix
542
+ else
543
+ x, y = m.coerce(self)
544
+ return x - y
545
+ end
546
+
547
+ Matrix.Raise ErrDimensionMismatch unless row_size == m.row_size and column_size == m.column_size
548
+
549
+ rows = (0 .. row_size - 1).collect {
550
+ |i|
551
+ (0 .. column_size - 1).collect {
552
+ |j|
553
+ self[i, j] - m[i, j]
554
+ }
555
+ }
556
+ Matrix.rows(rows, false)
557
+ end
558
+
559
+ #
560
+ # Matrix division (multiplication by the inverse).
561
+ # Matrix[[7,6], [3,9]] / Matrix[[2,9], [3,1]]
562
+ # => -7 1
563
+ # -3 -6
564
+ #
565
+ def /(other)
566
+ case other
567
+ when Numeric
568
+ rows = @rows.collect {
569
+ |row|
570
+ row.collect {
571
+ |e|
572
+ e / other
573
+ }
574
+ }
575
+ return Matrix.rows(rows, false)
576
+ when Matrix
577
+ return self * other.inverse
578
+ else
579
+ x, y = other.coerce(self)
580
+ rerurn x / y
581
+ end
582
+ end
583
+
584
+ #
585
+ # Returns the inverse of the matrix.
586
+ # Matrix[[1, 2], [2, 1]].inverse
587
+ # => -1 1
588
+ # 0 -1
589
+ #
590
+ def inverse
591
+ Matrix.Raise ErrDimensionMismatch unless square?
592
+ Matrix.I(row_size).inverse_from(self)
593
+ end
594
+ alias inv inverse
595
+
596
+ #
597
+ # Not for public consumption?
598
+ #
599
+ def inverse_from(src)
600
+ size = row_size - 1
601
+ a = src.to_a
602
+
603
+ for k in 0..size
604
+ i = k
605
+ akk = a[k][k].abs
606
+ for j in (k+1)..size
607
+ v = a[j][k].abs
608
+ if v > akk
609
+ i = j
610
+ akk = v
611
+ end
612
+ end
613
+ Matrix.Raise ErrNotRegular if akk == 0
614
+ if i != k
615
+ a[i], a[k] = a[k], a[i]
616
+ @rows[i], @rows[k] = @rows[k], @rows[i]
617
+ end
618
+ akk = a[k][k]
619
+
620
+ for i in 0 .. size
621
+ next if i == k
622
+ q = a[i][k].quo(akk)
623
+ a[i][k] = 0
624
+
625
+ (k + 1).upto(size) do
626
+ |j|
627
+ a[i][j] -= a[k][j] * q
628
+ end
629
+ 0.upto(size) do
630
+ |j|
631
+ @rows[i][j] -= @rows[k][j] * q
632
+ end
633
+ end
634
+
635
+ (k + 1).upto(size) do
636
+ |j|
637
+ a[k][j] = a[k][j].quo(akk)
638
+ end
639
+ 0.upto(size) do
640
+ |j|
641
+ @rows[k][j] = @rows[k][j].quo(akk)
642
+ end
643
+ end
644
+ self
645
+ end
646
+ #alias reciprocal inverse
647
+
648
+ #
649
+ # Matrix exponentiation. Defined for integer powers only. Equivalent to
650
+ # multiplying the matrix by itself N times.
651
+ # Matrix[[7,6], [3,9]] ** 2
652
+ # => 67 96
653
+ # 48 99
654
+ #
655
+ def ** (other)
656
+ if other.kind_of?(Integer)
657
+ x = self
658
+ if other <= 0
659
+ x = self.inverse
660
+ return Matrix.identity(self.column_size) if other == 0
661
+ other = -other
662
+ end
663
+ z = x
664
+ n = other - 1
665
+ while n != 0
666
+ while (div, mod = n.divmod(2)
667
+ mod == 0)
668
+ x = x * x
669
+ n = div
670
+ end
671
+ z *= x
672
+ n -= 1
673
+ end
674
+ z
675
+ elsif other.kind_of?(Float) || defined?(Rational) && other.kind_of?(Rational)
676
+ Matrix.Raise ErrOperationNotDefined, "**"
677
+ else
678
+ Matrix.Raise ErrOperationNotDefined, "**"
679
+ end
680
+ end
681
+
682
+ #--
683
+ # MATRIX FUNCTIONS -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
684
+ #++
685
+
686
+ #
687
+ # Returns the determinant of the matrix. If the matrix is not square, the
688
+ # result is 0. This method's algorism is Gaussian elimination method
689
+ # and using Numeric#quo(). Beware that using Float values, with their
690
+ # usual lack of precision, can affect the value returned by this method. Use
691
+ # Rational values or Matrix#det_e instead if this is important to you.
692
+ #
693
+ # Matrix[[7,6], [3,9]].determinant
694
+ # => 63.0
695
+ #
696
+ def determinant
697
+ return 0 unless square?
698
+
699
+ size = row_size - 1
700
+ a = to_a
701
+
702
+ det = 1
703
+ k = 0
704
+ begin
705
+ if (akk = a[k][k]) == 0
706
+ i = k
707
+ begin
708
+ return 0 if (i += 1) > size
709
+ end while a[i][k] == 0
710
+ a[i], a[k] = a[k], a[i]
711
+ akk = a[k][k]
712
+ det *= -1
713
+ end
714
+ (k + 1).upto(size) do
715
+ |i|
716
+ q = a[i][k].quo(akk)
717
+ (k + 1).upto(size) do
718
+ |j|
719
+ a[i][j] -= a[k][j] * q
720
+ end
721
+ end
722
+ det *= akk
723
+ end while (k += 1) <= size
724
+ det
725
+ end
726
+ alias det determinant
727
+
728
+ #
729
+ # Returns the determinant of the matrix. If the matrix is not square, the
730
+ # result is 0. This method's algorism is Gaussian elimination method.
731
+ # This method uses Euclidean algorism. If all elements are integer,
732
+ # really exact value. But, if an element is a float, can't return
733
+ # exact value.
734
+ #
735
+ # Matrix[[7,6], [3,9]].determinant
736
+ # => 63
737
+ #
738
+ def determinant_e
739
+ return 0 unless square?
740
+
741
+ size = row_size - 1
742
+ a = to_a
743
+
744
+ det = 1
745
+ k = 0
746
+ begin
747
+ if a[k][k].zero?
748
+ i = k
749
+ begin
750
+ return 0 if (i += 1) > size
751
+ end while a[i][k].zero?
752
+ a[i], a[k] = a[k], a[i]
753
+ det *= -1
754
+ end
755
+ (k + 1).upto(size) do |i|
756
+ q = a[i][k].quo(a[k][k])
757
+ k.upto(size) do |j|
758
+ a[i][j] -= a[k][j] * q
759
+ end
760
+ unless a[i][k].zero?
761
+ a[i], a[k] = a[k], a[i]
762
+ det *= -1
763
+ redo
764
+ end
765
+ end
766
+ det *= a[k][k]
767
+ end while (k += 1) <= size
768
+ det
769
+ end
770
+ alias det_e determinant_e
771
+
772
+ #
773
+ # Returns the rank of the matrix. Beware that using Float values,
774
+ # probably return faild value. Use Rational values or Matrix#rank_e
775
+ # for getting exact result.
776
+ #
777
+ # Matrix[[7,6], [3,9]].rank
778
+ # => 2
779
+ #
780
+ def rank
781
+ if column_size > row_size
782
+ a = transpose.to_a
783
+ a_column_size = row_size
784
+ a_row_size = column_size
785
+ else
786
+ a = to_a
787
+ a_column_size = column_size
788
+ a_row_size = row_size
789
+ end
790
+ rank = 0
791
+ k = 0
792
+ begin
793
+ if (akk = a[k][k]) == 0
794
+ i = k
795
+ exists = true
796
+ begin
797
+ if (i += 1) > a_column_size - 1
798
+ exists = false
799
+ break
800
+ end
801
+ end while a[i][k] == 0
802
+ if exists
803
+ a[i], a[k] = a[k], a[i]
804
+ akk = a[k][k]
805
+ else
806
+ i = k
807
+ exists = true
808
+ begin
809
+ if (i += 1) > a_row_size - 1
810
+ exists = false
811
+ break
812
+ end
813
+ end while a[k][i] == 0
814
+ if exists
815
+ k.upto(a_column_size - 1) do
816
+ |j|
817
+ a[j][k], a[j][i] = a[j][i], a[j][k]
818
+ end
819
+ akk = a[k][k]
820
+ else
821
+ next
822
+ end
823
+ end
824
+ end
825
+ (k + 1).upto(a_row_size - 1) do
826
+ |i|
827
+ q = a[i][k].quo(akk)
828
+ (k + 1).upto(a_column_size - 1) do
829
+ |j|
830
+ a[i][j] -= a[k][j] * q
831
+ end
832
+ end
833
+ rank += 1
834
+ end while (k += 1) <= a_column_size - 1
835
+ return rank
836
+ end
837
+
838
+ #
839
+ # Returns the rank of the matrix. This method uses Euclidean
840
+ # algorism. If all elements are integer, really exact value. But, if
841
+ # an element is a float, can't return exact value.
842
+ #
843
+ # Matrix[[7,6], [3,9]].rank
844
+ # => 2
845
+ #
846
+ def rank_e
847
+ a = to_a
848
+ a_column_size = column_size
849
+ a_row_size = row_size
850
+ pi = 0
851
+ (0 ... a_column_size).each do |j|
852
+ if i = (pi ... a_row_size).find{|i0| !a[i0][j].zero?}
853
+ if i != pi
854
+ a[pi], a[i] = a[i], a[pi]
855
+ end
856
+ (pi + 1 ... a_row_size).each do |k|
857
+ q = a[k][j].quo(a[pi][j])
858
+ (pi ... a_column_size).each do |j0|
859
+ a[k][j0] -= q * a[pi][j0]
860
+ end
861
+ if k > pi && !a[k][j].zero?
862
+ a[k], a[pi] = a[pi], a[k]
863
+ redo
864
+ end
865
+ end
866
+ pi += 1
867
+ end
868
+ end
869
+ pi
870
+ end
871
+
872
+
873
+ #
874
+ # Returns the trace (sum of diagonal elements) of the matrix.
875
+ # Matrix[[7,6], [3,9]].trace
876
+ # => 16
877
+ #
878
+ def trace
879
+ tr = 0
880
+ 0.upto(column_size - 1) do
881
+ |i|
882
+ tr += @rows[i][i]
883
+ end
884
+ tr
885
+ end
886
+ alias tr trace
887
+
888
+ #
889
+ # Returns the transpose of the matrix.
890
+ # Matrix[[1,2], [3,4], [5,6]]
891
+ # => 1 2
892
+ # 3 4
893
+ # 5 6
894
+ # Matrix[[1,2], [3,4], [5,6]].transpose
895
+ # => 1 3 5
896
+ # 2 4 6
897
+ #
898
+ def transpose
899
+ Matrix.columns(@rows)
900
+ end
901
+ alias t transpose
902
+
903
+ #--
904
+ # CONVERTING -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
905
+ #++
906
+
907
+ #
908
+ # FIXME: describe #coerce.
909
+ #
910
+ def coerce(other)
911
+ case other
912
+ when Numeric
913
+ return Scalar.new(other), self
914
+ else
915
+ raise TypeError, "#{self.class} can't be coerced into #{other.class}"
916
+ end
917
+ end
918
+
919
+ #
920
+ # Returns an array of the row vectors of the matrix. See Vector.
921
+ #
922
+ def row_vectors
923
+ rows = (0 .. row_size - 1).collect {
924
+ |i|
925
+ row(i)
926
+ }
927
+ rows
928
+ end
929
+
930
+ #
931
+ # Returns an array of the column vectors of the matrix. See Vector.
932
+ #
933
+ def column_vectors
934
+ columns = (0 .. column_size - 1).collect {
935
+ |i|
936
+ column(i)
937
+ }
938
+ columns
939
+ end
940
+
941
+ #
942
+ # Returns an array of arrays that describe the rows of the matrix.
943
+ #
944
+ def to_a
945
+ @rows.collect{|row| row.collect{|e| e}}
946
+ end
947
+
948
+ def elements_to_f
949
+ collect{|e| e.to_f}
950
+ end
951
+
952
+ def elements_to_i
953
+ collect{|e| e.to_i}
954
+ end
955
+
956
+ def elements_to_r
957
+ collect{|e| e.to_r}
958
+ end
959
+
960
+ #--
961
+ # PRINTING -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
962
+ #++
963
+
964
+ #
965
+ # Overrides Object#to_s
966
+ #
967
+ def to_s
968
+ "Matrix[" + @rows.collect{
969
+ |row|
970
+ "[" + row.collect{|e| e.to_s}.join(", ") + "]"
971
+ }.join(", ")+"]"
972
+ end
973
+
974
+ #
975
+ # Overrides Object#inspect
976
+ #
977
+ def inspect
978
+ "Matrix"+@rows.inspect
979
+ end
980
+
981
+ # Private CLASS
982
+
983
+ class Scalar < Numeric # :nodoc:
984
+ include ExceptionForMatrix
985
+
986
+ def initialize(value)
987
+ @value = value
988
+ end
989
+
990
+ # ARITHMETIC
991
+ def +(other)
992
+ case other
993
+ when Numeric
994
+ Scalar.new(@value + other)
995
+ when Vector, Matrix
996
+ Scalar.Raise WrongArgType, other.class, "Numeric or Scalar"
997
+ when Scalar
998
+ Scalar.new(@value + other.value)
999
+ else
1000
+ x, y = other.coerce(self)
1001
+ x + y
1002
+ end
1003
+ end
1004
+
1005
+ def -(other)
1006
+ case other
1007
+ when Numeric
1008
+ Scalar.new(@value - other)
1009
+ when Vector, Matrix
1010
+ Scalar.Raise WrongArgType, other.class, "Numeric or Scalar"
1011
+ when Scalar
1012
+ Scalar.new(@value - other.value)
1013
+ else
1014
+ x, y = other.coerce(self)
1015
+ x - y
1016
+ end
1017
+ end
1018
+
1019
+ def *(other)
1020
+ case other
1021
+ when Numeric
1022
+ Scalar.new(@value * other)
1023
+ when Vector, Matrix
1024
+ other.collect{|e| @value * e}
1025
+ else
1026
+ x, y = other.coerce(self)
1027
+ x * y
1028
+ end
1029
+ end
1030
+
1031
+ def / (other)
1032
+ case other
1033
+ when Numeric
1034
+ Scalar.new(@value / other)
1035
+ when Vector
1036
+ Scalar.Raise WrongArgType, other.class, "Numeric or Scalar or Matrix"
1037
+ when Matrix
1038
+ self * other.inverse
1039
+ else
1040
+ x, y = other.coerce(self)
1041
+ x.quo(y)
1042
+ end
1043
+ end
1044
+
1045
+ def ** (other)
1046
+ case other
1047
+ when Numeric
1048
+ Scalar.new(@value ** other)
1049
+ when Vector
1050
+ Scalar.Raise WrongArgType, other.class, "Numeric or Scalar or Matrix"
1051
+ when Matrix
1052
+ other.powered_by(self)
1053
+ else
1054
+ x, y = other.coerce(self)
1055
+ x ** y
1056
+ end
1057
+ end
1058
+ end
1059
+ end
1060
+
1061
+
1062
+ #
1063
+ # The +Vector+ class represents a mathematical vector, which is useful in its own right, and
1064
+ # also constitutes a row or column of a Matrix.
1065
+ #
1066
+ # == Method Catalogue
1067
+ #
1068
+ # To create a Vector:
1069
+ # * <tt> Vector.[](*array) </tt>
1070
+ # * <tt> Vector.elements(array, copy = true) </tt>
1071
+ #
1072
+ # To access elements:
1073
+ # * <tt> [](i) </tt>
1074
+ #
1075
+ # To enumerate the elements:
1076
+ # * <tt> #each2(v) </tt>
1077
+ # * <tt> #collect2(v) </tt>
1078
+ #
1079
+ # Vector arithmetic:
1080
+ # * <tt> *(x) "is matrix or number" </tt>
1081
+ # * <tt> +(v) </tt>
1082
+ # * <tt> -(v) </tt>
1083
+ #
1084
+ # Vector functions:
1085
+ # * <tt> #inner_product(v) </tt>
1086
+ # * <tt> #collect </tt>
1087
+ # * <tt> #map </tt>
1088
+ # * <tt> #map2(v) </tt>
1089
+ # * <tt> #r </tt>
1090
+ # * <tt> #size </tt>
1091
+ #
1092
+ # Conversion to other data types:
1093
+ # * <tt> #covector </tt>
1094
+ # * <tt> #to_a </tt>
1095
+ # * <tt> #coerce(other) </tt>
1096
+ #
1097
+ # String representations:
1098
+ # * <tt> #to_s </tt>
1099
+ # * <tt> #inspect </tt>
1100
+ #
1101
+ class Vector
1102
+ include ExceptionForMatrix
1103
+
1104
+ #INSTANCE CREATION
1105
+
1106
+ private_class_method :new
1107
+
1108
+ #
1109
+ # Creates a Vector from a list of elements.
1110
+ # Vector[7, 4, ...]
1111
+ #
1112
+ def Vector.[](*array)
1113
+ new(:init_elements, array, copy = false)
1114
+ end
1115
+
1116
+ #
1117
+ # Creates a vector from an Array. The optional second argument specifies
1118
+ # whether the array itself or a copy is used internally.
1119
+ #
1120
+ def Vector.elements(array, copy = true)
1121
+ new(:init_elements, array, copy)
1122
+ end
1123
+
1124
+ #
1125
+ # For internal use.
1126
+ #
1127
+ def initialize(method, array, copy)
1128
+ self.send(method, array, copy)
1129
+ end
1130
+
1131
+ #
1132
+ # For internal use.
1133
+ #
1134
+ def init_elements(array, copy)
1135
+ if copy
1136
+ @elements = array.dup
1137
+ else
1138
+ @elements = array
1139
+ end
1140
+ end
1141
+
1142
+ # ACCESSING
1143
+
1144
+ #
1145
+ # Returns element number +i+ (starting at zero) of the vector.
1146
+ #
1147
+ def [](i)
1148
+ @elements[i]
1149
+ end
1150
+ alias element []
1151
+ alias component []
1152
+
1153
+ def []=(i, v)
1154
+ @elements[i]= v
1155
+ end
1156
+ alias set_element []=
1157
+ alias set_component []=
1158
+ private :[]=, :set_element, :set_component
1159
+
1160
+ #
1161
+ # Returns the number of elements in the vector.
1162
+ #
1163
+ def size
1164
+ @elements.size
1165
+ end
1166
+
1167
+ #--
1168
+ # ENUMERATIONS -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
1169
+ #++
1170
+
1171
+ #
1172
+ # Iterate over the elements of this vector and +v+ in conjunction.
1173
+ #
1174
+ def each2(v) # :yield: e1, e2
1175
+ Vector.Raise ErrDimensionMismatch if size != v.size
1176
+ 0.upto(size - 1) do
1177
+ |i|
1178
+ yield @elements[i], v[i]
1179
+ end
1180
+ end
1181
+
1182
+ #
1183
+ # Collects (as in Enumerable#collect) over the elements of this vector and +v+
1184
+ # in conjunction.
1185
+ #
1186
+ def collect2(v) # :yield: e1, e2
1187
+ Vector.Raise ErrDimensionMismatch if size != v.size
1188
+ (0 .. size - 1).collect do
1189
+ |i|
1190
+ yield @elements[i], v[i]
1191
+ end
1192
+ end
1193
+
1194
+ #--
1195
+ # COMPARING -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
1196
+ #++
1197
+
1198
+ #
1199
+ # Returns +true+ iff the two vectors have the same elements in the same order.
1200
+ #
1201
+ def ==(other)
1202
+ return false unless Vector === other
1203
+
1204
+ other.compare_by(@elements)
1205
+ end
1206
+ alias eqn? ==
1207
+
1208
+ #
1209
+ # For internal use.
1210
+ #
1211
+ def compare_by(elements)
1212
+ @elements == elements
1213
+ end
1214
+
1215
+ #
1216
+ # Return a copy of the vector.
1217
+ #
1218
+ def clone
1219
+ Vector.elements(@elements)
1220
+ end
1221
+
1222
+ #
1223
+ # Return a hash-code for the vector.
1224
+ #
1225
+ def hash
1226
+ @elements.hash
1227
+ end
1228
+
1229
+ #--
1230
+ # ARITHMETIC -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
1231
+ #++
1232
+
1233
+ #
1234
+ # Multiplies the vector by +x+, where +x+ is a number or another vector.
1235
+ #
1236
+ def *(x)
1237
+ case x
1238
+ when Numeric
1239
+ els = @elements.collect{|e| e * x}
1240
+ Vector.elements(els, false)
1241
+ when Matrix
1242
+ Matrix.column_vector(self) * x
1243
+ else
1244
+ s, x = x.coerce(self)
1245
+ s * x
1246
+ end
1247
+ end
1248
+
1249
+ #
1250
+ # Vector addition.
1251
+ #
1252
+ def +(v)
1253
+ case v
1254
+ when Vector
1255
+ Vector.Raise ErrDimensionMismatch if size != v.size
1256
+ els = collect2(v) {
1257
+ |v1, v2|
1258
+ v1 + v2
1259
+ }
1260
+ Vector.elements(els, false)
1261
+ when Matrix
1262
+ Matrix.column_vector(self) + v
1263
+ else
1264
+ s, x = v.coerce(self)
1265
+ s + x
1266
+ end
1267
+ end
1268
+
1269
+ #
1270
+ # Vector subtraction.
1271
+ #
1272
+ def -(v)
1273
+ case v
1274
+ when Vector
1275
+ Vector.Raise ErrDimensionMismatch if size != v.size
1276
+ els = collect2(v) {
1277
+ |v1, v2|
1278
+ v1 - v2
1279
+ }
1280
+ Vector.elements(els, false)
1281
+ when Matrix
1282
+ Matrix.column_vector(self) - v
1283
+ else
1284
+ s, x = v.coerce(self)
1285
+ s - x
1286
+ end
1287
+ end
1288
+
1289
+ #--
1290
+ # VECTOR FUNCTIONS -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
1291
+ #++
1292
+
1293
+ #
1294
+ # Returns the inner product of this vector with the other.
1295
+ # Vector[4,7].inner_product Vector[10,1] => 47
1296
+ #
1297
+ def inner_product(v)
1298
+ Vector.Raise ErrDimensionMismatch if size != v.size
1299
+
1300
+ p = 0
1301
+ each2(v) {
1302
+ |v1, v2|
1303
+ p += v1 * v2
1304
+ }
1305
+ p
1306
+ end
1307
+
1308
+ #
1309
+ # Like Array#collect.
1310
+ #
1311
+ def collect # :yield: e
1312
+ els = @elements.collect {
1313
+ |v|
1314
+ yield v
1315
+ }
1316
+ Vector.elements(els, false)
1317
+ end
1318
+ alias map collect
1319
+
1320
+ #
1321
+ # Like Vector#collect2, but returns a Vector instead of an Array.
1322
+ #
1323
+ def map2(v) # :yield: e1, e2
1324
+ els = collect2(v) {
1325
+ |v1, v2|
1326
+ yield v1, v2
1327
+ }
1328
+ Vector.elements(els, false)
1329
+ end
1330
+
1331
+ #
1332
+ # Returns the modulus (Pythagorean distance) of the vector.
1333
+ # Vector[5,8,2].r => 9.643650761
1334
+ #
1335
+ def r
1336
+ v = 0
1337
+ for e in @elements
1338
+ v += e*e
1339
+ end
1340
+ return Math.sqrt(v)
1341
+ end
1342
+
1343
+ #--
1344
+ # CONVERTING
1345
+ #++
1346
+
1347
+ #
1348
+ # Creates a single-row matrix from this vector.
1349
+ #
1350
+ def covector
1351
+ Matrix.row_vector(self)
1352
+ end
1353
+
1354
+ #
1355
+ # Returns the elements of the vector in an array.
1356
+ #
1357
+ def to_a
1358
+ @elements.dup
1359
+ end
1360
+
1361
+ def elements_to_f
1362
+ collect{|e| e.to_f}
1363
+ end
1364
+
1365
+ def elements_to_i
1366
+ collect{|e| e.to_i}
1367
+ end
1368
+
1369
+ def elements_to_r
1370
+ collect{|e| e.to_r}
1371
+ end
1372
+
1373
+ #
1374
+ # FIXME: describe Vector#coerce.
1375
+ #
1376
+ def coerce(other)
1377
+ case other
1378
+ when Numeric
1379
+ return Matrix::Scalar.new(other), self
1380
+ else
1381
+ raise TypeError, "#{self.class} can't be coerced into #{other.class}"
1382
+ end
1383
+ end
1384
+
1385
+ #--
1386
+ # PRINTING -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
1387
+ #++
1388
+
1389
+ #
1390
+ # Overrides Object#to_s
1391
+ #
1392
+ def to_s
1393
+ "Vector[" + @elements.join(", ") + "]"
1394
+ end
1395
+
1396
+ #
1397
+ # Overrides Object#inspect
1398
+ #
1399
+ def inspect
1400
+ str = "Vector"+@elements.inspect
1401
+ end
1402
+ end
1403
+
1404
+
1405
+ # Documentation comments:
1406
+ # - Matrix#coerce and Vector#coerce need to be documented
1407
+
1408
+ end