echo on
clear
%    Informações sobre o arquivo de entrada
methodsNo    = 2;     % Número de métodos
propNo       = 7;     % Número de propriedades
errorRatesNo = 2;     % Número de taxas de erro
patternsNo   = 438;   % Número de padrões
columnsNo = propNo + errorRatesNo * methodsNo;

%   Informações sobre o treinamento (Valores a serem variados em busca da
%   melhor configuração
learnRate = [0.001, 0.01, 0.1];
learnRateCount = 3;

qntHidNeur = [1, 2, 3, 4, 5];
qntHidNeurCount = 5;

learnAlg = {'traingdm';'trainlm';'trainoss'};
learnAlgCount = 3;

iterationsNo = 1000;

% Informações sobre o experimento
inputNeurNo = 2;
outputNeurNo = 1; 
columnsQnt = inputNeurNo + outputNeurNo;

echo off

%   Normalização
inputFile = fopen('beagle_hmc.txt');
data = fscanf(inputFile,'%f',[columnsNo, patternsNo]);

% for i = 1 : propNo
%     maxValue = max(data(i,:));
%     minValue = min(data(i,:));
%     for j = 1: patternsNo
%         data(i, j) = (data(i, j) - minValue)/(maxValue - minValue);
%     end
% end

fclose(inputFile);

resultado = fopen('Resultado.txt', 'w+t');

for iA = 1 : propNo - 1
    for iB = (iA + 1) : propNo
		for o = 1 : errorRatesNo * methodsNo
        
			fprintf('\nTreinando ...\n%s-%s saída %s\n',int2str(iA), int2str(iB), int2str(o));
			fprintf('\n');
			
			patterns = [data(iA, :); data(iB, :); data(o + propNo, :)];

			%   Particionamento dos dados
			trainingPatternsNo = 0.5 * patternsNo;
			validationPatternsNo = ceil(0.25 * patternsNo);
			testPatternsNo = floor(0.25 * patternsNo);

			trainingPatterns = patterns(1:columnsQnt, 1:trainingPatternsNo);
			trainingInputs = trainingPatterns(1:inputNeurNo, 1:trainingPatternsNo);
			trainingOutputs = trainingPatterns((inputNeurNo + 1):columnsQnt, 1:trainingPatternsNo);

			validationPatterns = patterns(1:columnsQnt, (trainingPatternsNo + 1):(trainingPatternsNo + validationPatternsNo));
			validationInputs = validationPatterns(1:inputNeurNo, 1:validationPatternsNo);
			validationOutputs = validationPatterns((inputNeurNo + 1):columnsQnt, 1:validationPatternsNo);

			testPatterns = patterns(1:columnsQnt, (trainingPatternsNo + validationPatternsNo + 1):patternsNo);
			testInputs = testPatterns(1:inputNeurNo, 1:testPatternsNo);
			testOutputs = testPatterns((inputNeurNo + 1):columnsQnt, 1:testPatternsNo);

			lessErrorTest = 100000;

			for iLR = 1:learnRateCount
				lr = learnRate(iLR);

				for iQHN = 1:qntHidNeurCount
					qhn = qntHidNeur(iQHN);

					for iLA = 1:learnAlgCount
						str2 = cellstr(learnAlg);
						la = char(str2(iLA));

						info = sprintf('%1.3f\t%d\t%s', lr, qhn, la);              

						network = newff(trainingInputs, trainingOutputs, qhn,{'tansig','tansig'},la,'learngd','mse');
						% intervalMatrix                   : indica que todas as entradas possuem valores na faixa entre 0 e 1
						% [qhn outputNeurNo]               : indica a quantidade de nodos escondidos e de saida da rede
						% {af,af}                          : indica que os nodos das camadas escondida e de saida terao determinada funcao de ativação 
						% la,'learngd'                     : indica que o treinamento vai ser feito com gradiente descendente (backpropagation)
						% 'mse'                            : indica que o erro a ser utilizado vai ser MSE (média dos erros quadraticos)

						% Inicializa os pesos da rede criada
						network = init(network);

						%   Parametros do treinamento
						rede.trainParam.epochs   = iterationsNo;    % Maximo numero de iteracoes
						rede.trainParam.lr       = lr;              % Taxa de aprendizado
						rede.trainParam.goal     = 0;               % Criterio de minimo erro de treinamento
						rede.trainParam.max_fail = 7;              % Criterio de quantidade maxima de falhas na validacao
						rede.trainParam.min_grad = 0;               % Criterio de gradiente minimo
						rede.trainParam.show     = NaN;             % Iteracoes entre exibicoes na tela (preenchendo com 'NaN', nao exibe na tela)
						rede.trainParam.time     = inf;             % Tempo maximo (em segundos) para o treinamento

						validationSet.P = validationInputs;    % Entradas da validacao
						validationSet.T = validationOutputs;   % Saidas desejadas da validacao

						%   Treinando a rede
						[newNetwork,performance,outputs,errors] = train(network,trainingInputs,trainingOutputs,[],[],validationSet);
						% newNetwork   : rede apos treinamento
						% performance  : apresenta os seguintes resultados
						%              desempenho.perf  - vetor com os erros de treinamento de todas as iteracoes 
						%              desempenho.vperf - vetor com os erros de validacao de todas as iteracoes 
						%              desempenho.epoch - vetor com as iteracoes efetuadas
						% outputs      : matriz contendo as saidas da rede para cada padrao de treinamento
						% errors       : matriz contendo os erros para cada padrao de treinamento

						%    Testando a rede
						[testOutput,Pf,Af,testErrors,testPerformance] = sim(newNetwork,testInputs,[],[],testOutputs);
						% testOutputs     : matriz contendo as saidas da rede para cada padrao de teste
						% Pf,Af           : matrizes utilizadas apenas quando se usam delays)
						% testErrors      : matriz contendo os erros para cada padrao de teste
						% testPerformance : erro de teste (neste exemplo,
						% escolheu-se erro MSE)

						if testPerformance < lessErrorTest
							lessErrorTest = testPerformance;
							bestConfiguration = info;
						end

						close all hidden
						
					end
				end
			end
			fprintf(resultado, '%s\t%6.10f\n', bestConfiguration, lessErrorTest);
		end
    end
end
fclose(resultado);
    
