1 
1 
#

2 
2 
# matrix.rb 

3 
3 
# $Release Version: 1.0$

4 

# $Revision: 1.13 $


4 
# $Revision: 1.14 $

5 
5 
# Original Version from Smalltalk80 version

6 
6 
# on July 23, 1985 at 8:37:17 am

7 
7 
# by Keiju ISHITSUKA

...  ...  
35 
35 
# arithmetically and algebraically, and determining their mathematical properties (trace, rank,

36 
36 
# inverse, determinant).

37 
37 
#

38 

# Note that although matrices should theoretically be rectangular, this is not

39 

# enforced by the class.


38 
# Note that matrices must be rectangular.

40 
39 
#

41 

# Also note that the determinant of integer matrices may be incorrectly calculated unless you


40 
# Also note that the determinant of integer matrices may be approximated unless you

42 
41 
# also <tt>require 'mathn'</tt>. This may be fixed in the future.

43 
42 
#

44 
43 
# == Method Catalogue

...  ...  
50 
49 
# * <tt> Matrix.columns(columns) </tt>

51 
50 
# * <tt> Matrix.diagonal(*values) </tt>

52 
51 
# * <tt> Matrix.scalar(n, value) </tt>

53 

# * <tt> Matrix.scalar(n, value) </tt>

54 
52 
# * <tt> Matrix.identity(n) </tt>

55 
53 
# * <tt> Matrix.unit(n) </tt>

56 
54 
# * <tt> Matrix.I(n) </tt>

...  ...  
102 
100 
# * <tt> #inspect </tt>

103 
101 
#

104 
102 
class Matrix

105 

@RCS_ID='$Id: matrix.rb,v 1.13 2001/12/09 14:22:23 keiju Exp keiju $'


103 
@RCS_ID='$Id: matrix.rb,v 1.14 2009/05/28 00:00:00 keiju Exp keiju $'

106 
104 

107 

# extend Exception2MessageMapper

108 
105 
include ExceptionForMatrix

109 
106 

110 
107 
# instance creations

111 
108 
private_class_method :new


109 
attr_reader :rows


110 
protected :rows

112 
111 

113 
112 
#

114 
113 
# Creates a matrix where each argument is a row.

...  ...  
117 
116 
# 1 66

118 
117 
#

119 
118 
def Matrix.[](*rows)

120 

new(:init_rows, rows, false)


119 
Matrix.rows(rows, false)

121 
120 
end

122 
121 

123 
122 
#

124 
123 
# Creates a matrix where +rows+ is an array of arrays, each of which is a row

125 

# to the matrix. If the optional argument +copy+ is false, use the given


124 
# of the matrix. If the optional argument +copy+ is false, use the given

126 
125 
# arrays as the internal structure of the matrix without copying.

127 
126 
# Matrix.rows([[25, 93], [1, 66]])

128 
127 
# => 25 93

129 
128 
# 1 66


129 
#

130 
130 
def Matrix.rows(rows, copy = true)

131 

new(:init_rows, rows, copy)


131 
rows = Matrix.convert_to_array(rows)


132 
rows.map! do row


133 
Matrix.convert_to_array(row, copy)


134 
end


135 
size = (rows[0]  []).size


136 
rows.each do row


137 
Matrix.Raise ErrDimensionMismatch, "element size differs (#{row.size} should be #{size})" unless row.size == size


138 
end


139 
new rows, size

132 
140 
end

133 
141 

134 
142 
#

...  ...  
137 
145 
# => 25 1

138 
146 
# 93 66

139 
147 
#

140 

#

141 
148 
def Matrix.columns(columns)

142 

rows = (0 .. columns[0].size  1).collect {i

143 

(0 .. columns.size  1).collect {j

144 

columns[j][i]

145 

}

146 

}

147 

Matrix.rows(rows, false)


149 
Matrix.rows(columns, false).transpose

148 
150 
end

149 
151 

150 
152 
#

...  ...  
156 
158 
#

157 
159 
def Matrix.diagonal(*values)

158 
160 
size = values.size

159 

