// [ref] ${FANN_HOME}/examples/simple_pattern_recognition/simple_function_regression_application.cpp
void simple_function_regression_example()
{
	std::cout << "OpenNN. Simple Function Regression Application." << std::endl;

	// Data set object
	OpenNN::DataSet data_set;
	data_set.load_data("./data/neural_network/opennn/simple_function_regression.dat");

	OpenNN::VariablesInformation* variables_information_pointer = data_set.get_variables_information_pointer();

	variables_information_pointer->set_name(0, "x");   
	variables_information_pointer->set_name(1, "y");   

	OpenNN::Vector<OpenNN::Vector<std::string> > inputs_targets_information = variables_information_pointer->arrange_inputs_targets_information();

	OpenNN::InstancesInformation *instances_information_pointer = data_set.get_instances_information_pointer();
	instances_information_pointer->split_random_indices(0.75, 0.1, 0.25);

	const OpenNN::Vector<OpenNN::Vector<double> > inputs_targets_minimum_maximum = data_set.scale_inputs_targets_minimum_maximum();

	// Neural network
	OpenNN::NeuralNetwork neural_network(1, 3, 1);
	neural_network.set_inputs_outputs_information(inputs_targets_information);
	neural_network.set_inputs_outputs_minimums_maximums(inputs_targets_minimum_maximum);

	// Performance functional object
	OpenNN::PerformanceFunctional performance_functional(&neural_network, &data_set);

	// Training strategy
	OpenNN::TrainingStrategy training_strategy(&performance_functional);
	training_strategy.perform_training();

	neural_network.set_inputs_scaling_outputs_unscaling_methods("MeanStandardDeviation");

	// Testing analysis object
	OpenNN::TestingAnalysis testing_analysis(&neural_network, &data_set);
	OpenNN::FunctionRegressionTesting::LinearRegressionAnalysisResults linear_regression_analysis_results = testing_analysis.get_function_regression_testing_pointer()->perform_linear_regression_analysis();

	std::cout << "Linear regression parameters:" << std::endl
		<< "Intercept: " << linear_regression_analysis_results.linear_regression_parameters[0][0] << std::endl
		<< "Slope: " << linear_regression_analysis_results.linear_regression_parameters[0][1] << std::endl;

	// Save results
	data_set.save("./data/neural_network/opennn/simple_function_regression/data_set.xml");

	neural_network.save("./data/neural_network/opennn/simple_function_regression/neural_network.xml");
	neural_network.save_expression("./data/neural_network/opennn/simple_function_regression/expression.txt");

	performance_functional.save("./data/neural_network/opennn/simple_function_regression/performance_functional.xml");

	training_strategy.save("./data/neural_network/opennn/simple_function_regression/training_strategy.xml");

	linear_regression_analysis_results.save("./data/neural_network/opennn/simple_function_regression/linear_regression_analysis_results.dat");
}
Matrix<double> InputsSelectionAlgorithm::calculate_logistic_correlations(void) const
{
    // Control sentence (if debug)

#ifdef __OPENNN_DEBUG__

    std::ostringstream buffer;

    if(!training_strategy_pointer)
    {
        buffer << "OpenNN Exception: InputsSelectionAlgorithm class.\n"
               << "void check(void) const method.\n"
               << "Pointer to training strategy is NULL.\n";

        throw std::logic_error(buffer.str());
    }

    // Performance functional stuff


    if(!training_strategy_pointer->has_performance_functional())
    {
        buffer << "OpenNN Exception: InputsSelectionAlgorithm class.\n"
               << "void check(void) const method.\n"
               << "Pointer to performance functional is NULL.\n";

        throw std::logic_error(buffer.str());
    }

    if(!training_strategy_pointer->get_performance_functional_pointer()->has_data_set())
    {
        buffer << "OpenNN Exception: InputsSelectionAlgorithm class.\n"
               << "void check(void) const method.\n"
               << "Pointer to data set is NULL.\n";

        throw std::logic_error(buffer.str());
    }

#endif

    // Problem stuff

    const PerformanceFunctional* performance_functional_pointer = training_strategy_pointer->get_performance_functional_pointer();

    const DataSet* data_set_pointer = performance_functional_pointer->get_data_set_pointer();

    const Variables& variables = data_set_pointer->get_variables();

    const size_t inputs_number = variables.count_inputs_number();
    const size_t targets_number = variables.count_targets_number();

    const Vector<size_t> input_indices = variables.arrange_inputs_indices();
    const Vector<size_t> target_indices = variables.arrange_targets_indices();

    Matrix<double> correlations(inputs_number, targets_number);

    for(size_t i = 0; i < inputs_number; i++)
    {
        const Vector<double> inputs = data_set_pointer->get_variable(input_indices[i]);

        for(size_t j = 0; j < targets_number; j++)
        {

            const Vector<double> targets = data_set_pointer->get_variable(target_indices[j]);

            Matrix<double> data(inputs.size(), 2);

            data.set_column(0, inputs);
            data.set_column(1, targets);

            DataSet data_set(data);

            data_set.scale_inputs("MinimumMaximum");

            Instances* instances_pointer = data_set.get_instances_pointer();

            instances_pointer->set_training();

            NeuralNetwork neural_network(1, 1);

            MultilayerPerceptron* multilayer_perceptron_pointer = neural_network.get_multilayer_perceptron_pointer();

            multilayer_perceptron_pointer->set_layer_activation_function(0, Perceptron::Logistic);

            PerformanceFunctional performance_functional(&neural_network, &data_set);

            performance_functional.set_objective_type(PerformanceFunctional::MEAN_SQUARED_ERROR_OBJECTIVE);

            TrainingStrategy training_strategy(&performance_functional);

            training_strategy.set_main_type(TrainingStrategy::LEVENBERG_MARQUARDT_ALGORITHM);

            training_strategy.get_Levenberg_Marquardt_algorithm_pointer()->set_display(false);

            training_strategy.get_Levenberg_Marquardt_algorithm_pointer()->set_performance_goal(0.0);

            training_strategy.get_Levenberg_Marquardt_algorithm_pointer()->set_gradient_norm_goal(0.0);

            training_strategy.get_Levenberg_Marquardt_algorithm_pointer()->set_minimum_performance_increase(0.0);

            training_strategy.perform_training();

            const Vector<double> outputs = neural_network.calculate_output_data(inputs.to_column_matrix()).to_vector();

            correlations(i,j) = targets.calculate_linear_correlation(outputs);
        }
    }

    return(correlations);
}