require "linear-algebra"
include Algebra

def shownorms(m)
  str = ""
  m.each_column do |v|
    v.extend InnerProductSpace
    str << "Sqrt(#{v.norm2}), "
  end
  puts str.sub(/,\s*$/, "")
end

def analize_symmetric_matrix(a)
  puts "A = "; a.display; puts
  
  extfield, roots, tmatrix, evalues, addelms, evectors, espaces,
    chpoly, facts = a.diagonalize
  
  puts "Charactristic Polynomial: #{chpoly}"
  puts "                          => #{facts}"
  puts
  
  puts "Algebraic Numbers:"
  roots.each do |po, rs|
    puts "#{rs.join(', ')} : roots of #{po} == 0"
  end
  puts
  
  puts "Eigen Spaces: "
  evalues.uniq.each do |ev|
    puts "W_{#{ev}} = <#{espaces[ev].join(', ')}>"
  end
  
  puts
  
  puts "P = "; tmatrix.display; puts
  puts "== orthogonalize ==>"
  t = tmatrix.orthogonalize
  puts "P = "; t.display; puts
  
  q = t.inverse
  puts "P^-1 = "; q.display; puts
  puts "P^-1 * A * P = "; (q * a * t).display; puts
  
  print "size of P's vector is: "
  shownorms(t)
  print "size of P^-1's vector is: "
  shownorms(q)
end

if __FILE__ == $0
  require "rational"
  class Rational < Numeric
    def inspect; to_s; end
  end
  
  def mkentry(dim = 3, no = 0)
    case dim
    when 2
      [
	[2, -1, 2],
	[1, 0, 1],
	[1, 1, 1],
	[1, 1, 2],
      ]
    when 3
      [
	[1, -1, 0, -1, -1, 0], #t**3 - 3*t + 1
	[1, 1, 1, -1, -1, -1],
	[1, 1, 1, -1, -1, -1],
	[1, 0, 1, -1, -1, -1],
	[1, 0, 2, -1, -1, -1],
      ]
    when 4
      [
	[1, 0, 1, 0, 1, 0, 1, 0, 1, 0],
	[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
	[1, 1, 1, 1, 1, 1, 1],
	[1, 2, 1, 2, 1, 0, 1],
#	[1, 0, 2, 1, -1, -1, 1, 2, 0, 1], #irreducible, takes too long time
      ]
    else
      raise
    end[no]
  end
  
  tests = [
    [2, 0],
    [2, 1],
    [2, 2],
    [2, 3],
    [3, 0],
    [3, 1],
    [3, 2],
    [3, 3],
    [3, 4],
    [4, 0],
    [4, 1],
    [4, 2],
    [4, 3],
  ]
#  tests = [[4, 0]]
  tests.each do |dimension, number|
    m = SquareMatrix(Rational, dimension)
    a = m.symmetric(*mkentry(dimension, number))
    analize_symmetric_matrix(a)
  end
end
