#!/usr/bin/env ruby
require("gsl")
require("../gsl_test.rb")
require("eigen.rb")
include GSL::Test

def test_eigen_gen_results(a, b, alpha, beta, evec, count, desc, desc2)
  n = a.size1
  ma = a.to_complex
  mb = b.to_complex
  
  for i in 0...n do
    vi = evec.column(i)
    ai = alpha[i]
    bi = beta[i]
    
    x = mb*vi
    x *= ai
    
    y = ma*vi
    y *= bi
    
    for j in 0...n do
      GSL::Test::test_abs(y[j].real, x[j].real, 1e8*GSL::DBL_EPSILON, 
                          "gen(N=#{n},cnt=#{count}), #{desc}, eigenvalue(#{i},#{j}), real, #{desc2}")
      GSL::Test::test_abs(y[j].imag, x[j].imag, 1e8*GSL::DBL_EPSILON, 
                          "gen(N=#{n},cnt=#{count}), #{desc}, eigenvalue(#{i},#{j}), imag, #{desc2}")
    end
  end
end

def test_eigen_gen_pencil(a, b, count, desc, test_schur, w, wv)
  n = a.size1
  
  aa = a.clone
  bb = b.clone
  
  if test_schur == 1
    alphav, betav, evec, q, z = GSL::Eigen::genv_QZ(aa, bb, wv)
    test_eigen_schur(a, aa, q, z, count, "genv/A", desc)
    test_eigen_schur(b, bb, q, z, count, "genv/B", desc)
  else
    alphav, betav, evec = GSL::Eigen::genv(aa, bb, wv)
  end
  
  test_eigen_gen_results(a, b, alphav, betav, evec, count, desc, "unsorted")
  
  aa = a.clone
  bb = b.clone
  if test_schur == 1
    GSL::Eigen::gen_params(1, 1, 0, w)
    alpha, beta, q, z = GSL::Eigen::gen_QZ(aa, bb, w)
    test_eigen_schur(a, aa, q, z, count, "gen/A", desc)
    test_eigen_schur(b, bb, q, z, count, "gen/B", desc)
  else
    GSL::Eigen::gen_params(0, 0, 0, w)
    alpha, beta = GSL::Eigen::gen(aa, bb, w)
  end
  
  eval = GSL::Vector::Complex.alloc(n)
  evalv = GSL::Vector::Complex.alloc(n)	
  for i in 0...n do
    ai = alpha[i]
    bi = beta[i]
    z = GSL::Complex.alloc(ai.real/bi, ai.imag/bi)
    eval[i] = z
    
    ai = alphav[i]
    bi = betav[i]
    z = GSL::Complex.alloc(ai.real/bi, ai.imag/bi)
    evalv[i] = z
  end
  
  GSL::Eigen::nonsymmv_sort(eval, nil, GSL::EIGEN_SORT_ABS_ASC)
  GSL::Eigen::nonsymmv_sort(evalv, nil, GSL::EIGEN_SORT_ABS_ASC)
  test_eigenvalues_complex(evalv, eval, "gen", desc)
  
  GSL::Eigen::genv_sort(alphav, betav, evec, GSL::EIGEN_SORT_ABS_ASC)
  test_eigen_gen_results(a, b, alphav, betav, evec, count, desc, "abs/asc")
  GSL::Eigen::genv_sort(alphav, betav, evec, GSL::EIGEN_SORT_ABS_DESC)
  test_eigen_gen_results(a, b, alphav, betav, evec, count, desc, "abs/desc")
end

def test_eigen_gen()
  n_max = 20
  rng = GSL::Rng.alloc()
  for n in 1..n_max do
    w = GSL::Eigen::Gen.alloc(n)
    wv = GSL::Eigen::Genv.alloc(n)		
    for i in 0...5 do
      a = create_random_nonsymm_matrix(n, n, rng, -10, 10)
      b = create_random_nonsymm_matrix(n, n, rng, -10, 10)
      test_eigen_gen_pencil(a, b, i, "random", 0, w, wv);
      test_eigen_gen_pencil(a, b, i, "random", 1, w, wv);
    end
  end
  ma = GSL::Matrix.alloc([1, 1, 0, 0, 0, -1, 1, 0, 0], 3, 3)
  mb = GSL::Matrix.alloc([-1, 0, -1, 0, -1, 0, 0, 0, -1], 3, 3)
  w = GSL::Eigen::Gen.alloc(3)
  wv = GSL::Eigen::Genv.alloc(3)	    
  test_eigen_gen_pencil(ma, mb, 0, "integer", 0, w, wv);
  test_eigen_gen_pencil(ma, mb, 0, "integer", 1, w, wv);
end

test_eigen_gen()
