import tensorflow as tf
print(tf.__version__)

"""
Explanation: Demonstrates some common TensorFlow errors
This notebook demonstrates some common TensorFlow errors, how to find them, and how to fix them.
End of explanation
"""


def some_method(data):
  a = data[:,0:2]
  c = data[:,1]
  s = (a + c)
  return tf.sqrt(tf.matmul(s, tf.transpose(s)))

with tf.Session() as sess:
  fake_data = tf.constant([
      [5.0, 3.0, 7.1],
      [2.3, 4.1, 4.8],
      [2.8, 4.2, 5.6],
      [2.9, 8.3, 7.3]
    ])
  print(sess.run(some_method(fake_data)))

def some_method(data):
  a = data[:,0:2]
  print(a.get_shape())
  c = data[:,1]
  print(c.get_shape())
  s = (a + c)
  return tf.sqrt(tf.matmul(s, tf.transpose(s)))

with tf.Session() as sess:
  fake_data = tf.constant([
      [5.0, 3.0, 7.1],
      [2.3, 4.1, 4.8],
      [2.8, 4.2, 5.6],
      [2.9, 8.3, 7.3]
    ])
  print(sess.run(some_method(fake_data)))

def some_method(data):
  a = data[:,0:2]
  print(a.get_shape())
  c = data[:,1:3]
  print(c.get_shape())
  s = (a + c)
  return tf.sqrt(tf.matmul(s, tf.transpose(s)))

with tf.Session() as sess:
  fake_data = tf.constant([
      [5.0, 3.0, 7.1],
      [2.3, 4.1, 4.8],
      [2.8, 4.2, 5.6],
      [2.9, 8.3, 7.3]
    ])
  print(sess.run(some_method(fake_data)))

import tensorflow as tf

x = tf.constant([[3, 2],
                 [4, 5],
                 [6, 7]])
print("x.shape", x.shape)
expanded = tf.expand_dims(x, 1)
print("expanded.shape", expanded.shape)
sliced = tf.slice(x, [0, 1], [2, 1])
print("sliced.shape", sliced.shape)

with tf.Session() as sess:
  print("expanded: ", expanded.eval())
  print("sliced: ", sliced.eval())

"""
Explanation: Shape error
End of explanation
"""


def some_method(data):
  print(data.get_shape())
  a = data[:,0:2]
  print(a.get_shape())
  c = data[:,1:3]
  print(c.get_shape())
  s = (a + c)
  return tf.sqrt(tf.matmul(s, tf.transpose(s)))

with tf.Session() as sess:
  fake_data = tf.constant([5.0, 3.0, 7.1])
  print(sess.run(some_method(fake_data)))

def some_method(data):
  print(data.get_shape())
  a = data[:,0:2]
  print(a.get_shape())
  c = data[:,1:3]
  print(c.get_shape())
  s = (a + c)
  return tf.sqrt(tf.matmul(s, tf.transpose(s)))

with tf.Session() as sess:
  fake_data = tf.constant([5.0, 3.0, 7.1])
  fake_data = tf.expand_dims(fake_data, 0)
  print(sess.run(some_method(fake_data)))

"""
Explanation: Vector vs scalar
End of explanation
"""


def some_method(a, b):
  s = (a + b)
  return tf.sqrt(tf.matmul(s, tf.transpose(s)))

with tf.Session() as sess:
  fake_a = tf.constant([
      [5.0, 3.0, 7.1],
      [2.3, 4.1, 4.8],
    ])
  fake_b = tf.constant([
      [2, 4, 5],
      [2, 8, 7]
    ])
  print(sess.run(some_method(fake_a, fake_b)))

def some_method(a, b):
  b = tf.cast(b, tf.float32)
  s = (a + b)
  return tf.sqrt(tf.matmul(s, tf.transpose(s)))

with tf.Session() as sess:
  fake_a = tf.constant([
      [5.0, 3.0, 7.1],
      [2.3, 4.1, 4.8],
    ])
  fake_b = tf.constant([
      [2, 4, 5],
      [2, 8, 7]
    ])
  print(sess.run(some_method(fake_a, fake_b)))

"""
Explanation: Type error
End of explanation
"""


import tensorflow as tf
from tensorflow.python import debug as tf_debug

def some_method(a, b):
  b = tf.cast(b, tf.float32)
  s = (a / b)
  s2 = tf.matmul(s, tf.transpose(s))
  return tf.sqrt(s2)

with tf.Session() as sess:
  fake_a = [
      [5.0, 3.0, 7.1],
      [2.3, 4.1, 4.8],
    ]
  fake_b = [
      [2, 0, 5],
      [2, 8, 7]
    ]
  a = tf.placeholder(tf.float32, shape=[2, 3])
  b = tf.placeholder(tf.int32, shape=[2, 3])
  k = some_method(a, b)
  
  # Note: won't work without the ui_type="readline" argument because
  # Datalab is not an interactive terminal and doesn't support the default "curses" ui_type.
  # If you are running this a standalone program, omit the ui_type parameter and add --debug
  # when invoking the TensorFlow program
  #      --debug (e.g: python debugger.py --debug )
  sess = tf_debug.LocalCLIDebugWrapperSession(sess, ui_type="readline")
  sess.add_tensor_filter("has_inf_or_nan", tf_debug.has_inf_or_nan)
  print(sess.run(k, feed_dict = {a: fake_a, b: fake_b}))

"""
Explanation: TensorFlow debugger
Wrap your normal Session object with tf_debug.LocalCLIDebugWrapperSession
End of explanation
"""


%%writefile debugger.py
import tensorflow as tf

def some_method(a, b):
  b = tf.cast(b, tf.float32)
  s = (a / b)
  print_ab = tf.Print(s, [a, b])
  s = tf.where(tf.is_nan(s), print_ab, s)
  return tf.sqrt(tf.matmul(s, tf.transpose(s)))

with tf.Session() as sess:
  fake_a = tf.constant([
      [5.0, 3.0, 7.1],
      [2.3, 4.1, 4.8],
    ])
  fake_b = tf.constant([
      [2, 0, 5],
      [2, 8, 7]
    ])
  
  print(sess.run(some_method(fake_a, fake_b)))

"""
Explanation: In the tfdbg> window that comes up, try the following:
* run -f has_inf_or_nan
* Notice that several tensors are dumped once the filter criterion is met
* List the inputs to a specific tensor:
* li transpose:0 
* Print the value of a tensor
* pt transpose:0
* Where is the inf?
Visit https://www.tensorflow.org/programmers_guide/debugger for usage details of tfdbg
tf.Print()
Create a python script named debugger.py with the contents shown below.
End of explanation
"""


%%bash
python debugger.py

"""
Explanation: Execute the python script
End of explanation
"""


