using System;
using System.Configuration;
using System.Data;
using System.Data.Sql;
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Data.OleDb;
using System.Data.SqlClient;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Globalization;
using System.Threading;

namespace NNmarket
{
    class BP
    {
        public class neuron
        {
            public double[] Waga;
            public double[] BladWaga;
            public double[] StaraWaga;
            public double Bias;
            public double Blad;
            public double StaryBias;
            public double Wyjscie;
            public double Wejscie;
            public double[] deltaWaga;
            public double deltaBias;
            public neuron(int w)
            {
                Waga = new double[w];
                BladWaga = new double[w];
                Bias = 0;
                Blad = 0;
                Wyjscie = 0;
                Wejscie = 0;
                deltaWaga = new double[w];
                deltaBias = 0;
                StaraWaga = new double[w];
                StaryBias = 0;
            }

        }

        public double[][] DaneWejsciowe;
        public double[] DaneWyjsciowe;
        public neuron[][] Neuron;
        public int Ilewarstw;
        public void Tworzsiec(int wejscie, int ukryta, int wyjscie)
        {
            Neuron = new neuron[3][];
            Neuron[0] = new neuron[wejscie];
            Neuron[1] = new neuron[ukryta];
            Neuron[2] = new neuron[wyjscie];

            for (int i = 0; i < wejscie; i++)
                Neuron[0][i] = new neuron(1);

            for (int i = 0; i < ukryta; i++)
                Neuron[1][i] = new neuron(wejscie);

            for (int i = 0; i < wyjscie; i++)
                Neuron[2][i] = new neuron(ukryta);
            Ilewarstw = 3;
            LosujWagi();
        }
        public void Tworzsiec(int wejscie, int ukryta, int ukryta2, int wyjscie)
        {
            Neuron = new neuron[4][];
            Neuron[0] = new neuron[wejscie];
            Neuron[1] = new neuron[ukryta];
            Neuron[2] = new neuron[ukryta2];
            Neuron[3] = new neuron[wyjscie];
            for (int i = 0; i < wejscie; i++)
                Neuron[0][i] = new neuron(1);

            for (int i = 0; i < ukryta; i++)
                Neuron[1][i] = new neuron(wejscie);


            for (int i = 0; i < ukryta2; i++)
                Neuron[2][i] = new neuron(ukryta);

            for (int i = 0; i < wyjscie; i++)
                Neuron[3][i] = new neuron(ukryta2);
            Ilewarstw = 4;
            LosujWagi();
        }
        private void LosujWagi()
        {
            for (int L = 1; L < Ilewarstw; L++)
            {
                for (int N = 0; N < Neuron[L].Length; N++)
                {
                    System.Guid desiredGuid = System.Guid.NewGuid();
                    byte[] bArr = desiredGuid.ToByteArray();
                    int autonum = BitConverter.ToInt32(bArr, 0);
                    Random R = new Random(autonum);
                    double wbiasu = 1 - 2 * R.NextDouble();
                    Neuron[L][N].Bias = wbiasu;

                    for (int w = 0; w < Neuron[L][N].Waga.Length; w++)
                    {
                        System.Guid desiredGuid2 = System.Guid.NewGuid();
                        byte[] bArr2 = desiredGuid2.ToByteArray();
                        int autonum2 = BitConverter.ToInt32(bArr2, 0);
                        Random R2 = new Random(autonum2);

                        double ww = 1 - 2 * R2.NextDouble();
                        Neuron[L][N].Waga[w] = ww;
                    }
                }
            }
        }
        public double Funkcja(double x)
        {
            return (1 / (1 + Math.Exp(-x)));
        }   
        public double Pochodna(double y)
        {
            return y * (1 - y);
          
        }
        public void DaneWejscioweUstaw(List<double[]> DaneWejscioweL)
        {

            DaneWejsciowe = DaneWejscioweL.ToArray();

        }
        public double PropagacjaOnline(int wektor)
        {
            for (int n = 0; n < Neuron[0].Length; n++)
            {
                Neuron[0][n].Wejscie = DaneWejsciowe[n][wektor];

            }
            for (int n = 0; n < Neuron[0].Length; n++)
            {
                Neuron[0][n].Wyjscie = Neuron[0][n].Wejscie;

            }

            for (int L = 1; L < Ilewarstw; L++)
            {

                for (int n = 0; n < Neuron[L].Length; n++)
                {
                    double sumator = 0;
                    for (int w = 0; w < Neuron[L][n].Waga.Length; w++)
                    {
                        sumator += Neuron[L - 1][w].Wyjscie * Neuron[L][n].Waga[w];
                    }
                    Neuron[L][n].Wejscie = sumator + Neuron[L][n].Bias;

                }
                for (int n = 0; n < Neuron[L].Length; n++)
                {


                    Neuron[L][n].Wyjscie = Funkcja(Neuron[L][n].Wejscie);

                }

            }


            double poprawna = DaneWyjsciowe[wektor];
            double otrzymana = Neuron[Ilewarstw - 1][0].Wyjscie;
            Neuron[Ilewarstw - 1][0].Blad = (poprawna - otrzymana);//*Pochodna( Neuron[Ilewarstw - 1][0].Wyjscie);
            return Neuron[Ilewarstw - 1][0].Blad;
        }
        public void WstecznaPropagacjaOnline()
        {

            for (int n = 0; n < Neuron[Ilewarstw - 1].Length; n++)//blad dla ostatniej warstwy 
            {
                for (int w = 0; w < Neuron[Ilewarstw - 1][n].Waga.Length; w++)
                {
                    Neuron[Ilewarstw - 1][n].BladWaga[w] = Neuron[Ilewarstw - 1][n].Waga[w] * Neuron[Ilewarstw - 1][n].Blad;
                }

            }

            int L = Ilewarstw - 1;

            do
            {
                for (int n = 0; n < Neuron[L].Length; n++)
                {
                    for (int w = 0; w < Neuron[L][n].Waga.Length; w++)
                    {
                        Neuron[L - 1][w].Blad += Neuron[L][n].BladWaga[w];
                    }

                }

                for (int w = 0; w < Neuron[L - 1].Length; w++)
                {
                    Neuron[L - 1][w].Blad *= Pochodna(Neuron[L - 1][w].Wyjscie);
                }
                L--;
            } while (L != 1);

        }
        public void ZerujBledy()
        {
            for (int l = 0; l < Ilewarstw; l++)
            {
                for (int n = 0; n < Neuron[l].Length; n++)
                {
                    Neuron[l][n].Blad = 0;
                    for (int w = 0; w < Neuron[l][n].Waga.Length; w++)
                    {
                        Neuron[l][n].BladWaga[w] = 0;
                    }
                }
            }

        }
        public void PoprawOnline(double WspUczenia, bool momentum)
        {


            for (int l = 1; l < Ilewarstw; l++)
            {
                for (int n = 0; n < Neuron[l].Length; n++)
                {


                    for (int w = 0; w < Neuron[l][n].Waga.Length; w++)
                    {
                        if (momentum)
                        {
                            Neuron[l][n].StaraWaga[w] = Neuron[l][n].Waga[w];
                            Neuron[l][n].Waga[w] += (Neuron[l][n].Blad * WspUczenia * Neuron[l - 1][w].Wyjscie) + 0.4 * Neuron[l][n].deltaWaga[w];
                            Neuron[l][n].deltaWaga[w] = Neuron[l][n].Blad * WspUczenia * Neuron[l - 1][w].Wyjscie;
                        }
                        else
                        {
                            Neuron[l][n].StaraWaga[w] = Neuron[l][n].Waga[w];
                            Neuron[l][n].Waga[w] += (Neuron[l][n].Blad * WspUczenia * Neuron[l - 1][w].Wyjscie);
                        }
                    }
                    Neuron[l][n].StaryBias = Neuron[l][n].Bias;
                    Neuron[l][n].Bias += Neuron[l][n].Blad * WspUczenia;
                }

            }
        }
        public void WczytajWagi(List<double[]> W1, List<double[]> W2, List<double[]> W3)
        {
            double[][] W1d = W1.ToArray();
            double[][] W2d = W2.ToArray();
            double[][] W3d = W3.ToArray();
            for (int N = 0; N < Neuron[1].Length; N++)
            {

                for (int w = 0; w < Neuron[1][N].Waga.Length; w++)
                {

                    Neuron[1][N].Waga[w] = W1d[N][w];
                }
                Neuron[1][N].Bias = W1d[Neuron[1].Length][N];
            }

            for (int N = 0; N < Neuron[2].Length; N++)
            {

                for (int w = 0; w < Neuron[2][N].Waga.Length; w++)
                {

                    Neuron[2][N].Waga[w] = W2d[N][w];
                }
                Neuron[2][N].Bias = W2d[Neuron[2].Length][N];
            }

            for (int N = 0; N < Neuron[3].Length; N++)
            {

                for (int w = 0; w < Neuron[3][N].Waga.Length; w++)
                {

                    Neuron[3][N].Waga[w] = W3d[N][w];
                }
                Neuron[3][N].Bias = W3d[Neuron[3].Length][N];
            }


        }
        public void DaneWyjscioweUstaw(double[] DaneWyjscioweL)
        {

            DaneWyjsciowe = DaneWyjscioweL;

        }
        public void PrzywrocWagi()
        {


            for (int l = 1; l < Ilewarstw; l++)
            {
                for (int n = 0; n < Neuron[l].Length; n++)
                {


                    for (int w = 0; w < Neuron[l][n].Waga.Length; w++)
                    {

                        Neuron[l][n].Waga[w] = Neuron[l][n].StaraWaga[w];




                        Neuron[l][n].Bias = Neuron[l][n].StaryBias;

                    }

                }
            }
        }
    
    
    
    }
}
