// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2012 Desire Nuentsa Wakam <desire.nuentsa_wakam@inria.fr>
// Copyright (C) 2014 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
#include "sparse.h"
#include <Eigen/SparseQR>

template <typename MatrixType, typename DenseMat>
int generate_sparse_rectangular_problem(MatrixType& A, DenseMat& dA, int maxRows = 300, int maxCols = 150) {
  eigen_assert(maxRows >= maxCols);
  typedef typename MatrixType::Scalar Scalar;
  int rows = internal::random<int>(1, maxRows);
  int cols = internal::random<int>(1, maxCols);
  double density = (std::max)(8. / (rows * cols), 0.01);

  A.resize(rows, cols);
  dA.resize(rows, cols);
  initSparse<Scalar>(density, dA, A, ForceNonZeroDiag);
  A.makeCompressed();
  int nop = internal::random<int>(0, internal::random<double>(0, 1) > 0.5 ? cols / 2 : 0);
  for (int k = 0; k < nop; ++k) {
    int j0 = internal::random<int>(0, cols - 1);
    int j1 = internal::random<int>(0, cols - 1);
    Scalar s = internal::random<Scalar>();
    A.col(j0) = s * A.col(j1);
    dA.col(j0) = s * dA.col(j1);
  }

  //   if(rows<cols) {
  //     A.conservativeResize(cols,cols);
  //     dA.conservativeResize(cols,cols);
  //     dA.bottomRows(cols-rows).setZero();
  //   }

  return rows;
}

template <typename Scalar>
void test_sparseqr_scalar() {
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef SparseMatrix<Scalar, ColMajor> MatrixType;
  typedef Matrix<Scalar, Dynamic, Dynamic> DenseMat;
  typedef Matrix<Scalar, Dynamic, 1> DenseVector;
  MatrixType A;
  DenseMat dA;
  DenseVector refX, x, b;
  SparseQR<MatrixType, COLAMDOrdering<int> > solver;
  generate_sparse_rectangular_problem(A, dA);

  b = dA * DenseVector::Random(A.cols());
  solver.compute(A);

  // Q should be MxM
  VERIFY_IS_EQUAL(solver.matrixQ().rows(), A.rows());
  VERIFY_IS_EQUAL(solver.matrixQ().cols(), A.rows());

  // R should be MxN
  VERIFY_IS_EQUAL(solver.matrixR().rows(), A.rows());
  VERIFY_IS_EQUAL(solver.matrixR().cols(), A.cols());

  // Q and R can be multiplied
  DenseMat recoveredA = solver.matrixQ() * DenseMat(solver.matrixR().template triangularView<Upper>()) *
                        solver.colsPermutation().transpose();
  VERIFY_IS_EQUAL(recoveredA.rows(), A.rows());
  VERIFY_IS_EQUAL(recoveredA.cols(), A.cols());

  // and in the full rank case the original matrix is recovered
  if (solver.rank() == A.cols()) {
    VERIFY_IS_APPROX(A, recoveredA);
  }

  if (internal::random<float>(0, 1) > 0.5f)
    solver.factorize(A);  // this checks that calling analyzePattern is not needed if the pattern do not change.
  if (solver.info() != Success) {
    std::cerr << "sparse QR factorization failed\n";
    exit(0);
    return;
  }
  x = solver.solve(b);
  if (solver.info() != Success) {
    std::cerr << "sparse QR factorization failed\n";
    exit(0);
    return;
  }

  // Compare with a dense QR solver
  ColPivHouseholderQR<DenseMat> dqr(dA);
  refX = dqr.solve(b);

  bool rank_deficient = A.cols() > A.rows() || dqr.rank() < A.cols();
  if (rank_deficient) {
    // rank deficient problem -> we might have to increase the threshold
    // to get a correct solution.
    RealScalar th =
        RealScalar(20) * dA.colwise().norm().maxCoeff() * (A.rows() + A.cols()) * NumTraits<RealScalar>::epsilon();
    for (Index k = 0; (k < 16) && !test_isApprox(A * x, b); ++k) {
      th *= RealScalar(10);
      solver.setPivotThreshold(th);
      solver.compute(A);
      x = solver.solve(b);
    }
  }

  VERIFY_IS_APPROX(A * x, b);

  // For rank deficient problem, the estimated rank might
  // be slightly off, so let's only raise a warning in such cases.
  if (rank_deficient) ++g_test_level;
  VERIFY_IS_EQUAL(solver.rank(), dqr.rank());
  if (rank_deficient) --g_test_level;

  if (solver.rank() == A.cols())  // full rank
    VERIFY_IS_APPROX(x, refX);
  //   else
  //     VERIFY((dA * refX - b).norm() * 2 > (A * x - b).norm() );

  // Compute explicitly the matrix Q
  MatrixType Q, QtQ, idM;
  Q = solver.matrixQ();
  // Check  ||Q' * Q - I ||
  QtQ = Q * Q.adjoint();
  idM.resize(Q.rows(), Q.rows());
  idM.setIdentity();
  VERIFY(idM.isApprox(QtQ));

  // Q to dense
  DenseMat dQ;
  dQ = solver.matrixQ();
  VERIFY_IS_APPROX(Q, dQ);
}
EIGEN_DECLARE_TEST(sparseqr) {
  for (int i = 0; i < g_repeat; ++i) {
    CALL_SUBTEST_1(test_sparseqr_scalar<double>());
    CALL_SUBTEST_2(test_sparseqr_scalar<std::complex<double> >());
  }
}
