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

#include "main.h"
#include <Eigen/LevenbergMarquardt>

using namespace std;
using namespace Eigen;

template <typename Scalar>
struct sparseGaussianTest : SparseFunctor<Scalar, int>
{
  typedef Matrix<Scalar,Dynamic,1> VectorType;
  typedef SparseFunctor<Scalar,int> Base;
  typedef typename Base::JacobianType JacobianType;
  sparseGaussianTest(int inputs, int values) : SparseFunctor<Scalar,int>(inputs,values)
  { }
  
  VectorType model(const VectorType& uv, VectorType& x)
  {
    VectorType y; //Change this to use expression template
    int m = Base::values(); 
    int n = Base::inputs();
    eigen_assert(uv.size()%2 == 0);
    eigen_assert(uv.size() == n);
    eigen_assert(x.size() == m);
    y.setZero(m);
    int half = n/2;
    VectorBlock<const VectorType> u(uv, 0, half);
    VectorBlock<const VectorType> v(uv, half, half);
    Scalar coeff;
    for (int j = 0; j < m; j++)
    {
      for (int i = 0; i < half; i++) 
      {
        coeff = (x(j)-i)/v(i);
        coeff *= coeff;
        if (coeff < 1. && coeff > 0.)
          y(j) += u(i)*std::pow((1-coeff), 2);
      }
    }
    return y;
  }
  void initPoints(VectorType& uv_ref, VectorType& x)
  {
    m_x = x;
    m_y = this->model(uv_ref,x);
  }
  int operator()(const VectorType& uv, VectorType& fvec)
  {
    int m = Base::values(); 
    int n = Base::inputs();
    eigen_assert(uv.size()%2 == 0);
    eigen_assert(uv.size() == n);
    int half = n/2;
    VectorBlock<const VectorType> u(uv, 0, half);
    VectorBlock<const VectorType> v(uv, half, half);
    fvec = m_y;
    Scalar coeff;
    for (int j = 0; j < m; j++)
    {
      for (int i = 0; i < half; i++)
      {
        coeff = (m_x(j)-i)/v(i);
        coeff *= coeff;
        if (coeff < 1. && coeff > 0.)
          fvec(j) -= u(i)*std::pow((1-coeff), 2);
      }
    }
    return 0;
  }
  
  int df(const VectorType& uv, JacobianType& fjac)
  {
    int m = Base::values(); 
    int n = Base::inputs();
    eigen_assert(n == uv.size());
    eigen_assert(fjac.rows() == m);
    eigen_assert(fjac.cols() == n);
    int half = n/2;
    VectorBlock<const VectorType> u(uv, 0, half);
    VectorBlock<const VectorType> v(uv, half, half);
    Scalar coeff;
    
    //Derivatives with respect to u
    for (int col = 0; col < half; col++)
    {
      for (int row = 0; row < m; row++)
      {
        coeff = (m_x(row)-col)/v(col);
          coeff = coeff*coeff;
        if(coeff < 1. && coeff > 0.)
        {
          fjac.coeffRef(row,col) = -(1-coeff)*(1-coeff);
        }
      }
    }
    //Derivatives with respect to v
    for (int col = 0; col < half; col++)
    {
      for (int row = 0; row < m; row++)
      {
        coeff = (m_x(row)-col)/v(col);
        coeff = coeff*coeff;
        if(coeff < 1. && coeff > 0.)
        {
          fjac.coeffRef(row,col+half) = -4 * (u(col)/v(col))*coeff*(1-coeff);
        }
      }
    }
    return 0;
  }
  
  VectorType m_x, m_y; //Data points
};


template<typename T>
void test_sparseLM_T()
{
  typedef Matrix<T,Dynamic,1> VectorType;
  
  int inputs = 10;
  int values = 2000;
  sparseGaussianTest<T> sparse_gaussian(inputs, values);
  VectorType uv(inputs),uv_ref(inputs);
  VectorType x(values);
  // Generate the reference solution 
  uv_ref << -2, 1, 4 ,8, 6, 1.8, 1.2, 1.1, 1.9 , 3;
  //Generate the reference data points
  x.setRandom();
  x = 10*x;
  x.array() += 10;
  sparse_gaussian.initPoints(uv_ref, x);
  
  
  // Generate the initial parameters 
  VectorBlock<VectorType> u(uv, 0, inputs/2); 
  VectorBlock<VectorType> v(uv, inputs/2, inputs/2);
  v.setOnes();
  //Generate u or Solve for u from v
  u.setOnes();
  
  // Solve the optimization problem
  LevenbergMarquardt<sparseGaussianTest<T> > lm(sparse_gaussian);
  int info;
//   info = lm.minimize(uv);
  
  VERIFY_IS_EQUAL(info,1);
    // Do a step by step solution and save the residual 
  int maxiter = 200;
  int iter = 0;
  MatrixXd Err(values, maxiter);
  MatrixXd Mod(values, maxiter);
  LevenbergMarquardtSpace::Status status; 
  status = lm.minimizeInit(uv);
  if (status==LevenbergMarquardtSpace::ImproperInputParameters)
      return ;

}
EIGEN_DECLARE_TEST(sparseLM)
{
  CALL_SUBTEST_1(test_sparseLM_T<double>());
  
  // CALL_SUBTEST_2(test_sparseLM_T<std::complex<double>());
}
