package com.john;

import java.util.Random;

/**
 * Neural Network (Multilayer Perceptron) as the Client AI
 */
public class NeuralNetwork {

    float [] [] data;
    float [] [] weight1;
    float [] [] z2;
    float [] [] weight2;
    float [] [] yHat;
    int inputLayerDimensions;
    int hiddenLayerDimensions;
    int outputLayerDimensions;
    int numdata;
    float [][] labeledData;
    Random r = new Random();
    /*
    Initialization of the NeuralNetwork
     */
    NeuralNetwork(int inputLayerDimensions, int hiddenLayerDimensions, int outputLayerDimensions, int numData, float[][] labeledData){
        data = new float[numData][inputLayerDimensions];
        weight1 = new float[inputLayerDimensions][hiddenLayerDimensions];
        weight2 = new float[hiddenLayerDimensions][outputLayerDimensions];
        this.inputLayerDimensions = inputLayerDimensions;
        this.hiddenLayerDimensions = hiddenLayerDimensions;
        this.outputLayerDimensions = outputLayerDimensions;
        this.numdata = numData;
        this.labeledData = labeledData;
    }

    void initializeWeights(){
        /*
        Initialize Weight1
         */
        for(int i = 0; i < inputLayerDimensions; i++){
            for (int j = 0; j < hiddenLayerDimensions;j++){
                weight1[i][j] = r.nextFloat();
            }
        }
        /*
        Initialize Weight2
         */
        for(int i = 0; i < hiddenLayerDimensions; i++){
            for (int j = 0; j < outputLayerDimensions; j++){
                weight2[i][j] = r.nextFloat();
            }
        }
    }
    /*
    Update Weights for the Neural Network
     */
    void updateWeights(Gene[] gene1, Gene[] gene2){

    }
    /*
    Applied forward propagation for the input to get output
     */
    void forwardPropgate(){
        float[][] z2 = applyActivationFuction(matrixMultiply(data, this.numdata, this.inputLayerDimensions, weight1, this.hiddenLayerDimensions), this.numdata, this.hiddenLayerDimensions);
        yHat = applyActivationFuction(matrixMultiply(z2,this.inputLayerDimensions,this.hiddenLayerDimensions,weight1,this.outputLayerDimensions ),this.inputLayerDimensions,this.outputLayerDimensions );

    }

    /*
    Matrix Multiplication for Forward Propagation
     */
    float[][] matrixMultiply(float[][] M1,int m1Row, int m1Col, float[][] M2, int m2Col) {
        float[][] M3 = new float[2][2];
        for (int i = 0; i < m1Row; i++) { //M1 Rows
            for (int j = 0; j < m2Col; j++) { // M2 Columns
                for(int k = 0; k < m1Col; k++) { // M3 Columns
                    M3[i][j] += M1[i][k] * M2[k][j];
                }
            }
        }
        return M3;
    }

    /*
    Apply activation function to each elements of a matrix
     */
    float[][] applyActivationFuction(float[][] M, int x, int y){
        for(int i = 0; i < x; i++) {
            for (int j = 0; j < y; j++){
                M[i][j] = activationFunction(M[i][j]);
            }
        }
        return M;
    }
    /*
    Print Error (y - yHate) a.k.a (True Value - Predicted Value)
     */
    float[][] retrieveError(){
        float[][] error = new float[numdata][outputLayerDimensions];
        for(int i = 0; i < numdata; i++){
            for(int j = 0; j < outputLayerDimensions; j++){
                error[i][j] = labeledData[i][j] - yHat[i][j];
            }
        }
        return error;
    }
    /*
    Given a float value applied with the logistic function, return that new value
     */
    float activationFunction(float value){
        return (float)(1/(1 + Math.exp(-value)));
    }

    /*
    Print Matrix
     */
    void printMatrix(float [] [] M, int x, int y){
        for (int i = 0; i < x; i++) {
            for (int j = 0; j < y; j++) {
                System.out.print(M[i][j]);
            }
            System.out.println();
        }
    }
}

@@ -1573,24 +1573,148 @@
      %7D%0A    %7D
+%0A%0A    float%5B%5D%5B%5D%5B%5D retrieveWeights()%7B%0A        float%5B%5D%5B%5D%5B%5D weightArray = %7Bweight1, weight2%7D;%0A        return weightArray;%0A    %7D
 %0A    /*%0A    
@@ -1782,26 +1782,24 @@
 Weights(Gene
-%5B%5D
  gene1, Gene
@@ -1798,18 +1798,16 @@
 e1, Gene
-%5B%5D
  gene2)%7B
@@ -1807,23 +1807,109 @@
 gene2)%7B%0A
+        this.weight1 = gene1.returnGene();%0A        this.weight2 = gene2.returnGene();
 %0A    %7D%0A
+%0A
     /*%0A 
@@ -2010,26 +2010,16 @@
 %0A       
- float%5B%5D%5B%5D
  z2 = ap
@@ -2384,17 +2384,16 @@
 ions );%0A
-%0A
     %7D%0A%0A 
@@ -4066,10 +4066,11 @@
 %7D%0A    %7D%0A
+%0A
 %7D%0A

Update Neural Network