# your code gimport random
import sys
import numpy
import math

eta=0.0001 #learning rate
n=200 #number of training epoch
inp=30 #input layer size
m=60 #hidden layer size
y=0 #output signal
t=0 #target signal
e=0 #error
d_y=0 #local gradient for the last neuron
err=0 #calculated network error for output neuron
err_av=0 #average network error
path='dataTrain.txt' #training sample
path2='dataLaunch.txt' #launching a forecast
day = 365 #number of days of forecasting

x=[] #training sample
w=[[0 for j in range(inp)] for i in range(m)] #matrix of weights (synapses)
v=[0 for j in range(m)] #vector of weights of the output layer
y_s=[0 for j in range(m)] #hidden layer of neurons
d_y_s=[0 for j in range(m)] #local gradients for hidden layer neurons
averError=[] #array of NS errors (by epoch)
window=[] #sliding window
predict=[]
fact=[] #target values
training=[] #values obtained by the INS during training
y_s2=[0 for j in range(m)]
a=-1
b=1

def sigmoid(arg):
  res = 1.0/(1+numpy.exp(-(arg-1)))
  return res

def tanh(arg):
    return (numpy.exp(arg) - numpy.exp(-arg)) / (numpy.exp(arg) + numpy.exp(-arg))

def tanh_der(arg):
    return 1 - numpy.power(tanh(arg), 2)

def ReLu(arg):
    return max(0.00001*arg, arg)

def ReLu_der(arg):
    return 1 if arg > 0 else 0.00001

def init_x(path):
    t=0 #auxiliary variable

    for i in range(0, m):
      for j in range(0, inp):
          w[i][j]=random.random()*(1+1)-1

    for j in range(0, m):
        v[j]=random.random()*(1+1)-1
     
    try:
       f=open(path,'r')
    except FileNotFoundError:
       print("File not found")
       sys.exit()
    
    for k in f:
        x.append([])
        x[t].extend([float(x) for x in k.split()])
        t=t+1
    
    f.close()
    
    for i in range(0, len(x)):
     fact.append(x[i][30])
     xmax=max(x[i])
     xmin=min(x[i])
     for j in range(0, len(x[i])):
      x[i][j]=a+(x[i][j]-xmin)/(xmax-xmin)*(b-a)
     x[i].insert(0, xmax) 
     x[i].insert(0, xmin)
    random.shuffle(x)

def train(): 
  for k in range(1, n+1): #cycle by epoch
    err_av=0
    for f in range(0, len(x)): #cycle by samples
      for i in range(0, m):
        sum=0
        for j in range(0, inp):
           sum=sum+w[i][j]*x[f][j+2] #weighted sum of inputs
        y_s[i]=sum
      for p in range(0, m):
        y_s[p]=sigmoid(y_s[p]) #The activation signal is converted using the activation function
      #calculating output neuron activity
      sum2=0
      for z in range(0, m):
        sum2=sum2+v[z]*y_s[z]
      y=sigmoid(sum2) #end of propagation. y - output
      
      t=x[f][32] #target value
      e=y-t
      err=pow(e, 2)/2
      err_av=err_av+err
      
      if k == n:
        training.append(((y-a)/(b-a))*(x[f][1]-x[f][0])+x[f][0])
      
      d_y=e*y*(1-y)
      #modification of the output layer weights
      for q in range(0, m):
        v[q]=v[q]-eta*d_y*y_s[q]
      for r in range(0, m):
        d_y_s[r]=d_y*v[r] 
      
      for i1 in range(0, m):
        for j1 in range(0, inp):
          w[i1][j1]=w[i1][j1]-eta*d_y_s[i1]*y_s[i1]*(1-y_s[i1])*x[f][j1+2]
    averError.append(math.sqrt(err_av/n/(f+1)))

def prediction(window, predict, day):
  predict.extend(window)
  
  for z in range(1, day+1):
   xmax=max(window)
   xmin=min(window)
   for t in range(0, len(window)):
     window[t]=a+((window[t]-xmin)/(xmax-xmin))*(b-a)

   for i in range(0, m):
      sum=0
      for j in range(0, inp):
        sum=sum+w[i][j]*window[j]
      y_s2[i]=sum
  #calculating the activity of hidden layer neurons
   for i in range(0, m):
    y_s2[i]=sigmoid(y_s2[i])
  #calculating output neuron activity
   sum=0
   for j in range(0, m):
     sum=sum+v[j]*y_s2[j]
   t=sigmoid(sum)
   
   window.append(t)
   window.pop(0)
   predict.append(round(((t-a)/(b-a))*(xmax-xmin)+xmin, 2)) #denormalization of the output
   for i in range(0, len(window)):
       window[i]=((window[i]-a)/(b-a))*(xmax-xmin)+xmin #denormalization of the entire sliding window   
        
try:
    f=open(path2,'r')
except FileNotFoundError:
    print("File not found")
    sys.exit()

entrance=f.readline()
window.extend([float(x) for x in entrance.split()])
data=f.readline()
data=data.strip()
f.close()

init_x(path)
train()
prediction(window, predict, day)