## Take advantage of the overloaded operators Just like NumPy, TensorFlow overloads a number of python operators to make building graphs easier and the code more readable. The slicing op is one of the overloaded operators that can make indexing tensors very easy: ```python z = x[begin:end] # z = tf.slice(x, [begin], [end-begin]) ``` Be very careful when using this op though. The slicing op is very inefficient and often better avoided, especially when the number of slices is high. To understand how inefficient this op can be let's look at an example. We want to manually perform reduction across the rows of a matrix: ```python import tensorflow as tf import time x = tf.random_uniform([500, 10]) z = tf.zeros() for i in range(500): z += x[i] sess = tf.Session() start = time.time() sess.run(z) print("Took %f seconds." % (time.time() - start)) ``` On my MacBook Pro, this took 2.67 seconds to run! The reason is that we are calling the slice op 500 times, which is going to be very slow to run. A better choice would have been to use tf.unstack op to slice the matrix into a list of vectors all at once: ```python z = tf.zeros() for x_i in tf.unstack(x): z += x_i ``` This took 0.18 seconds. Of course, the right way to do this simple reduction is to use tf.reduce_sum op: ```python z = tf.reduce_sum(x, axis=0) ``` This took 0.008 seconds, which is 300x faster than the original implementation. TensorFlow also overloads a range of arithmetic and logical operators: ```python z = -x # z = tf.negative(x) z = x + y # z = tf.add(x, y) z = x - y # z = tf.subtract(x, y) z = x * y # z = tf.mul(x, y) z = x / y # z = tf.div(x, y) z = x // y # z = tf.floordiv(x, y) z = x % y # z = tf.mod(x, y) z = x ** y # z = tf.pow(x, y) z = x @ y # z = tf.matmul(x, y) z = x > y # z = tf.greater(x, y) z = x >= y # z = tf.greater_equal(x, y) z = x < y # z = tf.less(x, y) z = x <= y # z = tf.less_equal(x, y) z = abs(x) # z = tf.abs(x) z = x & y # z = tf.logical_and(x, y) z = x | y # z = tf.logical_or(x, y) z = x ^ y # z = tf.logical_xor(x, y) z = ~x # z = tf.logical_not(x) ``` You can also use the augmented version of these ops. For example `x += y` and `x **= 2` are also valid. Note that Python doesn't allow overloading "and", "or", and "not" keywords. TensorFlow also doesn't allow using tensors as booleans, as it may be error prone: ```python x = tf.constant(1.) if x: # This will raise a TypeError error ... ``` You can either use tf.cond(x, ...) if you want to check the value of the tensor, or use "if x is None" to check the value of the variable. Other operators that aren't supported are equal (==) and not equal (!=) operators which are overloaded in NumPy but not in TensorFlow. Use the function versions instead which are `tf.equal` and `tf.not_equal`.