from __future__ import division
import numpy as np
import matplotlib.pyplot as plt
import gzip
import random as rand
from timeit import default_timer as timer
import math

sin_wave = np.array([math.sin(x) for x in np.arange(200)])

X = []
Y = []

sequence_length = 50
number_records = len(sin_wave)-sequence_length
validation_length = 50

for i in range(number_records-validation_length): #Set aside 50 records for validation
    X.append(sin_wave[i:i+sequence_length]) #sequence lengths from 0 to 50, 1 to 51...
    Y.append(sin_wave[i+sequence_length]) #next value given sequence

X = np.array(X)
X = np.expand_dims(X, axis = 2)

Y = np.array(Y)
Y = np.expand_dims(Y, axis = 1)

X_Val = []
Y_Val = []

for i in range(number_records-validation_length, number_records):
    X_Val.append(sin_wave[i:i+sequence_length])
    Y_Val.append(sin_wave[i+sequence_length])

X_Val = np.array(X_Val)
X_Val = np.expand_dims(X_Val, axis = 2)

Y_Val = np.array(Y_Val)
Y_Val = np.expand_dims(Y_Val, axis = 1)

learning_rate = 0.0001
number_epochs = 25
T = 50
sizes = [T, 100, 1]
hidden_layer = 100
output_layer = 1

class RecurrentNet(object):
    def __init__(self, sizes):
        self.num_layers = len(sizes)
        self.sizes = sizes
        self.weights = np.asarray([np.random.randn(y,x) for x, y in zip(sizes[:-1],sizes[1:])])
        self.recurrent_weights = np.asarray([np.random.randn(y,x) for x, y in zip(sizes[1:-1],sizes[1:-1])])
        
def sigmoid(z):
    return 1.0/(1.0+np.exp(-z))

def sigmoid_prime(z):
    return sigmoid(z)*(1-sigmoid(z))

MyNetwork = RecurrentNet(sizes)



for i in range(Y.shape[0]):
    x, y = X[i], Y[i]
    previous_s = np.zeros((sizes[1], 1)) #value of previous activation of hidden layer; initialized as all zeroes. np.zeros of 100, 1
    for t in range(T):
        new_input = np.zeros(x.shape) # do a forward pass for every timestep in the sequence. 50, 1
        new_input[t] = x[t] #define a single input for that timestep
        print(x.shape)
        print(x[t])
        mulu = np.dot(MyNetwork.weights[0], new_input)          #100, 50 and 50, 1
        mulw = np.dot(MyNetwork.recurrent_weights, previous_s)  #100, 100 and 100, 1
        mulv = np.dot(MyNetwork.weights[1], sigmoid(mulw + mulu))#50, 100 and 100, 1 
        #so mulv is 50, 1
        break
    break
        # U = weight matrix for weights between input and hidden layers
        # V = weight matrix from weights between hidden and output layers
        # W = weight matrix for shared weights in the RNN layer
