void NumericalDifferentiationTest::test_calculate_Hessian(void)
{
   message += "test_calculate_Hessian\n";

   NumericalDifferentiation nd;

   Vector<double> x;
   Matrix<double> H;
	   
   // Test

   nd.set_numerical_differentiation_method(NumericalDifferentiation::ForwardDifferences);

   x.set(2, 0.0);

   H = nd.calculate_Hessian(*this, &NumericalDifferentiationTest::f2, x);

   assert_true(H.get_rows_number() == 2, LOG);
   assert_true(H.get_columns_number() == 2, LOG);
   assert_true(H == 0.0, LOG);

   // Test

   nd.set_numerical_differentiation_method(NumericalDifferentiation::CentralDifferences);

   x.set(2, 0.0);

   H = nd.calculate_Hessian(*this, &NumericalDifferentiationTest::f2, x);

   assert_true(H.get_rows_number() == 2, LOG);
   assert_true(H.get_columns_number() == 2, LOG);
   assert_true(H == 0.0, LOG);
}
void LevenbergMarquardtAlgorithmTest::test_calculate_Hessian_approximation(void)
{
   message += "test_calculate_Hessian_approximation\n";

   NumericalDifferentiation nd;

   NeuralNetwork nn;

   size_t parameters_number;

   Vector<double> parameters;

   DataSet ds;

   PerformanceFunctional pf(&nn, &ds);

   pf.set_error_type(PerformanceFunctional::SUM_SQUARED_ERROR);

   Matrix<double> terms_Jacobian;
   Matrix<double> Hessian;
   Matrix<double> numerical_Hessian;
   Matrix<double> Hessian_approximation;

   LevenbergMarquardtAlgorithm lma(&pf);
   
   // Test

   nn.set(1, 2);
   nn.initialize_parameters(0.0);

   parameters_number = nn.count_parameters_number();

   ds.set(1,2,2);
   ds.initialize_data(0.0);

   terms_Jacobian = pf.calculate_terms_Jacobian();

   Hessian_approximation = lma.calculate_Hessian_approximation(terms_Jacobian);

   assert_true(Hessian_approximation.get_rows_number() == parameters_number, LOG);
   assert_true(Hessian_approximation.get_columns_number() == parameters_number, LOG);
   assert_true(Hessian_approximation.is_symmetric(), LOG);

   // Test

   pf.set_error_type(PerformanceFunctional::NORMALIZED_SQUARED_ERROR);

   nn.set(1,1,2);
   nn.randomize_parameters_normal();

   parameters_number = nn.count_parameters_number();

   ds.set(1,2,3);
   ds.randomize_data_normal();

   terms_Jacobian = pf.calculate_terms_Jacobian();

   Hessian_approximation = lma.calculate_Hessian_approximation(terms_Jacobian);

   assert_true(Hessian_approximation.get_rows_number() == parameters_number, LOG);
   assert_true(Hessian_approximation.get_columns_number() == parameters_number, LOG);
   assert_true(Hessian_approximation.is_symmetric(), LOG);

   // Test

   nn.set(2);

   nn.randomize_parameters_normal();

   MockErrorTerm* mptp = new MockErrorTerm(&nn);

   pf.set_user_error_pointer(mptp);

   terms_Jacobian = pf.calculate_terms_Jacobian();

   Hessian = pf.calculate_Hessian();

   lma.set_damping_parameter(0.0);

   assert_true((lma.calculate_Hessian_approximation(terms_Jacobian) - Hessian).calculate_absolute_value() < 1.0e-3, LOG);

   // Test

   pf.set_error_type(PerformanceFunctional::SUM_SQUARED_ERROR);

   ds.set(1, 1, 1);

   ds.randomize_data_normal();

   nn.set(1, 1);

   parameters = nn.arrange_parameters();

   nn.randomize_parameters_normal();

   numerical_Hessian = nd.calculate_Hessian(pf, &PerformanceFunctional::calculate_performance, parameters);

   terms_Jacobian = pf.calculate_terms_Jacobian();

   Hessian_approximation = lma.calculate_Hessian_approximation(terms_Jacobian);

   assert_true((numerical_Hessian - Hessian_approximation).calculate_absolute_value() >= 0.0, LOG);

}