# -*- coding:utf-8 -*-
import tensorflow as tf


class CNN:

    def __init__(self, save_or_load_path=None, trainable=True, learning_rate = 0.00002,timestep=9,road=189,predstep=1):
        self.trainable = trainable
        self.learning_rate = learning_rate
        self.road = road
        self.input_size = timestep * road
        self.output_size = predstep * road
        self.bottom = tf.placeholder(tf.float32, shape=[None, self.input_size], name='input')  # 25*2*6
        self.target = tf.placeholder(tf.float32, shape=[None, self.output_size], name='target')
        self.timestep = timestep

    def weight_variable(self,shape):
        initial = tf.truncated_normal(shape, stddev=0.1)
        return tf.Variable(initial)

    def bias_variable(self,shape):
        initial = tf.truncated_normal(shape, stddev=0.1)
        return initial

    def conv2d(self,x, W):
        return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')

    def conv1d(self,x, W):
        return tf.nn.conv1d(x, W, stride=2, padding='SAME')

    def max_pool_2x2(self,x):
        return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')

    def build_CNN(self, ):

        # conv first
        bottom = tf.reshape(self.bottom, [-1, self.road, self.timestep, 1])
        W_conv1 = self.weight_variable([3, 3, 1, 64])
        b_conv1 = self.bias_variable([64])
        h_conv1 = tf.nn.elu(self.conv2d(bottom, W_conv1) + b_conv1)
        h_pool1 = self.max_pool_2x2(h_conv1)

        h_flat3 = tf.reshape(h_pool1, [-1, 95 * 5 * 64])
        W_fc2 = self.weight_variable([95 * 5  * 64, 1200])
        b_fc2 = self.bias_variable([1200])
        h = tf.nn.elu(tf.matmul(h_flat3, W_fc2) + b_fc2)
        # h_flat3 = tf.reshape(h_pool3, [-1, 400])
        W_fc2 = self.weight_variable([1200, self.output_size])
        b_fc2 = self.bias_variable([self.output_size])
        self.predict = tf.nn.elu(tf.matmul(h, W_fc2) + b_fc2)


        global_step = tf.Variable(0, trainable=False)
        self.learning_rate = 0.0002 #tf.train.exponential_decay(0.001,  global_step,  500, 0.9,staircase=True)
        self.loss = tf.reduce_mean(tf.squared_difference(self.target, self.predict))
        self.accuracy = 1. - tf.reduce_mean(abs(self.target-self.predict)/self.target)
        self.trainop = tf.train.AdamOptimizer(self.learning_rate).minimize(self.loss, global_step=global_step)
        # self.trainop = tf.train.RMSPropOptimizer(self.learning_rate, 0.99, 0.0, 1e-6).minimize(self.loss)
        return self.predict