rows = (0 .. size  1).collect {j


161 
rows = (0 ... size).collect {j

160 
162 
row = Array.new(size).fill(0, 0, size)

161 
163 
row[j] = values[j]

162 
164 
row

163 
165 
}

164 

rows(rows, false)


166 
new rows

165 
167 
end

166 
168 

167 
169 
#

...  ...  
206 
208 
# => 4 5 6

207 
209 
#

208 
210 
def Matrix.row_vector(row)

209 

case row

210 

when Vector

211 

Matrix.rows([row.to_a], false)

212 

when Array

213 

Matrix.rows([row.dup], false)

214 

else

215 

Matrix.rows([[row]], false)

216 

end


211 
row = Matrix.convert_to_array(row)


212 
new [row]

217 
213 
end

218 
214 

219 
215 
#

...  ...  
225 
221 
# 6

226 
222 
#

227 
223 
def Matrix.column_vector(column)

228 

case column

229 

when Vector

230 

Matrix.columns([column.to_a])

231 

when Array

232 

Matrix.columns([column])

233 

else

234 

Matrix.columns([[column]])

235 

end


224 
column = Matrix.convert_to_array(column)


225 
new column.map{elem [elem]}, 1

236 
226 
end

237 
227 

238 
228 
#

239 
229 
# This method is used by the other methods that create matrices, and is of no

240 
230 
# use to general users.


231 
# No checking is done at this point. rows must be an Array of Arrays.


232 
# column_size must be passed if rows is empty

241 
233 
#

242 

def initialize(init_method, *argv)

243 

self.send(init_method, *argv)


234 
def initialize(rows, column_size = rows[0].size)


235 
@rows = rows


236 
@column_size = column_size

244 
237 
end

245 
238 

246 

def init_rows(rows, copy)

247 

if copy

248 

@rows = rows.collect{row row.dup}

249 

else

250 

@rows = rows

251 

end

252 

self


239 
#


240 
# Use to bypass privacy of Matrix.new


241 
#


242 
def new(rows, column_size = rows[0].size)


243 
Matrix.send(:new, rows, column_size)

253 
244 
end

254 

private :init_rows


245 
private :new

255 
246 

256 
247 
#

257 
248 
# Returns element (+i+,+j+) of the matrix. That is: row +i+, column +j+.

258 
249 
#

259 
250 
def [](i, j)

260 

@rows[i][j]


251 
(@rows[i]  [])[j]

261 
252 
end

262 
253 
alias element []

263 
254 
alias component []

...  ...  
277 
268 
end

278 
269 

279 
270 
#

280 

# Returns the number of columns. Note that it is possible to construct a

281 

# matrix with uneven columns (e.g. Matrix[ [1,2,3], [4,5] ]), but this is

282 

# mathematically unsound. This method uses the first row to determine the

283 

# result.


271 
# Returns the number of columns.

284 
272 
#

285 

def column_size

286 

@rows[0].size

287 

end


273 
attr_reader :column_size

288 
274 

289 
275 
#

290 
276 
# Returns row vector number +i+ of the matrix as a Vector (starting at 0 like

291 
277 
# an array). When a block is given, the elements of that vector are iterated.

292 
278 
#

293 

def row(i) # :yield: e

294 

if block_given?

295 

for e in @rows[i]

296 

yield e


279 
def row(i, &block) # :yield: e


280 
if row = @rows[i]


281 
if block_given?


282 
row.each(&block)


283 
else


284 
Vector.elements(row, false)

297 
285 
end

298 
286 
else

299 

Vector.elements(@rows[i])


287 
if block_given?


288 
self


289 
else


290 
nil


291 
end

300 
292 
end

301 
293 
end

302 
294 

...  ...  
307 
299 
#

308 
300 
def column(j) # :yield: e

309 
301 
if block_given?

310 

0.upto(row_size  1) do i


302 
row_size.times do i

311 
303 
yield @rows[i][j]

312 

end


304 
end unless j >= column_size


305 
self

313 
306 
else

314 

col = (0 .. row_size  1).collect {i


307 
return nil if j >= column_size


308 
col = (0 ... row_size).collect {i

315 
309 
@rows[i][j]

316 
310 
}

317 
311 
Vector.elements(col, false)

...  ...  
325 
319 
# => 1 4

326 
320 
# 9 16

327 
321 
#

328 

def collect # :yield: e

329 

rows = @rows.collect{row row.collect{e yield e}}

330 

Matrix.rows(rows, false)


322 
def collect(&block) # :yield: e


323 
return to_enum(:collect) unless block_given?


324 
rows = @rows.collect{row row.collect(&block)}


325 
new(rows)

331 
326 
end

332 
327 
alias map collect

333 
328 

...  ...  
350 
345 
size_col = param[1].end  from_col

351 
346 
size_col += 1 unless param[1].exclude_end?

352 
347 
when 4

353 

from_row = param[0]

354 

size_row = param[1]

355 

from_col = param[2]

356 

size_col = param[3]


348 
from_row, size_row, from_col, size_col = param

357 
349 
else

358 
350 
Matrix.Raise ArgumentError, param.inspect

359 
351 
end

360 



352 
return nil if from_row > row_size  from_col > column_size

361 
353 
rows = @rows[from_row, size_row].collect{row

362 
354 
row[from_col, size_col]

363 
355 
}

364 

Matrix.rows(rows, false)


356 
new(rows, column_size  from_col)

365 
357 
end

366 
358 

367 
359 
#

...  ...  
383 
375 
end

384 
376 

385 
377 
#

386 

# Returns +true+ is this is a square matrix. See note in column_size about this

387 

# being unreliable, though.


378 
# Returns +true+ is this is a square matrix.

388 
379 
#

389 
380 
def square?

390 
381 
column_size == row_size

...  ...  
399 
390 
#

400 
391 
def ==(other)

401 
392 
return false unless Matrix === other

402 


403 

other.compare_by_row_vectors(@rows)


393 
@rows == other.rows

404 
394 
end


395 

405 
396 
def eql?(other)

406 
397 
return false unless Matrix === other

407 


408 

other.compare_by_row_vectors(@rows, :eql?)


398 
@rows.eql? other.rows

409 
399 
end

410 
400 

411 
401 
#

412 

# Not really intended for general consumption.

413 

#

414 

def compare_by_row_vectors(rows, comparison = :==)

415 

return false unless @rows.size == rows.size

416 


417 

0.upto(@rows.size  1) do i

418 

return false unless @rows[i].send(comparison, rows[i])

419 

end

420 

true

421 

end

422 


423 

#

424 
402 
# Returns a clone of the matrix, so that the contents of each do not reference

425 
403 
# identical objects.


404 
# There should be no good reason to do this since Matrices are immutable.

426 
405 
#

427 
406 
def clone

428 

Matrix.rows(@rows)


407 
new(@rows.map{row row.dup}, column_size)

429 
408 
end

430 
409 

431 
410 
#

432 
411 
# Returns a hashcode for the matrix.

433 
412 
#

434 
413 
def hash

435 

value = 0

436 

for row in @rows

437 

for e in row

438 

value ^= e.hash

439 

end

440 

end

441 

return value


414 
@rows.hash

442 
415 
end

443 
416 

444 
417 
#

...  ...  
459 
432 
e * m

460 
433 
}

461 
434 
}

