package org.algorithm.core.neural.neuroph;

import org.neuroph.core.data.DataSet;
import org.neuroph.core.data.DataSetRow;
import org.neuroph.core.events.LearningEvent;
import org.neuroph.core.events.LearningEventListener;
import org.neuroph.core.learning.LearningRule;
import org.neuroph.nnet.MultiLayerPerceptron;
import org.neuroph.nnet.learning.BackPropagation;
import org.neuroph.util.TransferFunctionType;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @Auther: fyeman
 * @Date: 2018/7/31/031 19:06
 * @Description:
 */
public class NeurophLearning implements LearningEventListener {

    private List<String> allInputNameList = new ArrayList<>();
    private List<String> allOutputNameList = new ArrayList<>();

    public static void main(String args[]) {
        NeurophLearning learning = new NeurophLearning();
        DataSet trainingDataSet = new DataSet(learning.allInputNameList.size(), learning.allOutputNameList.size());
        learning.initDataSet(trainingDataSet);
        learning.train(trainingDataSet);
    }

    public void train(DataSet trainingDataSet) {
        // 转移函数采用sigmoid,也可以用tanh之类的
        // 三个层，输入错两个单元，隐层3个单元，输出层1个单元
        MultiLayerPerceptron multiLayerPerceptron = new MultiLayerPerceptron(TransferFunctionType.SIGMOID, allInputNameList.size(), 100, allOutputNameList.size());
        //反向误差传播
        multiLayerPerceptron.setLearningRule(new BackPropagation());

        LearningRule learningRule = multiLayerPerceptron.getLearningRule();
        learningRule.addListener(this);

        // 训练XOR集
        System.out.println("XOR集训练神经网络...");
        multiLayerPerceptron.learn(trainingDataSet);

        test(multiLayerPerceptron, trainingDataSet);

    }

    public static void test(MultiLayerPerceptron multiLayerPerceptron, DataSet trainingDataSet) {
        for(DataSetRow testSetRow : trainingDataSet.getRows()) {
            multiLayerPerceptron.setInput(testSetRow.getInput());
            multiLayerPerceptron.calculate();
            double[] networkOutput = multiLayerPerceptron.getOutput();

            System.out.print("Input: " + Arrays.toString( testSetRow.getInput() ) );
            System.out.println(" Output: " + Arrays.toString( networkOutput) );
        }
    }

    @Override
    public void handleLearningEvent(LearningEvent event) {
        BackPropagation bp = (BackPropagation)event.getSource();
        if (event.getEventType() != LearningEvent.Type.LEARNING_STOPPED)
            System.out.println(bp.getCurrentIteration() + ". iteration : "+ bp.getTotalNetworkError());
    }

    public void initDataSet(DataSet trainingDataSet) {
    }

}
