// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2012-2016 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// SPDX-License-Identifier: MPL-2.0

#define EIGEN_RUNTIME_NO_MALLOC
#include "main.h"
#include <limits>
#include <Eigen/Eigenvalues>
#include <Eigen/LU>

template <typename MatrixType>
void generalized_eigensolver_real(const MatrixType& m) {
  /* this test covers the following files:
     GeneralizedEigenSolver.h
  */
  Index rows = m.rows();
  Index cols = m.cols();

  typedef typename MatrixType::Scalar Scalar;
  typedef std::complex<Scalar> ComplexScalar;
  typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;

  MatrixType a = MatrixType::Random(rows, cols);
  MatrixType b = MatrixType::Random(rows, cols);
  MatrixType a1 = MatrixType::Random(rows, cols);
  MatrixType b1 = MatrixType::Random(rows, cols);
  MatrixType spdA = a.adjoint() * a + a1.adjoint() * a1;
  MatrixType spdB = b.adjoint() * b + b1.adjoint() * b1;

  // lets compare to GeneralizedSelfAdjointEigenSolver
  {
    GeneralizedSelfAdjointEigenSolver<MatrixType> symmEig(spdA, spdB);
    GeneralizedEigenSolver<MatrixType> eig(spdA, spdB);

    VERIFY_IS_EQUAL(eig.eigenvalues().imag().cwiseAbs().maxCoeff(), 0);

    VectorType realEigenvalues = eig.eigenvalues().real();
    std::sort(realEigenvalues.data(), realEigenvalues.data() + realEigenvalues.size());
    VERIFY_IS_APPROX(realEigenvalues, symmEig.eigenvalues());

    // check eigenvectors
    typename GeneralizedEigenSolver<MatrixType>::EigenvectorsType D = eig.eigenvalues().asDiagonal();
    typename GeneralizedEigenSolver<MatrixType>::EigenvectorsType V = eig.eigenvectors();
    VERIFY_IS_APPROX(spdA * V, spdB * V * D);
  }

  // non symmetric case:
  {
    GeneralizedEigenSolver<MatrixType> eig(rows);
    eig.compute(a, b);
    for (Index k = 0; k < cols; ++k) {
      Matrix<ComplexScalar, Dynamic, Dynamic> tmp =
          (eig.betas()(k) * a).template cast<ComplexScalar>() - eig.alphas()(k) * b;
      if (tmp.size() > 1 && tmp.norm() > (std::numeric_limits<Scalar>::min)()) tmp /= tmp.norm();
      VERIFY_IS_MUCH_SMALLER_THAN(std::abs(tmp.determinant()), Scalar(1));
    }
    // check eigenvectors
    typename GeneralizedEigenSolver<MatrixType>::EigenvectorsType D = eig.eigenvalues().asDiagonal();
    typename GeneralizedEigenSolver<MatrixType>::EigenvectorsType V = eig.eigenvectors();
    VERIFY_IS_APPROX(a * V, b * V * D);
  }

  // regression test for bug 1098
  {
    GeneralizedSelfAdjointEigenSolver<MatrixType> eig1(a.adjoint() * a, b.adjoint() * b);
    eig1.compute(a.adjoint() * a, b.adjoint() * b);
    GeneralizedEigenSolver<MatrixType> eig2(a.adjoint() * a, b.adjoint() * b);
    eig2.compute(a.adjoint() * a, b.adjoint() * b);
  }

  // check without eigenvectors
  {
    GeneralizedEigenSolver<MatrixType> eig1(spdA, spdB, true);
    GeneralizedEigenSolver<MatrixType> eig2(spdA, spdB, false);
    VERIFY_IS_APPROX(eig1.eigenvalues(), eig2.eigenvalues());
  }
}