class CNN15:
    def __init__(self, save_or_load_path=None, trainable=True, learning_rate = 0.00002,timestep=9,road=189,predstep=3):
        self.trainable = trainable
        self.learning_rate = learning_rate
        self.road = road
        self.input_size = timestep * road
        self.output_size = predstep * road
        self.bottom = tf.placeholder(tf.float32, shape=[None, self.input_size], name='input')  # 25*2*6
        self.target = tf.placeholder(tf.float32, shape=[None, self.output_size], name='target')
        self.timestep = timestep

    def weight_variable(self,shape):
        initial = tf.truncated_normal(shape, stddev=0.1)
        return tf.Variable(initial)

    def bias_variable(self,shape):
        initial = tf.truncated_normal(shape, stddev=0.1)
        return initial

    def conv2d(self,x, W):
        return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')

    def conv1d(self,x, W):
        return tf.nn.conv1d(x, W, stride=2, padding='SAME')

    def max_pool_2x2(self,x):
        return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')

    def build_CNN(self, ):

        # conv first
        bottom = tf.reshape(self.bottom, [-1, self.road, self.timestep, 1])
        W_conv1 = self.weight_variable([3, 3, 1, 64])
        b_conv1 = self.bias_variable([64])
        h_conv1 = tf.nn.elu(self.conv2d(bottom, W_conv1) + b_conv1)
        h_pool1 = self.max_pool_2x2(h_conv1)

        h_flat3 = tf.reshape(h_pool1, [-1, 95 * 5 * 64])
        W_fc2 = self.weight_variable([95 * 5  * 64, 1200])
        b_fc2 = self.bias_variable([1200])
        h = tf.nn.elu(tf.matmul(h_flat3, W_fc2) + b_fc2)
        # h_flat3 = tf.reshape(h_pool3, [-1, 400])
        W_fc2 = self.weight_variable([1200, self.output_size])
        b_fc2 = self.bias_variable([self.output_size])
        self.predict = tf.nn.elu(tf.matmul(h, W_fc2) + b_fc2)


        global_step = tf.Variable(0, trainable=False)
        self.learning_rate = 0.0002 #tf.train.exponential_decay(0.001,  global_step,  500, 0.9,staircase=True)
        self.loss = tf.reduce_mean(tf.squared_difference(self.target, self.predict))
        self.accuracy = 1. - tf.reduce_mean(abs(self.target-self.predict)/self.target)
        self.trainop = tf.train.AdamOptimizer(self.learning_rate).minimize(self.loss, global_step=global_step)
        # self.trainop = tf.train.RMSPropOptimizer(self.learning_rate, 0.99, 0.0, 1e-6).minimize(self.loss)
        return self.predict




class CNN30:
    def __init__(self, save_or_load_path=None, trainable=True, learning_rate=0.00002,timestep=9,road=189,predstep=6):
        self.trainable = trainable
        self.learning_rate = learning_rate
        self.road = road
        self.input_size = timestep * road
        self.output_size = predstep * road
        self.bottom = tf.placeholder(tf.float32, shape=[None, self.input_size], name='input')  # 25*2*6
        self.target = tf.placeholder(tf.float32, shape=[None, self.output_size], name='target')
        self.timestep = timestep

    def weight_variable(self,shape):
        initial = tf.truncated_normal(shape, stddev=0.1)
        return tf.Variable(initial)

    def bias_variable(self,shape):
        initial = tf.truncated_normal(shape, stddev=0.1)
        return initial

    def conv2d(self,x, W):
        return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')

    def conv1d(self,x, W):
        return tf.nn.conv1d(x, W, stride=2, padding='SAME')

    def max_pool_2x2(self,x):
        return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')


    def build_CNN(self, ):
        # conv first
        bottom = tf.reshape(self.bottom, [-1, self.road, self.timestep, 1])
        W_conv1 = self.weight_variable([3, 3, 1, 64])
        b_conv1 = self.bias_variable([64])
        h_conv1 = tf.nn.elu(self.conv2d(bottom, W_conv1) + b_conv1)
        h_pool1 = self.max_pool_2x2(h_conv1)

        h_flat3 = tf.reshape(h_pool1, [-1, 95 * 5 * 64])
        W_fc2 = self.weight_variable([95 * 5 * 64, 1200])
        b_fc2 = self.bias_variable([1200])
        h = tf.nn.elu(tf.matmul(h_flat3, W_fc2) + b_fc2)
        # h_flat3 = tf.reshape(h_pool3, [-1, 400])
        W_fc2 = self.weight_variable([1200, self.output_size])
        b_fc2 = self.bias_variable([self.output_size])
        self.predict = tf.nn.elu(tf.matmul(h, W_fc2) + b_fc2)

        global_step = tf.Variable(0, trainable=False)
        self.learning_rate = 0.0002  # tf.train.exponential_decay(0.001,  global_step,  500, 0.9,staircase=True)
        self.loss = tf.reduce_mean(tf.squared_difference(self.target, self.predict))
        self.accuracy = 1. - tf.reduce_mean(abs(self.target - self.predict) / self.target)
        self.trainop = tf.train.AdamOptimizer(self.learning_rate).minimize(self.loss, global_step=global_step)
        # self.trainop = tf.train.RMSPropOptimizer(self.learning_rate, 0.99, 0.0, 1e-6).minimize(self.loss)
        return self.predict
