[완료] 간단한 루비 질문입니다.
positive eigenvalue를 가진 n by n matrix를 만들려고 해서 다음과 같이 짜 봤습니다.
require 'matrix'
print "Enter the dimension of the matrix:"
begin
dim=Integer(gets)
rescue ArgumentError
puts "This is not an integer!"
end
def dot_product(vec1, vec2)
sum=0
0.upto(vec1.size-1) {|i| sum+=vec1[i]*vec2[i]}
return sum
end
def norm(vec)
return Math.sqrt(dot_product(vec, vec))
end
def normalize(vec)
return vec*1/norm(vec)
end
def GramSchmidt(vecs)
new_vecs=[]
new_vecs << normalize(vecs[0])
1.upto(vecs.size-1) do |i|
new_vecs << vecs[i].clone
1.upto(i-1) do |j|
new_vecs[i]-=new_vecs[j]*dot_product(new_vecs[i], new_vecs[j])
end
end
return new_vecs
end
rand_nums=[]
dim.times {rand_nums << rand(10)+1}
diag_mat=Matrix.diagonal(rand_nums)
rand_vecs=[]
dim.times do
vec=[]
dim.times {vec << rand}
rand_vecs << vec
end
rot_mat=GramSchmidt(Vector[rand_vecs])
mat=rot_mat.t*diag_mat*rot_mat
그런데
asdf.rb:12:in `*': can't convert Array into Integer (TypeError)
from asdf.rb:12:in `dot_product'
from asdf.rb:12:in `upto'
from asdf.rb:12:in `dot_product'
from asdf.rb:17:in `norm'
from asdf.rb:21:in `normalize'
from asdf.rb:26:in `GramSchmidt'
from asdf.rb:51
가 뜨네요. 제가 보기엔 number*number로 보이는데 뭐가 문제인지 모르겠습니다. 아직 루비 문법에 익숙치 않아서 저걸 해결한다고 코드가 잘 작동할지도 의문이네요...
그리고 뭔가 코드를 지저분하게 짠 것 같은데 우아하게 정리하려면 어떻게 될지도 알고 싶습니다.
https://github.com/clbustos/e
https://github.com/clbustos/extendmatrix
0.upto(vec1.size-1) {|i|
0.upto(vec1.size-1) {|i| sum+=vec1[i]*vec2[i]} 을 보면
vec1 이라는 array 에 array 가 들어가 있습니다.(예 [ [0.22882944], [0.358388] ]
따라서 vec1[i] 는 array 이고 vec1[i] * vec2[i] 은 당연히 에러.
이 문장을
0.upto(vec1.size-1) {|i| sum+=vec1[i]*vec2[i]}
이렇게 바꿔도
vec1.size.times { |i| sum + = vec1[i] * vec2[i] } # i 값은 0...vec1.size 까지, 또는 0..(vec1.size-1)
vec1[i] 가 array 인 관계로 에러가 발생하겠지만, 위 문장과 의미는 동일합니다.
나머지는 수학이므로 다음 분께 패스
코딩 문제는 해결했는데
수학을 잘못 짜고 있었군요 -_-; 부끄럽네요.
최종 수정본
require 'matrix'
print "Enter the dimension of the matrix:"
begin
dim=Integer(gets)
rescue ArgumentError
puts "This is not an integer!"
end
class Matrix
#this method is required due to poor definition of matrices in ruby
def Matrix.diagonal(values)
size=values.size
rows=(0..size-1).collect {
|j|
row=Array.new(size).fill(0, 0, size)
row[j]=values[j]
row
}
rows(rows, false)
end
end
def dot_product(vec1, vec2)
sum=0
0.upto(vec1.size-1) {|i| sum+=vec1[i]*vec2[i]}
return sum
end
def norm(vec) Math.sqrt(dot_product(vec, vec)) end
def normalize(vec) vec.map{|i| i/norm(vec)} end
def gen_rand_vecs(dim) Array.new(dim) {Array.new(dim) {rand}} end
def GramSchmidt(vecs)
dim=vecs.size
new_vecs=[]
new_vecs << normalize(vecs[0])
(1...dim).each do |i|
new_vec=vecs[i].clone
(0...i).each do |j|
dot=dot_product(new_vec, new_vecs[j])
(0...dim).each {|k| new_vec[k]-=new_vecs[j][k]*dot}
end
new_vecs << normalize(new_vec)
end
return new_vecs
end
def print_mat(mat)
dim=mat.rank
(0...dim).each do |i|
puts Array.new(dim) {|j| sprintf("%4f", mat[i, j])}.join("\t")
end
end
diag_mat=Matrix.diagonal(Array.new(dim) {rand})
rot_mat=Matrix.rows(GramSchmidt(gen_rand_vecs(dim)))
#puts rot_mat.det
mat=rot_mat.t*diag_mat*rot_mat
puts "Diagonal matrix:"
print_mat(diag_mat)
puts "\nRotation matrix:"
print_mat(rot_mat)
puts "\nRotated matrix:"
print_mat(mat)
혹시 나중에 참고하실 분이 계신가 하여...
루비에서 Vector와 Matrix 클래스는 부실하군요.
댓글 달기