import sys
sys.version

import tensorflow as tf
tf.__version__

import matplotlib.pyplot as plt

%matplotlib inline
x_data = [1, 2, 3]
y_data = [1, 2 ,3]

plt.plot(x_data,y_data)
plt.show()

"""
Explanation: Linear Regression
(https://ko.wikipedia.org/wiki/%EC%84%A0%ED%98%95_%ED%9A%8C%EA%B7%80)
$$
H(x) = W(x) + b
$$
$$
cost(W,b) = \frac{1}{m} \sum_{i=0}^{m} ( h( x^i ) - y^i )^2
$$
End of explanation
"""


W = tf.Variable(tf.random_normal([1]), name='weight')
b = tf.Variable(tf.random_normal([1]), name='bias')
h = W * x_data + b

print(tf.random_normal([1]))


"""
Explanation: $$
H(x) = W(x) + b
$$
End of explanation
"""


print(h)
cost = tf.reduce_mean(tf.square(h - y_data))
#t = [1., 2., 3., 4.]
#tf.reduce_mean(t) ==> 2.5

optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01)
train = optimizer.minimize(cost)

init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)

for step in range(2000):
    sess.run(train)
    if step % 20 == 0:
        print(step,sess.run(cost),sess.run(W), sess.run(b))

"""
Explanation: $$
cost(W,b) = \frac{1}{m} \sum_{i=0}^{m} ( h( x^i ) - y^i )^2
$$
End of explanation
"""


x_data = [1., 2., 3.]
y_data = [2., 4., 6.]

W = tf.Variable(tf.random_normal([1]), name='weight')
b = tf.Variable(tf.random_normal([1]), name='bias')

X = tf.placeholder(tf.float32,shape=[None])
Y = tf.placeholder(tf.float32,shape=[None])

h = W * X + b
cost = tf.reduce_mean(tf.square(h - Y))
a = tf.Variable(0.1)
init = tf.global_variables_initializer()
opt = tf.train.GradientDescentOptimizer(a)
train = opt.minimize(cost)

sess = tf.Session()
sess.run(init)

for step in range(2000):
    sess.run(train,feed_dict={X:x_data, Y:y_data})
    if step % 20 == 0:
        print(step,sess.run(cost,feed_dict={X:x_data, Y:y_data}),sess.run(W), sess.run(b))

"""
Explanation: With placeholder
End of explanation
"""


print( sess.run(h, feed_dict={X:[5]}) )

print( sess.run(h, feed_dict={X:[2.3]}) )

"""
Explanation: Predict value with feed
End of explanation
"""


X = [1., 2., 3.]
Y = [1., 2., 3.]
m = n_samples = len(X)

W = tf.placeholder(tf.float32)
h = tf.multiply(X,W)

cost = tf.reduce_sum(tf.pow(h - Y, 2))/(m)
init = tf.global_variables_initializer()

W_val = []
cost_val = []

sess = tf.Session()
sess.run(init)
for i in range(-30, 50):
    curr_cost, curr_w = sess.run([cost,W], feed_dict={W: i*0.1})
    W_val.append(i*0.1)
    cost_val.append(curr_cost)
    
plt.plot(W_val, cost_val)
plt.ylabel('Cost')
plt.xlabel('W')

plt.show()

"""
Explanation: Cost minizied(desent algorithm)
End of explanation
"""


x_data = [1., 2., 3.]
y_data = [1., 2., 3.]

W = tf.Variable(5.0)
X = tf.placeholder(tf.float32)
Y = tf.placeholder(tf.float32)

h = W * X

"""
Explanation: minimized(Gradient descent)
End of explanation
"""


cost = tf.reduce_mean(tf.square(h - Y))
descent = W - tf.multiply(0.1, tf.reduce_mean(tf.multiply((tf.multiply(W,X) - Y), X)))
update = W.assign(descent)

init = tf.global_variables_initializer()

sess = tf.Session()
sess.run(init)

for step in range(100):
    sess.run(update, feed_dict={X:x_data, Y:y_data})
    print(step,sess.run(cost, feed_dict={X:x_data, Y:y_data}), sess.run(W))


#compute_gradient and apply_gradient
"""
gradient = tf.reduce_mean((W*X-Y)*X)*2

cost = tf.reduce_mean(tf.square(h-Y))

optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01)

gvs = optimizer.compute_gradients(cost)
apply_gradients = optimizer.apply_gradients(gvs)
"""

"""
Explanation: Derivative
$$
cost(W) = \frac{1}{2m} \sum_{i=1}^{m} (W( x^i) - y^i)^2
$$
$$
Gradient descent algorithm
 W := W - a \frac{ \partial}{\partial{m}} cost(W)
$$
$$
W:= W - a \frac{1}{m} \sum_{i=1}^{m} (W( x^i) - y^i)x^i
$$
End of explanation
"""


x1_data = [73,93,89,96,73]
x2_data = [80,88,91,98,66]
x3_data = [75,93,90,100,70]
y_data = [152,185,180,196,142]

x1 = tf.placeholder(tf.float32)
x2 = tf.placeholder(tf.float32)
x3 = tf.placeholder(tf.float32)
y = tf.placeholder(tf.float32)

W1 = tf.Variable(tf.random_uniform([1], -1.0, 1.0), name='weight1')
W2 = tf.Variable(tf.random_uniform([1], -1.0, 1.0), name='weight2')
W3 = tf.Variable(tf.random_uniform([1], -1.0, 1.0), name='weight3')
b = tf.Variable(tf.random_uniform([1], -1.0, 1.0),name='bias')

h = W1 * x1 + W2 * x2 + W3*x3 + b

cost = tf.reduce_mean(tf.square(h - y))
opt = tf.train.GradientDescentOptimizer(learning_rate=1e-5)
train = opt.minimize(cost)

init = tf.global_variables_initializer()

sess = tf.Session()
sess.run(init)

for step in range(2000):
    cost_val, h_val, _ = sess.run([cost, h, train] , feed_dict={x1:x1_data, x2: x2_data, x3:x3_data, y:y_data})
    if step % 20 == 0:
         print(step,cost_val, h_val)

x_data = [ [73,80,75], [93,88,93], [89,91,90],[96,98,100], [73,66,70]]
y_data = [[152],[185],[180],[196],[142]]


X = tf.placeholder(tf.float32, shape=[None,3])
Y = tf.placeholder(tf.float32, shape=[None,1])

W = tf.Variable(tf.random_normal([3,1]), name='weight')
b = tf.Variable(tf.random_normal([1]), name='bias')

h = tf.matmul(X,W)+b

cost = tf.reduce_mean(tf.square(h - y_data))
a = tf.Variable(0.1)
opt = tf.train.GradientDescentOptimizer(learning_rate=1e-5)
train = opt.minimize(cost)

init = tf.global_variables_initializer()

sess = tf.Session()
sess.run(init)

for step in range(3000):
    cost_val, h_val, _ =  sess.run([cost,h,train], feed_dict={X:x_data, Y: y_data}) 
    if step % 20 == 0:
        print(step, cost_val, h_val)

"""
Explanation: Multi variable Linear regression
$$
H(x_1,x_2) = w_1x_1 + w_2x_2 + w_3x_3
$$
End of explanation
"""


