/* -*- mia-c++  -*-
 *
 * This file is part of MIA - a toolbox for medical image analysis 
 * Copyright (c) Leipzig, Madrid 1999-2017 Gert Wollny
 *
 * MIA is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with MIA; if not, see <http://www.gnu.org/licenses/>.
 *
 */

#include <mia/internal/plugintester.hh>
#include <mia/core/minimizer/gdas.hh>
using namespace mia; 
using namespace gdas;


class TestCFDFProblem : public CMinimizer::Problem {
public:
	TestCFDFProblem(); 
private: 
	virtual double  do_f(const CDoubleVector& x); 
	virtual void    do_df(const CDoubleVector&  x, CDoubleVector&  g); 
	virtual double  do_fdf(const CDoubleVector&  x, CDoubleVector&  g); 
	virtual size_t do_size() const; 
	std::vector<double> m_p; 
	size_t m_size; 
}; 

BOOST_AUTO_TEST_CASE( test_cfdf_multmin ) 
{
        auto minimizer = BOOST_TEST_create_from_plugin<CGDSAMinimizerPlugin>("gdas:maxiter=300,min-step=0.00001"
                                                                             ",max-step=3,xtola=0.0001,ftolr=0.0");
        
	CMinimizer::PProblem problem(new TestCFDFProblem); 
	problem->add(property_gradient); 
	minimizer->set_problem(problem); 
	
	CDoubleVector x(2); 
	x[0] = 5.0; 
	x[1] = 7.0; 
	
	BOOST_REQUIRE(minimizer->run(x)==  CMinimizer::success); 
	BOOST_CHECK_CLOSE(x[0], 1.0, 0.1); 
	BOOST_CHECK_CLOSE(x[1], 2.0, 0.1); 
}

TestCFDFProblem::TestCFDFProblem():
	m_p(5), 
	m_size(2)
{
	double p_init[5] = {1.0, 2.0, 10.0, 20.0, 30.0 }; 
	copy(p_init, p_init+5, m_p.begin()); 
}

size_t TestCFDFProblem::do_size()const 
{
	return m_size; 
}

double  TestCFDFProblem::do_f(const CDoubleVector&  v)
{

	const double x = v[0];
	const double y = v[1];
	
	return m_p[2] * (x - m_p[0]) * (x - m_p[0]) +
		m_p[3] * (y - m_p[1]) * (y - m_p[1]) + m_p[4]; 
	
}

void    TestCFDFProblem::do_df(const CDoubleVector&  v, CDoubleVector&  g)
{
	const double x = v[0];
	const double y = v[1];
      
	g[0] = 2.0 * m_p[2] * (x - m_p[0]);
	g[1] = 2.0 * m_p[3] * (y - m_p[1]);
}

double  TestCFDFProblem::do_fdf(const CDoubleVector&  x, CDoubleVector&  g)
{
	do_df(x,g); 
	return do_f(x); 
}


class TestCFProblem : public CMinimizer::Problem {
public:
	TestCFProblem(); 
private: 
	virtual double  do_f(const CDoubleVector& x); 
	virtual void    do_df(const CDoubleVector& x, CDoubleVector&  g); 
	virtual double  do_fdf(const CDoubleVector& x, CDoubleVector&  g); 
	virtual size_t do_size() const; 
	std::vector<double> m_p; 
	size_t m_size; 
}; 