462 

return Matrix.rows(rows, false)


435 
return new(rows, column_size)

463 
436 
when Vector

464 
437 
m = Matrix.column_vector(m)

465 
438 
r = self * m

...  ...  
467 
440 
when Matrix

468 
441 
Matrix.Raise ErrDimensionMismatch if column_size != m.row_size

469 
442 

470 

rows = (0 .. row_size  1).collect {i

471 

(0 .. m.column_size  1).collect {j


443 
rows = (0 ... row_size).collect {i


444 
(0 ... m.column_size).collect {j

472 
445 
vij = 0

473 

0.upto(column_size  1) do k


446 
column_size.times do k

474 
447 
vij += self[i, k] * m[k, j]

475 
448 
end

476 
449 
vij

477 
450 
}

478 
451 
}

479 

return Matrix.rows(rows, false)


452 
return new(rows, m.column_size)

480 
453 
else

481 
454 
x, y = m.coerce(self)

482 
455 
return x * y

...  ...  
503 
476 

504 
477 
Matrix.Raise ErrDimensionMismatch unless row_size == m.row_size and column_size == m.column_size

505 
478 

506 

rows = (0 .. row_size  1).collect {i

507 

(0 .. column_size  1).collect {j


479 
rows = (0 ... row_size).collect {i


480 
(0 ... column_size).collect {j

508 
481 
self[i, j] + m[i, j]

509 
482 
}

510 
483 
}

511 

Matrix.rows(rows, false)


484 
new(rows, column_size)

512 
485 
end

513 
486 

514 
487 
#

...  ...  
531 
504 

532 
505 
Matrix.Raise ErrDimensionMismatch unless row_size == m.row_size and column_size == m.column_size

533 
506 

534 

rows = (0 .. row_size  1).collect {i

535 

(0 .. column_size  1).collect {j


507 
rows = (0 ... row_size).collect {i


508 
(0 ... column_size).collect {j

536 
509 
self[i, j]  m[i, j]

537 
510 
}

538 
511 
}

539 

Matrix.rows(rows, false)


512 
new(rows, column_size)

540 
513 
end

541 
514 

542 
515 
#

...  ...  
553 
526 
e / other

554 
527 
}

555 
528 
}

556 

return Matrix.rows(rows, false)


529 
return new(rows, column_size)

557 
530 
when Matrix

558 
531 
return self * other.inverse

559 
532 
else

...  ...  
578 
551 
# Not for public consumption?

579 
552 
#

580 
553 
def inverse_from(src)

581 

size = row_size  1


554 
size = row_size

582 
555 
a = src.to_a

583 
556 

584 

for k in 0..size


557 
for k in 0...size

585 
558 
i = k

586 
559 
akk = a[k][k].abs

587 

((k+1)..size).each do j


560 
((k+1)...size).each do j

588 
561 
v = a[j][k].abs

589 
562 
if v > akk

590 
563 
i = j

...  ...  
598 
571 
end

599 
572 
akk = a[k][k]

600 
573 

601 

for i in 0 .. size


574 
for i in 0 ... size

602 
575 
next if i == k

603 
576 
q = a[i][k].quo(akk)

604 
577 
a[i][k] = 0

605 
578 

606 

for j in (k + 1).. size


579 
for j in (k + 1)... size

607 
580 
a[i][j] = a[k][j] * q

608 
581 
end

609 

for j in 0..size


582 
for j in 0...size

610 
583 
@rows[i][j] = @rows[k][j] * q

611 
584 
end

612 
585 
end

613 
586 

614 

for j in (k + 1).. size


587 
for j in (k + 1)...size

615 
588 
a[k][j] = a[k][j].quo(akk)

616 
589 
end

617 

for j in 0..size


590 
for j in 0...size

618 
591 
@rows[k][j] = @rows[k][j].quo(akk)

619 
592 
end

620 
593 
end

...  ...  
630 
603 
# 48 99

631 
604 
#

632 
605 
def ** (other)


606 
Matrix.Raise ErrDimensionMismatch unless square?

633 
607 
if other.kind_of?(Integer)

634 
608 
x = self

635 
609 
if other <= 0

636 

x = self.inverse

637 
610 
return Matrix.identity(self.column_size) if other == 0


611 
x = self.inverse

638 
612 
other = other

639 
613 
end

640 
614 
z = x

...  ...  
662 
636 

663 
637 
#

664 
638 
# Returns the determinant of the matrix. If the matrix is not square, the

665 

# result is 0. This method's algorism is Gaussian elimination method


639 
# result is 0. This method's algorithm is Gaussian elimination method

666 
640 
# and using Numeric#quo(). Beware that using Float values, with their

667 
641 
# usual lack of precision, can affect the value returned by this method. Use

668 
642 
# Rational values or Matrix#det_e instead if this is important to you.

669 
643 
#

670 
644 
# Matrix[[7,6], [3,9]].determinant

671 

# => 63.0


645 
# => 45.0

672 
646 
#

673 
647 
def determinant

674 
648 
return 0 unless square?

675 
649 

676 

size = row_size  1


650 
size = row_size

677 
651 
a = to_a

678 
652 

679 
653 
det = 1

680 

k = 0

681 

loop do


654 
for k in 0...size do

682 
655 
if (akk = a[k][k]) == 0

683 
656 
i = k

684 
657 
loop do

685 

return 0 if (ii += 1) > size


658 
return 0 if (i += 1) >= size

686 
659 
break unless a[i][k] == 0

687 
660 
end

688 
661 
a[i], a[k] = a[k], a[i]

...  ...  
690 
663 
det *= 1

691 
664 
end

692 
665 

693 

for i in k + 1 .. size


666 
for i in k + 1 ... size

694 
667 
q = a[i][k].quo(akk)

695 

(k + 1).upto(size) do j


668 
for j in k + 1 ... size

696 
669 
a[i][j] = a[k][j] * q

697 
670 
end

698 
671 
end

699 
672 
det *= akk

700 

break unless (k += 1) <= size

701 
673 
end

702 
674 
det

703 
675 
end

...  ...  
705 
677 

706 
678 
#

707 
679 
# Returns the determinant of the matrix. If the matrix is not square, the

708 

# result is 0. This method's algorism is Gaussian elimination method.

709 

# This method uses Euclidean algorism. If all elements are integer,


680 
# result is 0. This method's algorithm is Gaussian elimination method.


681 
# This method uses Euclidean algorithm. If all elements are integer,

710 
682 
# really exact value. But, if an element is a float, can't return

711 
683 
# exact value.

712 
684 
#

...  ...  
716 
688 
def determinant_e

717 
689 
return 0 unless square?

718 
690 

719 

size = row_size  1


691 
size = row_size

720 
692 
a = to_a

721 
693 

722 
694 
det = 1

723 

k = 0

724 

loop do


695 
for k in 0...size

725 
696 
if a[k][k].zero?

726 
697 
i = k

727 
698 
loop do

728 

return 0 if (i += 1) > size


699 
return 0 if (i += 1) >= size

729 
700 
break unless a[i][k].zero?

730 
701 
end

731 
702 
a[i], a[k] = a[k], a[i]

732 
703 
det *= 1

733 
704 
end

734 
705 

735 

for i in (k + 1)..size


706 
for i in (k + 1)...size

736 
707 
q = a[i][k].quo(a[k][k])

737 

k.upto(size) do j


708 
for j in k...size do

738 
709 
a[i][j] = a[k][j] * q

739 
710 
end

740 
711 
unless a[i][k].zero?

...  ...  
744 
715 
end

745 
716 
end

746 
717 
det *= a[k][k]

747 

break unless (k += 1) <= size

748 
718 
end

749 
719 
det

750 
720 
end

...  ...  
769 
739 
a_row_size = row_size

770 
740 
end

771 
741 
rank = 0

772 

k = 0

773 

loop do


742 
for k in 0...a_column_size

774 
743 
if (akk = a[k][k]) == 0

775 
744 
i = k

776 
745 
exists = true

777 
746 
loop do

778 

if (i += 1) > a_column_size  1


747 
if (i += 1) >= a_column_size

779 
748 
exists = false

780 
749 
break

781 
750 
end

...  ...  
788 
757 
i = k

789 
758 
exists = true

790 
759 
loop do

791 

if (i += 1) > a_row_size  1


760 
if (i += 1) >= a_row_size

792 
761 
exists = false

793 
762 
break

794 
763 
end

795 
764 
break unless a[k][i] == 0

796 
765 
end

797 
766 
if exists

798 

k.upto(a_column_size  1) do j


767 
for j in k...a_column_size do

799 
768 
a[j][k], a[j][i] = a[j][i], a[j][k]

800 
769 
end

801 
770 
akk = a[k][k]

...  ...  
805 
774 
end

806 
775 
end

807 
776 

808 

for i in (k + 1)..(a_row_size  1)


777 
for i in (k + 1)...a_row_size

809 
778 
q = a[i][k].quo(akk)

810 

for j in (k + 1)..(a_column_size  1)


779 
for j in (k + 1)...a_column_size

811 
780 
a[i][j] = a[k][j] * q

812 
781 
end

813 
782 
end

814 
783 
rank += 1

815 

break unless (k += 1) <= a_column_size  1

816 
784 
end

817 
785 
return rank

818 
786 
end

819 
787 

820 
788 
#

821 
789 
# Returns the rank of the matrix. This method uses Euclidean

822 

# algorism. If all elements are integer, really exact value. But, if


790 
# algorithm. If all elements are integer, really exact value. But, if

823 
791 
# an element is a float, can't return exact value.

824 
792 
#

825 
793 
# Matrix[[7,6], [3,9]].rank

...  ...  
830 
798 
a_column_size = column_size

831 
799 
a_row_size = row_size

832 
800 
pi = 0

833 

(0 ... a_column_size).each do j


801 
a_column_size.times do j

834 
802 
if i = (pi ... a_row_size).find{i0 !a[i0][j].zero?}

835 
803 
if i != pi

836 
804 
a[pi], a[i] = a[i], a[pi]

...  ...  
858 
826 
# => 16

859 
827 
#

860 
828 
def trace


829 
Matrix.Raise ErrDimensionMismatch unless square?

861 
830 
tr = 0

862 

0.upto(column_size  1) do i


831 
column_size.times do i

863 
832 
tr += @rows[i][i]

864 
833 
end

865 
834 
tr

...  ...  
877 
846 
# 2 4 6

878 
847 
#

879 
848 
def transpose

880 

Matrix.columns(@rows)


849 
new @rows.transpose, row_size

881 
850 
end

882 
851 
alias t transpose

883 
852 

...  ...  
901 
870 
# Returns an array of the row vectors of the matrix. See Vector.

902 
871 
#

903 
872 
def row_vectors

904 

rows = (0 .. row_size  1).collect {i


873 
rows = (0 ... row_size).collect {i

905 
874 
row(i)

906 
875 
}

907 
876 
rows

...  ...  
911 
880 
# Returns an array of the column vectors of the matrix. See Vector.

912 
881 
#

913 
882 
def column_vectors

914 

columns = (0 .. column_size  1).collect {i


883 
columns = (0 ... column_size).collect {i

915 
884 
column(i)

916 
885 
}

917 
886 
columns

...  ...  
921 
890 
# Returns an array of arrays that describe the rows of the matrix.

922 
891 
#

923 
892 
def to_a

924 

@rows.collect{row row.collect{e e}}


893 
@rows.collect{row row.dup}

925 
894 
end

926 
895 

927 
896 
def elements_to_f

...  ...  
944 
913 
# Overrides Object#to_s

945 
914 
#

946 
915 
def to_s

947 

"Matrix[" + @rows.collect{row

948 

"[" + row.collect{e e.to_s}.join(", ") + "]"

949 

}.join(", ")+"]"


916 
if row_size == 0 && column_size > 0


917 
"Matrix.columns([" + (["[]"] * column_size).join(", ") + "])"


918 
else


919 
"Matrix[" + @rows.collect{row


920 
"[" + row.collect{e e.to_s}.join(", ") + "]"


921 
}.join(", ")+"]"


922 
end

950 
923 
end

951 
924 

952 
925 
#

953 
926 
# Overrides Object#inspect

954 
927 
#

955 
928 
def inspect


929 
return to_s if row_size == 0 && column_size > 0

956 
930 
"Matrix"+@rows.inspect

957 
931 
end

958 
932 


933 
#


934 
# Converts the obj to an Array. If copy is set to true


935 
# a copy of obj will be made if necessary.


936 
#


937 
def Matrix.convert_to_array(obj, copy = false)


938 
case obj


939 
when Array


940 
copy ? obj.dup : obj


941 
when Vector


942 
obj.to_a


943 
else


944 
begin


945 
converted = obj.to_ary


946 
rescue Exception => e


947 
raise TypeError, "can't convert #{obj.class} into an Array (#{e.message})"


948 
end


949 
raise TypeError, "#{obj.class}#to_ary should return an Array" unless converted.is_a? Array


950 
converted


951 
end


952 
end


953 

959 
954 
# Private CLASS

960 
955 

961 
956 
class Scalar < Numeric # :nodoc:

...  ...  
1013 
1008 
when Vector

1014 
1009 
Scalar.Raise WrongArgType, other.class, "Numeric or Scalar or Matrix"

1015 
1010 
when Matrix

1016 

self * other.inverse


1011 
self * other.inverse

1017 
1012 
else

1018 
1013 
x, y = other.coerce(self)

1019 
1014 
x.quo(y)

...  ...  
1082 
1077 
#INSTANCE CREATION

1083 
1078 

1084 
1079 
private_class_method :new

1085 



1080 
attr_reader :elements


1081 
protected :elements

1086 
1082 
#

1087 
1083 
# Creates a Vector from a list of elements.

1088 
1084 
# Vector[7, 4, ...]

1089 
1085 
#

1090 
1086 
def Vector.[](*array)

1091 

new(:init_elements, array, copy = false)


1087 
new array

1092 
1088 
end

1093 
1089 

1094 
1090 
#

...  ...  
1096 
1092 
# whether the array itself or a copy is used internally.

1097 
1093 
#

1098 
1094 
def Vector.elements(array, copy = true)

1099 

new(:init_elements, array, copy)


1095 
new Matrix.convert_to_array(array, copy)

1100 
1096 
end

1101 
1097 

1102 
1098 
#

1103 
1099 
# For internal use.

1104 
1100 
#

1105 

def initialize(method, array, copy)

1106 

self.send(method, array, copy)


1101 
def initialize(array)


1102 
@elements = array

1107 
1103 
end

1108 
1104 

1109 

#

1110 

# For internal use.

1111 

#

1112 

def init_elements(array, copy)

1113 

if copy

1114 

@elements = array.dup

1115 

else

1116 

@elements = array

1117 

end

1118 

end

1119 


1120 
1105 
# ACCESSING

1121 
1106 

1122 
1107 
#

...  ...  
1150 
1135 
# Iterate over the elements of this vector and +v+ in conjunction.

1151 
1136 
#

1152 
1137 
def each2(v) # :yield: e1, e2


1138 
return to_enum(:each2, v) unless block_given?

1153 
1139 
Vector.Raise ErrDimensionMismatch if size != v.size

1154 

0.upto(size  1) do i


1140 
size.times do i

1155 
1141 
yield @elements[i], v[i]

1156 
1142 
end

1157 
1143 
end

...  ...  
1161 
1147 
# in conjunction.

1162 
1148 
#

1163 
1149 
def collect2(v) # :yield: e1, e2


1150 
return to_enum(:collect2, v) unless block_given?

1164 
1151 
Vector.Raise ErrDimensionMismatch if size != v.size

1165 

(0 .. size  1).collect do i


1152 
(0 ... size).collect do i

1166 
1153 
yield @elements[i], v[i]

1167 
1154 
end

1168 
1155 
end

...  ...  
1176 
1163 
#

1177 
1164 
def ==(other)

1178 
1165 
return false unless Vector === other

1179 


1180 

other.compare_by(@elements)


1166 
@elements == other.elements

1181 
1167 
end

1182 
1168 
def eql?(other)

1183 
1169 
return false unless Vector === other

1184 


1185 

other.compare_by(@elements, :eql?)


1170 
@elements.eql? other.elements

1186 
1171 
end

1187 
1172 

1188 
1173 
#

1189 

# For internal use.

1190 

#

1191 

def compare_by(elements, comparison = :==)

1192 

@elements.send(comparison, elements)

1193 

end

1194 


1195 

#

1196 
1174 
# Return a copy of the vector.

1197 
1175 
#

1198 
1176 
def clone

...  ...  
1285 
1263 
#

1286 
1264 
# Like Array#collect.

1287 
1265 
#

1288 

def collect # :yield: e

1289 

els = @elements.collect {v

1290 

yield v

1291 

}


1266 
def collect(&block) # :yield: e


1267 
return to_enum(:collect) unless block_given?


1268 
els = @elements.collect(&block)

1292 
1269 
Vector.elements(els, false)

1293 
1270 
end

1294 
1271 
alias map collect

...  ...  
1296 
1273 
#

1297 
1274 
# Like Vector#collect2, but returns a Vector instead of an Array.

1298 
1275 
#

1299 

def map2(v) # :yield: e1, e2

1300 

els = collect2(v) {v1, v2

1301 

yield v1, v2

1302 

}


1276 
def map2(v, &block) # :yield: e1, e2


1277 
return to_enum(:map2, v) unless block_given?


1278 
els = collect2(v, &block)

1303 
1279 
Vector.elements(els, false)

1304 
1280 
end

1305 
1281 

...  ...  
1376 
1352 
end

1377 
1353 
end

1378 
1354 

1379 


1380 
1355 
# Documentation comments:

1381 
1356 
#  Matrix#coerce and Vector#coerce need to be documented
