%% Scenario1 (TSK - Airfoil Self-Noise)
%
% Assignment 3 in Fuzzy systems
% 
% author:
%   Christos Choutouridis ΑΕΜ 8997
%   cchoutou@ece.auth.gr
%
clear; clc; close all;


% Configuration
% --------------------------------
config.mf_types    = ["constant", "constant", "linear", "linear"];
config.num_mf      = [2, 3, 2, 3];  % #MFs per input
config.model_names = ["TSK0-2MF", "TSK0-3MF", "TSK1-2MF", "TSK1-3MF"];
config.Nepochs     = 100;

rng(42,'twister');

% Load dataset (Airfoil Self-Noise: 5 inputs, 1 target)
data = load("Datasets/airfoil_self_noise.dat");
% Split data: 60% train, 20% val, 20% check(test)
[X_trn, y_trn, X_val, y_val, X_chk, y_chk] = split_data(data, [0.6 0.2 0.2], 42);
% Preprocess inputs (mode=1 -> MinMax to [0,1])
[X_trn, X_val, X_chk, stats] = preprocess_data(X_trn, X_val, X_chk, 1);

% Pack data for anfis/evalfis convenience
trn_data = [X_trn, y_trn];
val_data = [X_val, y_val];
chk_X    = X_chk;
chk_y    = y_chk;


% Results
T = table(['MSE '; 'RMSE'; 'R2  '; 'NMSE'; 'NDEI'], 'VariableNames', {'Metrics'});

all_models = cell(1,4);
all_trnErr = cell(1,4);
all_valErr = cell(1,4);

for i = 1:length(config.mf_types)
    fprintf('\n');
    fprintf('Model %d: %s (gbellmf × %d per input)\n', i, config.model_names(i), config.num_mf(i));
    fprintf('=====================================\n');

    % Step 1 -  Initial FIS via Grid Partition
    opt_g = genfisOptions("GridPartition", ...
        "InputMembershipFunctionType", "gbellmf", ...
        "NumMembershipFunctions", config.num_mf(i), ...
        "OutputMembershipFunctionType", config.mf_types(i));

    init_fis = genfis(X_trn, y_trn, opt_g);

    % Info rules and MF
    nRules = numel(init_fis.Rules);
    fprintf('Initial rules: %d\n', nRules);

    % Step 2 - Train with ANFIS (Hybrid: BP + LSE)
    opt_a = anfisOptions( ...
        "InitialFis", init_fis, ...
        "ValidationData", val_data, ...
        "EpochNumber", config.Nepochs, ...
        "OptimizationMethod", 1 ... % 1=Hybrid
    );
    [trn_fis, trn_error, ~, val_fis, val_error] = anfis(trn_data, opt_a);

    final_fis = val_fis;    % Select final

    % Step 3 -  Evaluate on Check/Test set
    y_hat = evalfis(final_fis, chk_X);
    [mse, rmse, r2, nmse, ndei] = evaluate(y_hat, chk_y);

    % Print & store metrics
    fprintf('MSE : %g\n', mse);
    fprintf('RMSE: %g\n', rmse);
    fprintf('R2  : %g\n', r2);
    fprintf('NMSE: %g\n', nmse);
    fprintf('NDEI: %g\n', ndei);

    T = addvars(T, [mse; rmse; r2; nmse; ndei], 'NewVariableNames', sprintf('Model_%d',i));

    % Plots & figure exports
    %   - MFs before/after
    %   - Learning curves
    %   - Predicted vs Actual
    %   - Prediction Error
    plot_results1(init_fis, final_fis, trn_error, val_error, y_chk, y_hat, i);

end

% Show and save table
disp(T);
writetable(T, 'scenario1_metrics.csv');