[(13, 'tensorflow.placeholder', 'tf.placeholder', (['tf.float32'], {'shape': '[None, self.input_size]', 'name': '"""input"""'}), True, 'import tensorflow as tf\n'), (14, 'tensorflow.placeholder', 'tf.placeholder', (['tf.float32'], {'shape': '[None, self.output_size]', 'name': '"""target"""'}), True, 'import tensorflow as tf\n'), (18, 'tensorflow.truncated_normal', 'tf.truncated_normal', (['shape'], {'stddev': '(0.1)'}), True, 'import tensorflow as tf\n'), (19, 'tensorflow.Variable', 'tf.Variable', (['initial'], {}), True, 'import tensorflow as tf\n'), (22, 'tensorflow.truncated_normal', 'tf.truncated_normal', (['shape'], {'stddev': '(0.1)'}), True, 'import tensorflow as tf\n'), (26, 'tensorflow.nn.conv2d', 'tf.nn.conv2d', (['x', 'W'], {'strides': '[1, 1, 1, 1]', 'padding': '"""SAME"""'}), True, 'import tensorflow as tf\n'), (29, 'tensorflow.nn.conv1d', 'tf.nn.conv1d', (['x', 'W'], {'stride': '(2)', 'padding': '"""SAME"""'}), True, 'import tensorflow as tf\n'), (32, 'tensorflow.nn.max_pool', 'tf.nn.max_pool', (['x'], {'ksize': '[1, 2, 2, 1]', 'strides': '[1, 2, 2, 1]', 'padding': '"""SAME"""'}), True, 'import tensorflow as tf\n'), (37, 'tensorflow.reshape', 'tf.reshape', (['self.bottom', '[-1, self.road, self.timestep, 1]'], {}), True, 'import tensorflow as tf\n'), (43, 'tensorflow.reshape', 'tf.reshape', (['h_pool1', '[-1, 95 * 5 * 64]'], {}), True, 'import tensorflow as tf\n'), (53, 'tensorflow.Variable', 'tf.Variable', (['(0)'], {'trainable': '(False)'}), True, 'import tensorflow as tf\n'), (70, 'tensorflow.placeholder', 'tf.placeholder', (['tf.float32'], {'shape': '[None, self.input_size]', 'name': '"""input"""'}), True, 'import tensorflow as tf\n'), (71, 'tensorflow.placeholder', 'tf.placeholder', (['tf.float32'], {'shape': '[None, self.output_size]', 'name': '"""target"""'}), True, 'import tensorflow as tf\n'), (75, 'tensorflow.truncated_normal', 'tf.truncated_normal', (['shape'], {'stddev': '(0.1)'}), True, 'import tensorflow as tf\n'), (76, 'tensorflow.Variable', 'tf.Variable', (['initial'], {}), True, 'import tensorflow as tf\n'), (79, 'tensorflow.truncated_normal', 'tf.truncated_normal', (['shape'], {'stddev': '(0.1)'}), True, 'import tensorflow as tf\n'), (83, 'tensorflow.nn.conv2d', 'tf.nn.conv2d', (['x', 'W'], {'strides': '[1, 1, 1, 1]', 'padding': '"""SAME"""'}), True, 'import tensorflow as tf\n'), (86, 'tensorflow.nn.conv1d', 'tf.nn.conv1d', (['x', 'W'], {'stride': '(2)', 'padding': '"""SAME"""'}), True, 'import tensorflow as tf\n'), (89, 'tensorflow.nn.max_pool', 'tf.nn.max_pool', (['x'], {'ksize': '[1, 2, 2, 1]', 'strides': '[1, 2, 2, 1]', 'padding': '"""SAME"""'}), True, 'import tensorflow as tf\n'), (94, 'tensorflow.reshape', 'tf.reshape', (['self.bottom', '[-1, self.road, self.timestep, 1]'], {}), True, 'import tensorflow as tf\n'), (100, 'tensorflow.reshape', 'tf.reshape', (['h_pool1', '[-1, 95 * 5 * 64]'], {}), True, 'import tensorflow as tf\n'), (110, 'tensorflow.Variable', 'tf.Variable', (['(0)'], {'trainable': '(False)'}), True, 'import tensorflow as tf\n'), (128, 'tensorflow.placeholder', 'tf.placeholder', (['tf.float32'], {'shape': '[None, self.input_size]', 'name': '"""input"""'}), True, 'import tensorflow as tf\n'), (129, 'tensorflow.placeholder', 'tf.placeholder', (['tf.float32'], {'shape': '[None, self.output_size]', 'name': '"""target"""'}), True, 'import tensorflow as tf\n'), (133, 'tensorflow.truncated_normal', 'tf.truncated_normal', (['shape'], {'stddev': '(0.1)'}), True, 'import tensorflow as tf\n'), (134, 'tensorflow.Variable', 'tf.Variable', (['initial'], {}), True, 'import tensorflow as tf\n'), (137, 'tensorflow.truncated_normal', 'tf.truncated_normal', (['shape'], {'stddev': '(0.1)'}), True, 'import tensorflow as tf\n'), (141, 'tensorflow.nn.conv2d', 'tf.nn.conv2d', (['x', 'W'], {'strides': '[1, 1, 1, 1]', 'padding': '"""SAME"""'}), True, 'import tensorflow as tf\n'), (144, 'tensorflow.nn.conv1d', 'tf.nn.conv1d', (['x', 'W'], {'stride': '(2)', 'padding': '"""SAME"""'}), True, 'import tensorflow as tf\n'), (147, 'tensorflow.nn.max_pool', 'tf.nn.max_pool', (['x'], {'ksize': '[1, 2, 2, 1]', 'strides': '[1, 2, 2, 1]', 'padding': '"""SAME"""'}), True, 'import tensorflow as tf\n'), (152, 'tensorflow.reshape', 'tf.reshape', (['self.bottom', '[-1, self.road, self.timestep, 1]'], {}), True, 'import tensorflow as tf\n'), (158, 'tensorflow.reshape', 'tf.reshape', (['h_pool1', '[-1, 95 * 5 * 64]'], {}), True, 'import tensorflow as tf\n'), (167, 'tensorflow.Variable', 'tf.Variable', (['(0)'], {'trainable': '(False)'}), True, 'import tensorflow as tf\n'), (55, 'tensorflow.squared_difference', 'tf.squared_difference', (['self.target', 'self.predict'], {}), True, 'import tensorflow as tf\n'), (112, 'tensorflow.squared_difference', 'tf.squared_difference', (['self.target', 'self.predict'], {}), True, 'import tensorflow as tf\n'), (169, 'tensorflow.squared_difference', 'tf.squared_difference', (['self.target', 'self.predict'], {}), True, 'import tensorflow as tf\n'), (46, 'tensorflow.matmul', 'tf.matmul', (['h_flat3', 'W_fc2'], {}), True, 'import tensorflow as tf\n'), (50, 'tensorflow.matmul', 'tf.matmul', (['h', 'W_fc2'], {}), True, 'import tensorflow as tf\n'), (57, 'tensorflow.train.AdamOptimizer', 'tf.train.AdamOptimizer', (['self.learning_rate'], {}), True, 'import tensorflow as tf\n'), (103, 'tensorflow.matmul', 'tf.matmul', (['h_flat3', 'W_fc2'], {}), True, 'import tensorflow as tf\n'), (107, 'tensorflow.matmul', 'tf.matmul', (['h', 'W_fc2'], {}), True, 'import tensorflow as tf\n'), (114, 'tensorflow.train.AdamOptimizer', 'tf.train.AdamOptimizer', (['self.learning_rate'], {}), True, 'import tensorflow as tf\n'), (161, 'tensorflow.matmul', 'tf.matmul', (['h_flat3', 'W_fc2'], {}), True, 'import tensorflow as tf\n'), (165, 'tensorflow.matmul', 'tf.matmul', (['h', 'W_fc2'], {}), True, 'import tensorflow as tf\n'), (171, 'tensorflow.train.AdamOptimizer', 'tf.train.AdamOptimizer', (['self.learning_rate'], {}), True, 'import tensorflow as tf\n')]