import numpy as np

# Numpy is an array processing library with support for n-dimensional arrays and a number of mathematical operations
# How numpy handles arrays of varying shapes is common to a lot of mathematical processing done in python,
# most relevantly TensorFlow.

# Suppose we have a list of numbers
l = []
for i in range(1000):
    l.append(i)

# This can be converted into an array
a = np.array(l)
print(f"Shape of a: {a.shape}")

# We can reshape this array
b = np.reshape(a, (10, 10, 10))
print(f"Shape of b: {b.shape}")

# We can expand the dimensions of this array
# Note that these two operations are equivalent
c = np.expand_dims(a, axis=-1)
print(f"Shape of c: {c.shape}")
c = np.reshape(a, (1000, 1))
print(f"Shape of c: {c.shape}")

# We can also concatenate arrays along different axes
d = np.concatenate([b, b], axis=0)
e = np.concatenate([b, b], axis=1)
f = np.concatenate([b, b], axis=2)

print(f"Shape of d: {d.shape}")
print(f"Shape of e: {e.shape}")
print(f"Shape of f: {f.shape}")

# For mathematical operations, lets take a subset of b
# Here, we take the first 3 elements of each dimension
arr = b[:3, :3, :3]
print(f"arr: \n{arr}")

# Alternatively, we could have taken the first 3 elements of the first dimension
_ = b[:3, ...]
print(f"_: \n{_}")

# See https://numpy.org/doc/stable/reference/arrays.indexing.html
# for more information regarding this kind of indexing

# But lets keep things small

# Suppose we want to multiply the entire array by a constant.
# This is made easy by a process called broadcasting.
# There is a lot to broadcasting, so to keep things brief and simple,
# see https://numpy.org/doc/stable/user/basics.broadcasting.html
# for more information

# Here, arr2[i][j][k] == arr[i][j][k] * 3
arr2 = arr * 3
print(f"arr2: \n{arr2}")

# Broadcasting applies to the base binary mathematical operations
# i.e. + - * /

# Note here that none of these numpy operations are done in-place.
# i.e. in Line 57, arr is unchanged and available for future use.
# See the numpy docs https://numpy.org/doc/stable/index.html
# for options regarding in-place operations