template <typename MatrixType>
void generalized_eigensolver_assert() {
  GeneralizedEigenSolver<MatrixType> eig;
  // all raise assert if uninitialized
  VERIFY_RAISES_ASSERT(eig.info());
  VERIFY_RAISES_ASSERT(eig.eigenvectors());
  VERIFY_RAISES_ASSERT(eig.eigenvalues());
  VERIFY_RAISES_ASSERT(eig.alphas());
  VERIFY_RAISES_ASSERT(eig.betas());

  // none raise assert after compute called
  eig.compute(MatrixType::Random(20, 20), MatrixType::Random(20, 20));
  VERIFY(eig.info() == Success);
  eig.eigenvectors();
  eig.eigenvalues();
  eig.alphas();
  eig.betas();

  // eigenvectors() raises assert, if eigenvectors were not requested
  eig.compute(MatrixType::Random(20, 20), MatrixType::Random(20, 20), false);
  VERIFY(eig.info() == Success);
  VERIFY_RAISES_ASSERT(eig.eigenvectors());
  eig.eigenvalues();
  eig.alphas();
  eig.betas();

  // all except info raise assert if realQZ did not converge
  eig.setMaxIterations(0);  // force real QZ to fail.
  eig.compute(MatrixType::Random(20, 20), MatrixType::Random(20, 20));
  VERIFY(eig.info() == NoConvergence);
  VERIFY_RAISES_ASSERT(eig.eigenvectors());
  VERIFY_RAISES_ASSERT(eig.eigenvalues());
  VERIFY_RAISES_ASSERT(eig.alphas());
  VERIFY_RAISES_ASSERT(eig.betas());
}

// Use an unbounded dynamic matrix below the block Householder threshold.
template <typename MatrixType>
void generalized_eigensolver_no_malloc() {
  const Index dim = 24;
  MatrixType A = MatrixType::Random(dim, dim), B = MatrixType::Random(dim, dim);
  GeneralizedEigenSolver<MatrixType> eig(dim);
  internal::set_is_malloc_allowed(false);
  eig.compute(A, B, false);
  internal::set_is_malloc_allowed(true);
  VERIFY_IS_EQUAL(eig.info(), Success);
  const auto alphas = eig.alphas().eval();
  const auto betas = eig.betas().eval();

  for (int i = 0; i < 2; ++i) {
    internal::set_is_malloc_allowed(false);
    eig.compute(A, B, true);
    internal::set_is_malloc_allowed(true);
    VERIFY_IS_EQUAL(eig.info(), Success);
    VERIFY_IS_APPROX(eig.alphas(), alphas);
    VERIFY_IS_APPROX(eig.betas(), betas);
    VERIFY_IS_APPROX(A * eig.eigenvectors() * eig.betas().asDiagonal(),
                     B * eig.eigenvectors() * eig.alphas().asDiagonal());
  }
}

EIGEN_DECLARE_TEST(eigensolver_generalized_real) {
  CALL_SUBTEST_2(generalized_eigensolver_no_malloc<MatrixXd>());
  CALL_SUBTEST_2((generalized_eigensolver_no_malloc<Matrix<double, Dynamic, Dynamic, RowMajor>>()));
  for (int i = 0; i < g_repeat; i++) {
    int s = 0;
    CALL_SUBTEST_1(generalized_eigensolver_real(Matrix4f()));
    s = internal::random<int>(1, EIGEN_TEST_MAX_SIZE / 4);
    CALL_SUBTEST_2(generalized_eigensolver_real(MatrixXd(s, s)));

    // some trivial but implementation-wise special cases
    CALL_SUBTEST_2(generalized_eigensolver_real(MatrixXd(1, 1)));
    CALL_SUBTEST_2(generalized_eigensolver_real(MatrixXd(2, 2)));
    CALL_SUBTEST_3(generalized_eigensolver_real(Matrix<double, 1, 1>()));
    CALL_SUBTEST_4(generalized_eigensolver_real(Matrix2d()));
    CALL_SUBTEST_5(generalized_eigensolver_assert<MatrixXd>());
    TEST_SET_BUT_UNUSED_VARIABLE(s);
  }
}
