# -*- coding: utf-8 -*-
"""Day 76 - Computation with NumPy and N Dimensional Arrays.ipynb

Automatically generated by Colaboratory.

Original file is located at
    https://colab.research.google.com/drive/1kCcwZf4JArALwgz5UszKNIdt5WOVQVHi

# Introduction

In this notebook we'll learn how to use NumPy to work with numerical data.

# Import Statements
"""

import numpy as np

import matplotlib.pyplot as plt
from scipy import misc # contains an image of a racoon!
from PIL import Image # for reading image files

"""# Understanding NumPy's ndarray

NumPy's most amazing feature is the **powerful** ndarray.

#### 1-Dimensional Arrays (Vectors)
"""

my_array = np.array([1.1, 9.2, 8.1, 4.7])

my_array.shape

my_array[2]

my_array.ndim

"""#### 2-Dimensional Arrays (Matrices)"""

array_2d = np.array([[1, 2, 3, 9],
                     [5, 6, 7, 8]])

print(f'array_2d has {array_2d.ndim} dimensions')
print(f'Its shape is {array_2d.shape}')
print(f'It has {array_2d.shape[0]} rows and {array_2d.shape[1]} columns')
print(array_2d)

array_2d[1,2]

array_2d[0, :]

"""#### N-Dimensional Arrays (Tensors)

**Challenge**:
* How many dimensions does the array below have?
* What is its shape (i.e., how many elements are along each axis)?
* Try to access the value `18` in the last line of code.
* Try to retrieve a 1 dimensional vector with the values `[97, 0, 27, 18]`
* Try to retrieve a (3,2) matrix with the values `[[ 0,  4], [ 7,  5], [ 5, 97]]`

*Hint*: You can use the `:` operator just as with Python Lists.
"""

mystery_array = np.array(
    [
      [
        [0, 1, 2, 3],
        [4, 5, 6, 7]
      ],
      [
        [7, 86, 6, 98],
        [5, 1, 0, 4]
      ],
      [
        [5, 36, 32, 48],
        [97, 0, 27, 18]
      ]
     ]
   )

# Note all the square brackets!

print(f'mystery_array has {mystery_array.ndim} dimensions')
print(f'Its shape is {mystery_array.shape}')
print(f'Access the value 18 in the last line of code: {mystery_array[2, 1, 3]}')
print(f'Retrieve a 1 dimensional vector with the values [97, 0, 27, 18]:\n {mystery_array[2, 1]}')
print(f'Retrieve a (3,2) matrix with the values [[ 0, 4], [ 7, 5], [ 5, 97]]:\n {mystery_array[:, :, 0]}')

"""# NumPy Mini-Challenges

#### **Challenge 1**: Use [`.arange()`](https://numpy.org/devdocs/reference/generated/numpy.arange.html)to createa a vector `a` with values ranging from 10 to 29. You should get this:

`print(a)`

`[10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29]`
"""

a = np.arange(start=10, stop=30, step=1)
print(a)

"""#### **Challenge 2**: Use Python slicing techniques on `a` to:
* Create an array containing only the last 3 values of `a`
* Create a subset with only the 4th, 5th, and 6th values
* Create a subset of `a` containing all the values except for the first 12 (i.e., `[22, 23, 24, 25, 26, 27, 28, 29]`)
* Create a subset that only contains the even numbers (i.e, every second number)
"""

a[-3:]

a[3:6]

a[12:]

a[::2]

"""#### **Challenge 3**:Reverse the order of the values in `a`, so that the first element comes last:

`[29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13,
       12, 11, 10]`

If you need a hint, you can check out this part of the [NumPy beginner's guide](
https://numpy.org/devdocs/user/absolute_beginners.html#how-to-reverse-an-array)
"""

np.flip(a)

"""#### **Challenge 4**: Print out all the indices of the non-zero elements in this array: [6,0,9,0,0,5,0]"""

arr = np.array([6, 0, 9, 0, 0, 5, 0])
print(arr)

print(np.where(arr != 0))

"""#### **Challenge 5**: Use NumPy to generate a 3x3x3 array with random numbers

Hint: Use the [`.random()` function](https://numpy.org/doc/stable/reference/random/index.html?highlight=random#module-numpy.random)
"""

array_3d = np.random.randint(0, 100, size=(3, 3, 3))
print(array_3d)

"""#### **Challenge 6**: Use [`.linspace()`](https://numpy.org/doc/stable/reference/generated/numpy.linspace.html) to create a vector `x` of size 9 with values spaced out evenly between 0 to 100 (both included)."""

array_even = np.linspace(0, 100, num=9, dtype=np.int16)
print(array_even)

"""#### **Challenge 7**: Use [`.linspace()`](https://numpy.org/doc/stable/reference/generated/numpy.linspace.html) to create another vector `y` of size 9 with values between -3 to 3 (both included). Then plot `x` and `y` on a line chart using Matplotlib."""

array_even = np.linspace(-3, 3, num=9, dtype=np.int16)
plt.plot(array_even)
plt.xlabel('Size')
plt.ylabel('Value')
plt.show()

"""#### **Challenge 8**: Use NumPy to generate an array called `noise` with shape 128x128x3 that has random values. Then use Matplotlib's [`.imshow()`](https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.pyplot.imshow.html) to display the array as an image. """

noise = np.random.randint(0, 255, size=(128, 128, 3))
plt.imshow(noise)
plt.show()

"""# Linear Algebra with Vectors"""

v1 = np.array([4, 5, 2, 7])
v2 = np.array([2, 1, 3, 3])

# Python Lists vs ndarrays
list1 = [4, 5, 2, 7]
list2 = [2, 1, 3, 3]

v1 + v2

v1 * v2

"""# Broadcasting and Scalars

"""

array_2d = np.array([[1, 2, 3, 4],
                     [5, 6, 7, 8]])

array_2d + 10

array_2d * 5

"""# Matrix Multiplication with @ and .matmul()

"""

a1 = np.array([[1, 3],
               [0, 1],
               [6, 2],
               [9, 7]])

b1 = np.array([[4, 1, 3],
               [5, 8, 5]])

print(f'{a1.shape}: a has {a1.shape[0]} rows and {a1.shape[1]} columns.')
print(f'{b1.shape}: b has {b1.shape[0]} rows and {b1.shape[1]} columns.')
print('Dimensions of result: (4x2)*(2x3)=(4x3)')

"""**Challenge**: Let's multiply `a1` with `b1`. Looking at the wikipedia example above, work out the values for c12 and c33 on paper. Then use the [`.matmul()`](https://numpy.org/doc/stable/reference/generated/numpy.matmul.html) function or the `@` operator to check your work. """

np.matmul(a1, b1)

a1 @ b1

"""# Manipulating Images as ndarrays

"""

img = misc.face()

plt.imshow(img)
plt.show()

"""**Challenge**: What is the data type of `img`? Also, what is the shape of `img` and how many dimensions does it have? What is the resolution of the image?"""

type(img)

img.shape

img.ndim

print(f'Resolution of the img: {img.shape[0]} x {img.shape[1]}')

"""**Challenge**: Convert the image to black and white. The values in our `img` range from 0 to 255.
* Divide all the values by 255 to convert them to sRGB, where all the values are between 0 and 1.
* Next, multiply the sRGB array by the `grey_vals` to convert the image to grey scale.
* Finally use Matplotlib's [`.imshow()`](https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.pyplot.imshow.html) together with the colormap parameter set to gray `cmap=gray` to look at the results.
"""

grey_vals = np.array([0.2126, 0.7152, 0.0722])

img_array = img / 255
print(img_array)

img_grey_scale = img_array @ grey_vals
plt.imshow(img_grey_scale, cmap='gray')
plt.show()

"""**Challenge**: Can you manipulate the images by doing some operations on the underlying ndarrays? See if you can change the values in the ndarray so that:

1) You flip the grayscale image upside down

2) Rotate the colour image

3) Invert (i.e., solarize) the colour image. To do this you need to converting all the pixels to their "opposite" value, so black (0) becomes white (255).

#### Challenge Solutions
"""

plt.imshow(np.flip(img_grey_scale), cmap='gray')
plt.show()

plt.imshow(np.rot90(img))
plt.show()

img_solar = 255 - img
plt.imshow(img_solar)
plt.show()

"""# Use your Own Image!"""

file_name = 'yummy_macarons.jpg'

my_img = Image.open(file_name)
img_array = np.array(my_img)

img_array.ndim

img_array.shape

"""#### Use PIL to open """

plt.imshow(img_array)
plt.show()

plt.imshow(255 - img_array)
plt.show()

plt.imshow((img_array / 255) @ grey_vals, cmap='gray')
plt.show()

plt.imshow(np.flip(img_array / 255 @ grey_vals), cmap='gray')
plt.show()


import numpy as np

np.random.seed(0) # seed for reproducibility

x1 = np.random.randint(10, size=6) #1d array
x2 = np.random.randint(10, size=(3,4)) #2d array
x3 = np.random.randint(10, size=(3,4,5)) #3d array

print("x3 ndim:", x3.ndim)
print("x3 shape:", x3.shape)
print("x3 size:", x3.size)

print("dytpe:", x3.dtype)

print("itemsize:", x3.itemsize,  "bytes")
print("nbytes:", x3.nbytes, "bytes")

print(x2[:,0]) # first column of x2
print(x2[0,:]) #first row of x2

print(x2[0]) # equivelent to x2[0, :]
print("x2:")
print(x2)

#views

x2_sub = x2[:2, :2]
print("x2 sub array:")
print(x2_sub)

x2_sub[0, 0] = 99 #this will change the parent array as it is a view, not a copy
print(x2_sub)
print(x2)

#copying arrays

x2_sub_copy = x2[:2,:2].copy()
print(x2_sub_copy)

x2_sub_copy[0,0] = 42
print(x2_sub_copy)
print(x2)

#reshaping arrays

grid = np.arange(1,10).reshape((3,3))
print(grid)

x = np.array([1,2,3])

print(" ")
#row vector via reshape
print(x.reshape((1,3)))

#row vector via newaxis
print(x[np.newaxis, :])

#column vector via reshape
print(x.reshape((3,1)))

#column vector from newaxis
print(x[:, np.newaxis])

#concatenation
x = np.array([1,2,3])
y = np.array([4,5,6])
print(np.concatenate([x,y]))

z = [7,8,9]

print(np.concatenate([x,y,z]))

grid = np.array([[1,2,3],[4,5,6]])
print()
print(grid)
print(np.concatenate([grid,grid]))

print(np.concatenate([grid, grid], axis=1))

grid = np.array([[9,8,7],[6,5,4]])
#vertically stack arrays
print(np.vstack([x,grid]))
print("horizontally stack arrays")
y = np.array([[99],[99]])
print(np.hstack([grid,y]))

#np.dstack goes along third axis

print("splitting arrays")
x = [1,2,3,4,5,6,7,8]
print(x)
x1, x2, x3 = np.split(x, [3,5])
print("split [3,5]")
print(x1)
print(x2)
print(x3)

#hsplit, vsplit simmilar

grid = np.arange(16).reshape((4,4))
print(grid)
upper, lower = np.vsplit(grid, [2])
print("vsplit [2]")
print(upper)
print(lower)

left, right = np.hsplit(grid, [2])
print("hsplit [2]")
print(left)
print(right)


## 2. The mean as the center ##

# Make a list of values
values = [2, 4, 5, -1, 0, 10, 8, 9]
# Compute the mean of the values
values_mean = sum(values) / len(values)
# Find the difference between each of the values and the mean by subtracting the mean from each value.
differences = [i - values_mean for i in values]
# This equals 0.  Try changing the values around and verifying that it equals 0 if you want.
print(sum(differences))

# We can use the median function from numpy to find the median
# The median is the "middle" value in a set of values -- if you sort the values in order, it's the one in the center (or the average of the two in the center if there are an even number of items in the set)
# You'll see that the differences from the median don't always add to 0.  You might want to play around with this and think about why that is.
from numpy import median
values_median = median(values)
median_difference_sum = 0
for i in range(len(values)):
    val = values[i] - values_median
    median_difference_sum += val

## 3. Finding variance ##

import matplotlib.pyplot as plt
import pandas as pd
# The nba data is loaded into the nba_stats variable.
# Find the mean value of the column
pf_mean = nba_stats["pf"].mean()
# Initialize variance at zero
variance = 0
# Loop through each item in the "pf" column
for p in nba_stats["pf"]:
    # Calculate the difference between the mean and the value
    difference = p - pf_mean
    # Square the difference -- this ensures that the result isn't negative
    # If we didn't square the difference, the total variance would be zero
    # ** in python means "raise whatever comes before this to the power of whatever number is after this"
    square_difference = difference ** 2
    # Add the difference to the total
    variance += square_difference
# Average the total to find the final variance.
variance = variance / len(nba_stats["pf"])
pt_mean = nba_stats['pts'].mean()
va = 0
for i in nba_stats['pts']:
    va += (i - pt_mean)**2
point_variance =  va / len(nba_stats['pts'])

## 4. Order of operations ##

# You might be wondering why multiplication and division are on the same level.
# It doesn't matter whether we do the multiplication first, or the division first -- the answer here will always be the same.
# In this case, we need to think of division as multiplication by a fraction -- otherwise, we'll be dividing more than we want to.
# Create a formula
a = 5 * 5 / 2
# Multiply by 1/2 instead of dividing by 2 -- the result is the same (2/2 == 2 * 1/2)
a_subbed = 5 * 5 * 1/2
a_mul_first = 25 * 1/2
a_div_first = 5 * 2.5
print(a_mul_first == a_div_first)

# The same thing is true for subtraction and addition
# In this case, we need to convert subtraction into adding a negative number -- if we don't we'll end up subtracting more than we expect
b = 10 - 8 + 5
# Add -8 instead of subtracting 8
b_subbed = 10 + -8 + 5
b_sub_first = 2 + 5
b_add_first = 10 + -3
print(b_sub_first == b_add_first)

c = 10 / 2 + 5
d = 3 - 1 / 2 * 2
c = 10 / 2 * 5
d = 3 - 1 / 2 - 2

## 5. Using parentheses ##

a = 50 * 50 - 10 / 5
a_paren = 50 * (50 - 10) / 5
# If we put multiple operations inside parentheses, the order of operations is used inside to determine the order.
a_paren = 50 * (50 - 10 / 5)

b = 10 * (10 + 100)
c = (8 - 6) * 100

## 6. Fractional powers ##

a = 5 ** 2
# Raise to the fourth power
b = 10 ** 4

# Take the square root ( 3 * 3 == 9, so the answer is 3)
c = 9 ** (1/2)

# Take the cube root (4 * 4 * 4 == 64, so 4 is the cube root)
d = 64 ** (1/3)
e = 11**5
f = 10000 ** (1/4)

## 7. Calculating standard deviation ##

# The nba stats are loaded into the nba_stats variable.
def std_dev(data):
    d_mean = data.mean()
    v = 0
    for i in data:
        v += (i - d_mean)**2
    v = v/len(data)
    return(v**(1/2))

mp_dev = std_dev(nba_stats['mp'])
ast_dev = std_dev(nba_stats['ast'])

## 8. Find standard deviation distance ##

import matplotlib.pyplot as plt

plt.hist(nba_stats["pf"])
mean = nba_stats["pf"].mean()
plt.axvline(mean, color="r")
# We can calculate standard deviation by using the std() method on a pandas series.
std_dev = nba_stats["pf"].std()
# Plot a line one standard deviation below the mean
plt.axvline(mean - std_dev, color="g")
# Plot a line one standard deviation above the mean
plt.axvline(mean + std_dev, color="g")

# We can see how much of the data points fall within 1 standard deviation of the mean
# The more that falls into this range, the less spread out the data is
plt.show()

# We can calculate how many standard deviations a data point is from the mean by doing some subtraction and division
# First, we find the total distance by subtracting the mean
total_distance = nba_stats["pf"][0] - mean
# Then we divide by standard deviation to find how many standard deviations away the point is.
standard_deviation_distance = total_distance / std_dev

point_10 = nba_stats["pf"][9]
point_100 = nba_stats["pf"][99]
point_10_std = (point_10 - mean) / std_dev
point_100_std = (point_100 - mean) / std_dev

## 9. Working with the normal distribution ##

import numpy as np
import matplotlib.pyplot as plt
# The norm module has a pdf function (pdf stands for probability density function)
from scipy.stats import norm

# The arange function generates a numpy vector
# The vector below will start at -1, and go up to, but not including 1
# It will proceed in "steps" of .01.  So the first element will be -1, the second -.99, the third -.98, all the way up to .99.
points = np.arange(-1, 1, 0.01)

# The norm.pdf function will take points vector and turn it into a probability vector
# Each element in the vector will correspond to the normal distribution (earlier elements and later element smaller, peak in the center)
# The distribution will be centered on 0, and will have a standard devation of .3
probabilities = norm.pdf(points, 0, .3)

# Plot the points values on the x axis and the corresponding probabilities on the y axis
# See the bell curve?
plt.plot(points, probabilities)
plt.show()

pt = np.arange(-1,1,0.1)
prob = norm.pdf(pt,0,2)
plt.plot(pt,prob)
plt.show()

## 10. Normal distribution deviation ##

# Housefly wing lengths in millimeters
wing_lengths = [36, 37, 38, 38, 39, 39, 40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 42, 42, 42, 42, 42, 42, 42, 43, 43, 43, 43, 43, 43, 43, 43, 44, 44, 44, 44, 44, 44, 44, 44, 44, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 47, 47, 47, 47, 47, 47, 47, 47, 47, 48, 48, 48, 48, 48, 48, 48, 48, 49, 49, 49, 49, 49, 49, 49, 50, 50, 50, 50, 50, 50, 51, 51, 51, 51, 52, 52, 53, 53, 54, 55]
mean = sum(wing_lengths)/len(wing_lengths)
variances = [(i - mean)**2 for i in wing_lengths]
variance = sum(variances)/len(variances)
std = variance ** (1/2)
std= [(i - mean) /std for i in wing_lengths]
def within_percentage(deviations, count):
    within = [i for i in deviations if i <= count and i >= -count]
    count = len(within)
    return count / len(deviations)
within_one_percentage = within_percentage(std, 1)
within_two_percentage = within_percentage(std, 2)
within_three_percentage = within_percentage(std, 3)

## 11. Plotting correlations ##

import matplotlib.pyplot as plt

# This is plotting field goals attempted (number of shots someone takes in a season) vs point scored in a season
# Field goals attempted is on the x-axis, and points is on the y-axis
# As you can tell, they are very strongly correlated -- the plot is close to a straight line.
# The plot also slopes upward, which means that as field goal attempts go up, so do points.
# That means that the plot is positively correlated.
plt.scatter(nba_stats["fga"], nba_stats["pts"])
plt.show()

# If we make points negative (so the people who scored the most points now score the least, because 3000 becomes -3000), we can change the direction of the correlation
# Field goals are negatively correlated with our new "negative" points column -- the more free throws you attempt, the less negative points you score.
# We can see this because the correlation line slopes downward.
plt.scatter(nba_stats["fga"], -nba_stats["pts"])
plt.show()

# Now, we can plot total rebounds (number of times someone got the ball back for their team after someone shot) vs total assists (number of times someone helped another person score)
# These are uncorrelated, so you don't see the same nice line as you see with the plot above.
plt.scatter(nba_stats["trb"], nba_stats["ast"])
plt.show()
plt.scatter(nba_stats["fta"], nba_stats["pts"])
plt.show()
plt.scatter(nba_stats["stl"], nba_stats["pf"])
plt.show()

## 12. Measuring correlation ##

from scipy.stats.stats import pearsonr

# The pearsonr function will find the correlation between two columns of data.
# It returns the r value and the p value.  We'll learn more about p values later on.
r, p_value = pearsonr(nba_stats["fga"], nba_stats["pts"])
# As we can see, this is a very high positive r value -- close to 1
print(r)

# These two columns are much less correlated
r, p_value = pearsonr(nba_stats["trb"], nba_stats["ast"])
# We get a much lower, but still positive, r value
print(r)
r_fta_pts, p_value = pearsonr(nba_stats["fta"], nba_stats["pts"])
r_stl_pf, p_value = pearsonr(nba_stats["stl"], nba_stats["pf"])

## 13. Calculate covariance ##

# The nba_stats variable has been loaded.
def covariance(x, y):
    x_mean = sum(x) / len(x)
    y_mean = sum(y) / len(y)
    x_diffs = [i - x_mean for i in x]
    y_diffs = [i - y_mean for i in y]
    codeviates = [x_diffs[i] * y_diffs[i] for i in range(len(x))]
    return sum(codeviates) / len(codeviates)

cov_stl_pf = covariance(nba_stats["stl"], nba_stats["pf"])
cov_fta_pts = covariance(nba_stats["fta"], nba_stats["pts"])

## 14. Calculate correlation ##

from numpy import cov
# The nba_stats variable has already been loaded.
r_fta_blk = cov(nba_stats["fta"], nba_stats["blk"])[0,1] / ((nba_stats["fta"].var() * nba_stats["blk"].var())** (1/2))
r_ast_stl = cov(nba_stats["ast"], nba_stats["stl"])[0,1] / ((nba_stats["ast"].var() * nba_stats["stl"].var())** (1/2))

Probability Statistics Beginner/Standard deviation and correlation-14.py


"""
  Question 1: Partial Harmonic Series
"""
import numpy as np
import matplotlib.pyplot as plt
import pathlib
#%% Functions
# Naive (using loop)
def f(N):
  A = 0
  for n in range(1, N + 1):
    A += 1 / n
  return A

# Vectorized (to get faster results)
fv = lambda n: np.sum(1 / n)

#%% Experiments. Compute some values of series
EXP = 25
Ns = np.array([2 ** i for i in range(EXP+1)]) # N = {2^0, 2^1, ..., 2^EXP}

# Using loop (slow but for N too large may be stored in memory...)
#As = np.array([f(n) for n in Ns], dtype=np.float32)
#Ad = np.array([f(n) for n in Ns], dtype=np.float64)

# Using vectorized implementation (faster but dangerous with memory usage...)
As = np.array([fv(np.arange(1, n+1)) for n in Ns], dtype=np.float32) # Compute summation with single precision
Ad = np.array([fv(np.arange(1, n+1)) for n in Ns], dtype=np.float64) # Compute summation with double precision
diff = np.abs(As-Ad) # Absolute value of difference between single and double precision (a simple measure)

#%% Plot both summations
plt.plot(Ns, As, label="Single precision")
plt.plot(Ns, Ad, label="Double precision")
plt.grid(True)
plt.legend()
plt.show()
#%% Plot difference
plt.plot(Ns, diff, label=r'$|A_d - A_s$|')
plt.grid(True)
plt.yscale('log')
plt.xscale('log', basex=2)
plt.legend()
plt.show()

#%% Data to save
series = np.zeros((len(Ns), 4))
series[:,0] = Ns
series[:,1] = As
series[:,2] = Ad
series[:,3] = diff
#%% Save data for plots
DIR = 'data/1/' # Directory name
pathlib.Path(DIR).mkdir(parents=True, exist_ok=True) # Create Folder
np.savetxt(DIR + 'series.csv', series, fmt='%.16f', delimiter=',', header='N,As,Ad,dif', comments="") # Save data


import numpy as np

def central_difference_z(grid, Nz, Nx, dz, order=1):
    """
    Take the differentiation in z of a "2D z-x grid" via central difference.
    """
    if (order==1):
        grid_temp = np.vstack((np.zeros(Nx), grid, np.zeros(Nx)))

        prime_grid = (grid_temp[2:Nz+2] - grid_temp[0:Nz]) / (2*dz)

        # Endpoints with 2nd order accuracy
        prime_grid[0]    = ((-3/2)*grid[0]   + 2*grid[1]    - (1/2)*grid[2]) / dz
        prime_grid[Nz-1] = ((1/2)*grid[Nz-3] - 2*grid[Nz-2] + (3/2)*grid[Nz-1]) / dz

    elif (order==2):
        grid_temp = np.vstack((np.zeros(Nx), np.zeros(Nx), grid, np.zeros(Nx), np.zeros(Nx)))

        prime_grid = (-   grid_temp[4:Nz+4] \
                      + 8*grid_temp[3:Nz+3] \
                      - 8*grid_temp[1:Nz+1] \
                      +   grid_temp[0:Nz]) / (12*dz)

    elif (order==3):
        grid_temp = np.vstack((np.zeros(Nx),np.zeros(Nx),np.zeros(Nx), grid, np.zeros(Nx),np.zeros(Nx),np.zeros(Nx)))

        prime_grid = (    grid_temp[6:Nz+6] \
                     -  9*grid_temp[5:Nz+5] \
                     + 45*grid_temp[4:Nz+4] \
                     - 45*grid_temp[2:Nz+2] \
                     +  9*grid_temp[1:Nz+1] \
                     -    grid_temp[0:Nz] ) / (60*dz)
    else:
        raise ValueError(' order value has to be 1 or 2 or 3!! ')

    return prime_grid


import math
import random
import numpy as np
import matplotlib.pyplot as plt

xdim = 1024  # x dimension of image
ydim = 1024  # y dimension of image

# smooths the noise using interpolation
def fade(t):
    return 3*(t**2) -2*(t**3)

# finds closes edge to a pixel
def findEdge(x, y, size_box):
    if x % size_box == 0 and y % size_box == 0:
        return (math.ceil(x/size_box)+1,math.ceil(y/size_box)+1)
    elif x % size_box == 0 :
        return (math.ceil(x/size_box)+1,math.ceil(y/size_box))
    elif y % size_box == 0 :
        return (math.ceil(x/size_box),math.ceil(y/size_box)+1)
    else:
        return math.ceil(x/size_box), math.ceil(y/size_box) # returns outer 2 edges contain x and y

# creates the creates the perlin noise array
def makeNoise(num_boxes):
    global xdim, ydim
    pixels = np.zeros((xdim,ydim))
    size_box = int(xdim/num_boxes)
    boxes =[]

    # array of sqaures in the grid
    for j in range(0, xdim+size_box, size_box):
            for k in range(0, ydim+size_box, size_box):
                boxes.append([k,j])

    boxes = np.asarray(boxes)
    corners = np.reshape(boxes, (num_boxes+1,num_boxes+1,2))   # squares converted to corners

    # generates a vector for each corner in the grid using the unit circle
    vectors =[]
    for i in range(len(boxes)):
        radians = (2*math.pi) * random.uniform(0, 1)
        vectors.append([round(math.cos(radians),3), round(math.sin(radians),3)])

    vectors = np.asarray(vectors)
    vectors = np.reshape(vectors,(num_boxes+1,num_boxes+1,2))

    # creates noise using perlin noise algorithim
    for x in range(xdim):
        for y in range(ydim):
            edge4 = findEdge(x, y, size_box)

            # finds nearest edges to the specified pixel
            edge1 = (edge4[0]-1,edge4[1]-1) #[0,0]
            edge2 = (edge4[0]-1,edge4[1]) #[0,1]
            edge3 = (edge4[0],edge4[1]-1) #[1,0]
            edge4 = edge4 #[1,1]

            # finds the nearest corners based on the calculated edges
            corner1 = corners[edge1[::-1]]
            corner2 = corners[edge2[::-1]]
            corner3 = corners[edge3[::-1]]
            corner4 = corners[edge4[::-1]]

            # calculates the distance between each corner and a pixel and normalizes them based on the size of each box
            dist1 = np.array([x-corner1[0], y-corner1[1]])/size_box
            dist2 = np.array([x-corner2[0], y-corner2[1]])/size_box
            dist3 = np.array([x-corner3[0], y-corner3[1]])/size_box
            dist4 = np.array([x-corner4[0], y-corner4[1]])/size_box

            # stores the vector for the specifed corners using the calculated edges
            vect1 = vectors[edge1]
            vect2 = vectors[edge2]
            vect3 = vectors[edge3]
            vect4 = vectors[edge4]

            # calculates the dot product between all 4 vectors and uses the fading function to smooth it
            dp1 = (vect1@dist1)*fade(1-dist1[0])*fade(1-dist1[1])
            dp2 = (vect2@dist2)*fade(1-dist1[0])*fade(dist1[1])
            dp3 = (vect3@dist3)*fade(dist1[0])*fade(1-dist1[1])
            dp4 = (vect4@dist4)*fade(dist1[0])*fade(dist1[1])

            sums = dp1+dp2+dp3+dp4 # sums all the dot products
            pixels[x][y] = sums # sets the pixel to the sum of all dot products

    return pixels

def add_contrast(img,amt): #change
    im2 = amt*(img-128)/128
    return 256 / (1 + np.exp(-1*im2))

def make_map():
    # map 1
    raw = makeNoise(4)  # makes an array with noise using 4 boxes

    raw -= np.amin(raw)  # finds the minimum value in the array and ensures non negative pixels
    raw /= np.amax(raw)  # finds the maximum value in the array and normalizes the pixels
    final1 = 256*raw     # creates the rgb value for each pixel

    # map 2
    raw2 = makeNoise(16)

    raw2 -= np.amin(raw2)
    raw2 /= np.amax(raw2)
    final2 = 256*raw2

    # map 3
    raw3 = makeNoise(64)

    raw3 -= np.amin(raw3)
    raw3 /= np.amax(raw3)
    final3 = 256*raw3

    completeMap = (0.4*final1)+ (0.4*(final2))+ (0.2*(final3))    # adds all 3 maps on top of each other to create 1 map
    added = add_contrast(completeMap,4)
    added -= np.amin(added)
    added /= np.amax(added)
    added = 256*added

    return completeMap

# plots the generated noise
completeMap = make_map()

fig, ax = plt.subplots(figsize=(10,10))
ax.imshow(completeMap, cmap='gray', vmin=0, vmax=256, interpolation='nearest')

# uses the generated noise to make a map
def generate_map(noise, xdim, ydim):
    new_pixels = np.zeros((512,512,3))
    for x in range(xdim):
        for y in range(ydim):
            if noise[x,y] < 105:
                new_pixels[x,y] = [165,186,58] #green
            elif noise[x,y] < 120:
                new_pixels[x,y] = [245,219,136] #yellow
            else:
                new_pixels[x,y] = [0,70,170] #blue
    return new_pixels

# plots the generated map
gm = generate_map(completeMap, 512, 512)

fig, ax = plt.subplots(figsize=(10,10))
ax.imshow(gm/256, vmin=0, vmax=256, interpolation='nearest')


import numpy as np
import matplotlib.pyplot as plt
m=10
d_teta1=0.01
teta_1_min=-1
teta_1_max=1

# here we actually have a graph with h_teta=teta1*x
X = np.arange(m)
np.random.seed(42) #use to get the same results every run
rnd = np.random.rand(m)
Y = np.arange(m)*0.5 + rnd # actually we have h = teta1*x where teta1 is actually 0.5

#estimated y -> H
Teta1 = np.arange(teta_1_min,teta_1_max,d_teta1)
# J is not required for comuting here gradient descent
# J is used here just to get min(J) as a comparison for me
J=[]

# can i do it without a loop ???
for teta1 in Teta1:
    H = X * teta1
    E = H - Y
    cost = np.dot(E,E)/(2*m)
    J.append(cost)

# compute teta1 for min(J)
min_j_index = np.argmin(J)
teta1 = Teta1[min_j_index]

h_vec = X * Teta1[min_j_index] # computed linear estimation

# gradient descent
teta1_gds = 100 # arbitrary initial condition
iterations = 0
max_iterations = 10000
alfa = 0.001 # learning rate

while iterations < max_iterations:
    H = X * teta1_gds
    E = H - Y
    dj_to_dteta1 = (1/m)*np.dot(E, X)
    teta1_gds = teta1_gds - alfa * dj_to_dteta1
    iterations += 1
    j = np.dot(E,E)/(2*m)
    iterations += 1
    print(iterations,j)

print("min(J) : {:.3f} , tata1 @ min(J) : {:.3f}".format(J[min_j_index] , teta1))
print("gradient descent tata1  : {:.3f} , iterations : {:.3f}".format(teta1_gds,iterations))


'''
This python program solves the following driven damped pendulum equation:
theta''(t) = (-1/Q)theta'(t) + sin(theta(t)) + d cos(Omega t)
Where   theta(t)        : angular position as a fn of time
        Q               : damping factor
        sin(theta(t))   : nonlinear term in Simple Harmonic motion equation
        d               : Driving force amplitude
        Omega           : Driving force frequency

This second order nonlinear differential equation is first transformed to a system of
2 first order diffeqs and then solved using scipy.odeint(...)

The first order diff eqs are:
theta'(t) = omega
omega'(t) = (-1/Q)omega + sin(theta(t)) + d cos(Omega t)
Where   omega = theta'(t) for convenience.

The new initial conditions are given by theta0 and omega0.  These are fed to the y0
argument in odeint as seen below.

For greater detail, please visit
http://www.physics.nyu.edu/pine/pymanual/html/chap9/chap9_scipy.html#solving-odes

__author__ : folks at physics.nyu.edu
'''
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint

def f(y, t, params):
    #print('inside function f...')
    theta, omega = y      # unpack current values of y
    Q, d, Omega = params  # unpack parameters
    derivs = [omega,      # list of dy/dt=f functions
             -omega/Q + np.sin(theta) + d*np.cos(Omega*t)]
    return derivs

# Parameters
print('inside initialization portion...')
Q = 2.0          # quality factor (inverse damping)
d = 1.5          # forcing amplitude
Omega = 0.65     # drive frequency

# Initial values
theta0 = 0.0     # initial angular displacement
omega0 = 0.0     # initial angular velocity

# Bundle parameters for ODE solver
params = [Q, d, Omega]

# Bundle initial conditions for ODE solver
y0 = [theta0, omega0]

# Make time array for solution
tStop = 50.
tInc = 0.05
t = np.arange(0., tStop, tInc)
#print t.size #printing for debugging

# Call the ODE solver
psoln = odeint(f, y0, t, args=(params,))
#print psoln.dtype #printing for debugging
#print psoln.size #printing for debugging

# Plot results
fig = plt.figure(1, figsize=(8,8))

# Plot theta as a function of time
ax1 = fig.add_subplot(311)
ax1.plot(t, psoln[:,0])
ax1.set_xlabel('time')
ax1.set_ylabel('theta')

# Plot omega as a function of time
ax2 = fig.add_subplot(312)
ax2.plot(t, psoln[:,1])
ax2.set_xlabel('time')
ax2.set_ylabel('omega')

# Plot omega vs theta
ax3 = fig.add_subplot(313)
twopi = 2.0*np.pi
ax3.plot(psoln[:,0]%twopi, psoln[:,1], '.', ms=1)
ax3.set_xlabel('theta')
ax3.set_ylabel('omega')
ax3.set_xlim(0., twopi)

plt.tight_layout()
plt.show()


#%%
# import libraries
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

#%%
# read data
path = 'ex1data2.txt'
data = pd.read_csv(path, header = None, names= ['Size', 'Bedrooms', 'Price'])

#%%
# show imported data details
# print('data = \n', data.head(10))
# print('**************************************')
# print('data.describe = \n', data.describe())
# print('**************************************')

#%%
#Normalizes the features in X
def featureNormalize(data):
    data_norm = data.copy()
    data_norm.iloc[:, 0:-1] = (data.iloc[:, 0:-1] - data.iloc[:, 0:-1].mean()) / data.iloc[:, 0:-1].std()
    return data_norm, data.mean(), data.std()

data_norm, mu, sigma = featureNormalize(data)

#%%
# show normalized data details
# print('norm data = \n', data_norm.head(10))
# print('**************************************')
# print('data_norm.describe = \n', data_norm.describe())
# print('**************************************')

#%%
# adding a new column called ones before the data
data.insert(0, 'Ones', 1)
data_norm.insert(0, 'Ones', 1)
# print('new data = \n', data_norm.head(10))
# print('**************************************')

#%%
# separate X (training data) from y (target variable)
cols = data_norm.shape[1]
X = data_norm.iloc[:, 0 : cols-1]
y = data_norm.iloc[:, cols-1 : cols]

# print('X data = \n', X.head(10))
# print('**************************************')
# print('y data = \n', y.head(10))
# print('**************************************')

#%%
# draw data
#3D
fig, ax = plt.subplots(figsize= (6,6), subplot_kw={'projection' : '3d'})
ax.scatter3D(data_norm['Size'], data_norm['Bedrooms'], data_norm['Price'], s= 30)
plt.show()

#2D
fig, ax = plt.subplots(figsize= (6,6))
ax.scatter(data_norm['Size'], data_norm['Price'], s= 30, label= 'Dataset')
ax.set(xlabel= 'Size (Normalized)', ylabel= 'Price', title= 'Dataset')
plt.legend(loc= 1, shadow=True)
plt.show()

#%%
# Convert data from data frames to numpy matrices
X = np.matrix(X.values)
y = np.matrix(y.values)
theta = np.matrix(np.array(np.zeros((cols-1, 1))))

# print('X \n', X)
print('\nX.shape = ', X.shape)
print('**************************************')
# print('y \n', y)
print('y.shape = ', y.shape)
print('**************************************')
# print('theta \n', theta)
print('theta.shape = ', theta.shape)
print('**************************************')

#%%
# Cost function
def computeCost(X, y, theta):
    J = np.sum(np.power(((X * theta) - y), 2)) / (2 * len(y))
    return float(J)

#%%
# Running Gradient Descent
def gradientDescent(X, y, theta, alpha, num_iters):
    temp = np.matrix(np.zeros(theta.shape))
    J_history = np.zeros((num_iters, 1))

    for i in range(num_iters):
        for j in range(len(theta)):
            temp[j, 0] = theta[j, 0] - ((alpha / len(y)) * np.sum(np.multiply(((X * theta) - y), X[:, j])))

        theta = temp.copy()
        J_history[i,0] = computeCost(X, y, theta)

    return theta, J_history

iterations = 400
alpha = 0.01

theta, J_history = gradientDescent(X, y, theta, alpha, iterations)

print('Theta computed from gradient descent: ')
for i in range(len(theta)): print(theta[i,0])
print('**************************************')

test = np.array([[1.], [1650.], [3.]])
print('Predicted price of a 1650 sq-ft, 3 br house (using gradient descent):\n $', (theta.T * test)[0,0])
print('Expected Price (approx)\n $ 165489064.118993')
print('**************************************')
# print('J_history\n', J_history)
# print('**************************************')

#%%
# Normalize the test point
print(test)
test[1,:] = (test[1,:] - np.mean(np.matrix(data['Size']), axis= 1)) / np.std(np.matrix(data['Size']), axis= 1)
test[2,:] = (test[2,:] - np.mean(np.matrix(data['Bedrooms']), axis= 1)) / np.std(np.matrix(data['Bedrooms']), axis= 1)
print(test)

# draw the best fit line from Gradient Descent
fig, ax = plt.subplots(figsize= (6,6))
ax.scatter(data_norm['Size'], data_norm['Price'], s= 30, label= 'Dataset')
ax.scatter(test[1,:], (theta.T * test)[0,0], s= 30, marker= 'x', color= 'r', linewidths=2, label= 'Test Data')
ax.plot(X[:,1], (X[:,1]*theta[1,:]) + theta[0,:], 'r-', linewidth= 2, label= 'Best Fit line')
ax.set(xlabel= 'Size (Normalized)', ylabel= 'Price', title= 'Best Fit line from Gradient Descent')
plt.legend(loc= 2, shadow=True, borderpad= 1)
plt.show()

#%%
# draw error graph
fig, ax = plt.subplots(figsize=(6,6))
ax.plot(np.arange(1, iterations+1), J_history, 'b', linewidth=2)
ax.set(xlabel= 'No. of Iterations', ylabel= 'Cost', title= 'Error vs. Training Data')
plt.show()

#%%
# reset the data
del X,y,theta
cols = data.shape[1]
X = data.iloc[:, 0 : cols-1]
y = data.iloc[:, cols-1 : cols]
X = np.matrix(X.values)
y = np.matrix(y.values)

#%%
# Calculate the parameters from the normal equation
def normalEqn(X, y):
    theta = np.matrix(np.zeros((X.shape[1], 1)))
    theta = np.linalg.inv(X.T * X) * X.T * y
    return theta

theta = normalEqn(X, y)

#%%
# Display normal equation's result
print('\nTheta computed from the normal equations: ')
for i in range(len(theta)): print(theta[i,0])
print('**************************************')

test = np.array([[1.], [1650.], [3.]])
print('Predicted price of a 1650 sq-ft, 3 br house (using normal equations):\n $', (theta.T * test)[0,0])
print('Expected Price (approx)\n $ 293081.464335')
print('**************************************')

#%%
# draw the best fit line from normal equation
fig, ax = plt.subplots(figsize= (6,6))
ax.scatter(data['Size'], data['Price'], s= 30, label= 'Dataset')
ax.scatter(test[1,:], (theta.T * test)[0,0], s= 30, marker= 'x', color= 'r', linewidths=2, label= 'Test Data')
ax.plot(X[:,1], (X[:,1]*theta[1,:]) + theta[0,:], 'r-', linewidth= 2, label= 'Best Fit line')
ax.set(xlabel= 'Size', ylabel= 'Price', title= 'Best Fit line from Normal Equation')
plt.legend(loc= 2, shadow=True, borderpad= 1)
plt.show()


import numpy as np
import sympy as sp
from prettytable import PrettyTable
import math
from math import cos, sin , exp
from sympy import cos, sin , exp

def cambiarValores(dic_var, nuevos_valores, num_ecuaciones, var):
    for i in range(0, num_ecuaciones):
        dic_var[f'{var[i]}'] = nuevos_valores[i]
    return dic_var

def nuevosValores(ecua, Ecuaciones, variables):
    valor_ini = []
    funcs = vars(math)
    for i in range(0, Ecuaciones):
        expr = ecua[i]
        funcion = eval(expr,funcs, variables)
        valor_ini.append(funcion)
    return valor_ini

def efunciones(var, valor, Ecuaciones):
    var_valor = {}
    for i in range(0, Ecuaciones):
        variable = var[i]
        anadir = {f'{variable}': valor[i]}
        var_valor.update(anadir)
    return var_valor

def punto_fijo_multivariable(ecua, var, valor, Ecuaciones, emax, N=50):
    encabezados = []
    encabezados.append("Iteracion")
    for i in var:
        encabezados.append(i)
    encabezados.append(f"Error |{var[0]}(i)-{var[0]}(i-1)|")
    contenido = []
    tabla = PrettyTable(encabezados)
    tabla.title = "METODO DE PUNTO FIJO MULTIVARIABLE"
    evalu_func = efunciones(var, valor, Ecuaciones)
    for k in range(1, N):

        variables = cambiarValores(evalu_func, valor, Ecuaciones, var)
        corregidos = nuevosValores(ecua, Ecuaciones, variables)
        error = abs(valor[0]-corregidos[0])
        valor = corregidos

        contenido = []
        contenido.append(k)
        for i in range(0, Ecuaciones):
            contenido.append("{0:.7f}".format(valor[i]))
        contenido.append("{0:.7f}".format(error))
        # tabla.add_row([k, "{0:.7f}".format(valor[0]), "{0:.7f}".format(
        #    valor[1]), "{0:.7f}".format(error)])
        tabla.add_row(contenido)
        if error < emax or error == 0:
            break
        # print(valor)
    #funcion = eval(expr, {f'{var1}': valor[0],f'{var2}':  valor[1]})
    #w = {f'{var1}': valor[0], f'{var2}':  valor[1]}
    print(tabla)
    print(f'Solucion del sistema:  ')
    for i in range(0, Ecuaciones):
        print(f'                     {var[i]} = {"{0:.4f}".format(valor[i])}')

#ecua = ['(x**2+y**2+8)/10', '(x*y**2+x+8)/10']
#var = ['x', 'y']
#valori = [0.0, 0.0]
#Ecuaciones = 2

#ecua = ['(9-y**2-z**2)**0.5', '1/(x*z)','(x+y)**0.5']
#var = ['x', 'y','z']
#valori = [2.5, 0.2,1.6]
#Ecuaciones = 3

#ecua = ['(0.5+cos(y*z))/3', 'x/(625)**0.5','(-exp(-x*y)-(10*pi-3)/3)/20']
#var = ['x', 'y', 'z']
#valori = [1, 1, 1]
#Ecuaciones = 3

#punto_fijo_multivariable(ecua, var, valori, Ecuaciones, 1e-3, N=50)

src/3. Sistemas de ecuaciones no lineales/Metodos/pf_multivariable.py


import numpy as np

## Linear scalar Dahlquist's equation
def linear_scalar_flux(u,t=0,k_coef=10):
    ff=np.zeros(np.shape(u))
    ff[0]= -k_coef*u[0]
    return ff

def linear_scalar_exact_solution(u0,t,k_coef=10):
    return np.array([np.exp(-k_coef*u0[0]*t)])

def linear_scalar_jacobian(u,t=0,k_coef=10):
    Jf=np.zeros((len(u),len(u)))
    Jf[0,0]=-k_coef
    return Jf

#nonlinear problem y'=-ky|y| +1
def nonlinear_scalar_flux(u,t=0,k_coef=10):
    ff=np.zeros(np.shape(u))
    ff[0]=-k_coef*abs(u[0])*u[0] +1
    return ff

def nonlinear_scalar_exact_solution(u0,t,k_coef = 10):
        sqrtk = np.sqrt(k_coef)
        ustar = 1 / sqrtk
        if u0[0] >= ustar:
            uex=np.array([1./np.tanh(sqrtk * t + np.arctanh(1/sqrtk /u0[0])) / sqrtk])
        elif u0[0] < 0 and t < - np.atan(sqrtk * u0[0]) / sqrtk:
            uex=np.array([np.tan(sqrtk * t + np.arctan(sqrtk * u0[0])) / sqrtk])
        else:
            uex=np.array([np.tanh(sqrtk * t + np.arctanh(sqrtk * u0[0])) / sqrtk])
        return uex

def nonlinear_scalar_jacobian(u,t=0,k_coef=10):
    Jf=np.zeros((len(u),len(u)))
    Jf[0,0]=-k_coef*abs(u[0])
    return Jf

# SYSTEMS

# linear systems
def linear_system2_flux(u,t=0):
    d=np.zeros(len(u))
    d[0]= -5*u[0] + u[1]
    d[1]= 5*u[0] -u[1]
    return d

def linear_system2_exact_solution(u0,t):
    A=np.array([[-5,1],[5,-1]])
    u_e=u0+(1-np.exp(-6*t))/6*np.dot(A,u0)
    return u_e

def linear_system2_jacobian(u,t=0):
    Jf=np.array([[-5,1],[5,-1]])
    return Jf

linear_system2_matrix = np.array([[-5,1],[5,-1]])

def linear_system2_production_destruction(u,t=0):
    p=np.zeros((len(u),len(u)))
    d=np.zeros((len(u),len(u)))
    p[0,1]=u[1]
    d[1,0]=u[1]
    p[1,0]=5*u[0]
    d[0,1]=5*u[0]
    return p,d

#lin system 3 x3

def linear_system3_flux(u,t=0):
    d=np.zeros(len(u))
    d[0]= -u[0] + 3*u[1]
    d[1]= -3*u[1] + 5*u[2]
    d[2]= -5*u[2]
    return d

def linear_system3_exact_solution(u0,t=0):
    u_e = np.zeros(len(u0))
    u_e[0] = 15.0/8.0*u0[2]*(np.exp(-5*t) - 2*np.exp(-3*t)+np.exp(-t))
    u_e[1] = 5.0/2.0*u0[2]*(-np.exp(-5*t) + np.exp(-3*t))
    u_e[2] = u0[2]*np.exp(-5*t)
    return u_e
def linear_system3_jacobian(u,t=0):
    Jf=np.zeros((len(u),len(u)))
    Jf[0,0]=-1.
    Jf[0,1]=3
    Jf[1,1] = -3
    Jf[1,2] = 5
    Jf[2,2] = -5
    return Jf

## Nonlinear 3x3 system production destruction
def nonlinear_system3_flux(u,t=0):
    ff=np.zeros(len(u))
    ff[0]= -u[0]*u[1]/(u[0]+1)
    ff[1]= u[0]*u[1]/(u[0]+1) -0.3*u[1]
    ff[2]= 0.3*u[1]
    return ff

def nonlinear_system3_production_destruction(u,t=0):
    p=np.zeros((len(u),len(u)))
    d=np.zeros((len(u),len(u)))
    p[1,0]=u[0]*u[1]/(u[0]+1)
    d[0,1]=p[1,0]
    p[2,1]=0.3*u[1]
    d[1,2]=p[2,1]
    return p,d

# SIR Model
def SIR_flux(u,t=0,beta=3,gamma=1):
    ff=np.zeros(len(u))
    N=np.sum(u)
    ff[0]=-beta*u[0]*u[1]/N
    ff[1]=+beta*u[0]*u[1]/N - gamma*u[1]
    ff[2]= gamma*u[1]
    return ff

def SIR_jacobian(u,t=0,beta=3,gamma=1):
    Jf=np.zeros((len(u),len(u)))
    N=np.sum(u)
    Jf[0,0]=-beta*u[1]/N
    Jf[0,1]=-beta*u[0]/N
    Jf[1,0]= beta*u[1]/N
    Jf[1,1]= beta*u[0]/N - gamma
    Jf[2,1] = gamma
    return Jf

def SIR_production_destruction(u,t=0,beta=3,gamma=1):
    p=np.zeros((len(u),len(u)))
    d=np.zeros((len(u),len(u)))
    N=np.sum(u)
    p[1,0]=beta*u[0]*u[1]/N
    d[0,1]=p[1,0]
    p[2,1]=gamma*u[1]
    d[1,2]=p[2,1]
    return p,d

# Nonlinear_oscillator
def nonLinearOscillator_flux(u,t=0,alpha=0.):
    ff=np.zeros(np.shape(u))
    n=np.sqrt(np.dot(u,u))
    ff[0]=-u[1]/n-alpha*u[0]/n
    ff[1]=u[0]/n - alpha*u[1]/n
    return ff

def nonLinearOscillator_exact_solution(u0,t):
    u_ex=np.zeros(np.shape(u0))
    n=np.sqrt(np.dot(u0,u0))
    u_ex[0]=np.cos(t/n)*u0[0]-np.sin(t/n)*u0[1]
    u_ex[1]=np.sin(t/n)*u0[0]+np.cos(t/n)*u0[1]
    return u_ex

# Non linear oscillator damped
def nonLinearOscillatorDamped_flux(u,t,alpha=0.01):
    ff=np.zeros(np.shape(u))
    n=np.sqrt(np.dot(u,u))
    ff[0]=-u[1]/n-alpha*u[0]/n
    ff[1]=u[0]/n - alpha*u[1]/n
    return ff

def nonLinearOscillatorDamped_exact_solution(u0,t,alpha=0.01):
    u_ex=np.zeros(np.shape(u0))
    n0=np.sqrt(np.dot(u0,u0))
    n=n0*np.exp(-alpha*t)
    u_ex[0]=n/n0*(np.cos(t/n)*u0[0]-np.sin(t/n)*u0[1])
    u_ex[1]=n/n0*(np.sin(t/n)*u0[0]+np.cos(t/n)*u0[1])
    return u_ex

# Robertson
def Robertson_flux(u,t=0,alpha=10**4,beta=0.04, gamma=3*10**7):
    ff=np.zeros(np.shape(u))
    ff[0] = alpha*u[1]*u[2]-beta*u[0]
    ff[1] = beta*u[0]-alpha*u[1]*u[2] - gamma*u[1]**2
    ff[2] = gamma*u[1]**2
    return ff

def Robertson_jacobian(u,t=0,alpha=10**4,beta=0.04, gamma=3*10**7):
    Jf=np.zeros((3,3))
    Jf[0,0]= -beta
    Jf[0,1]= alpha*u[2]
    Jf[0,2]= alpha*u[1]
    Jf[1,0]= beta
    Jf[1,1]= -alpha*u[2]-2*gamma*u[1]
    Jf[1,2]= -alpha*u[1]
    Jf[2,1] = 2*gamma*u[1]
    return Jf

def Robertson_production_destruction(u,t=0,alpha=10**4,beta=0.04, gamma=3*10**7):
    p=np.zeros((len(u),len(u)))
    d=np.zeros((len(u),len(u)))
    p[0,1]=alpha*u[1]*u[2]
    d[1,0]=p[0,1]
    p[1,0]=beta*u[0]
    d[0,1]=p[1,0]
    p[2,1]=gamma*u[1]**2
    d[1,2]=p[2,1]
    return p,d

def Robertson_rhs(u,t=0):
    return np.zeros(3)

# Lotka:
def lotka_flux(u,t=0,alpha=1,beta=0.2,delta=0.5,gamma=0.2):
    ff=np.zeros(np.shape(u))
    ff[0]=alpha*u[0]-beta*u[0]*u[1]
    ff[1]=delta*beta*u[0]*u[1]-gamma*u[1]
    return ff

def lotka_jacobian(u,t=0,alpha=1,beta=0.2,delta=0.5,gamma=0.2):
    Jf=np.zeros((2,2))
    Jf[0,0] = alpha -beta*u[1]
    Jf[0,1] = -beta*u[0]
    Jf[1,0] = delta*beta*u[1]
    Jf[1,1] = delta*beta*u[0] -gamma
    return Jf

#3 bodies problem in 2D: U=(x_1,x_2,v_1,v_2,y_1,y_2,w_1,w_2,z_1,z_2,s_1,s_2)
# where x is the 2D position of body1 and v is speed body1 sun
# y, w are position and velocity body2 earth
# z, s are position and velocity body3 mars

def threeBodies_flux(u,t=0):
    m1=1.98892*10**30
    m2=5.9722*10**24
    m3=6.4185*10**23
    G=6.67*10**(-11)
    f=np.zeros(np.shape(u))
    x=u[0:2]
    v=u[2:4]
    y=u[4:6]
    w=u[6:8]
    z=u[8:10]
    s=u[10:12]
    dxy3=np.linalg.norm(x-y)**3
    dxz3=np.linalg.norm(x-z)**3
    dyz3=np.linalg.norm(y-z)**3
    f[0:2]=v
    f[2:4]=-m2*G/dxy3*(x-y)-m3*G/dxz3*(x-z)
    f[4:6]=w
    f[6:8]=-m1*G/dxy3*(y-x)-m3*G/dyz3*(y-z)
    f[8:10]=s
    f[10:12]=-m1*G/dxz3*(z-x)-m2*G/dyz3*(z-y)
    return f

class ODEproblem:
    def __init__(self,name):
        self.name=name
        if self.name=="linear_scalar":
            self.u0 = np.array([1.])
            self.T_fin= 2.
            self.k_coef=10
            self.matrix=np.array([-self.k_coef])
        elif self.name=="nonlinear_scalar":
            self.k_coef=10
            self.u0 = np.array([1.1/np.sqrt(self.k_coef)])
            self.T_fin= 1.
        elif self.name=="linear_system2":
            self.u0 = np.array([0.9,0.1])
            self.T_fin= 1.
            self.matrix = np.array([[-5,1],[5,-1]])
        elif self.name=="linear_system3":
            self.u0 = np.array([0,0.,10.])
            self.T_fin= 10.
        elif self.name=="nonlinear_system3":
            self.u0 = np.array([9.98,0.01,0.01])
            self.T_fin= 30.
        elif self.name=="SIR":
            self.u0 = np.array([1000.,1,10**-20])
            self.T_fin= 10.
        elif self.name=="nonLinearOscillator":
            self.u0 = np.array([1.,0.])
            self.T_fin= 50
        elif self.name=="nonLinearOscillatorDamped":
            self.u0 = np.array([1.,0.])
            self.T_fin= 50
        elif self.name=="Robertson":
            self.u0 = np.array([1.,10**-20,10**-20])
            self.T_fin= 10.**10.
        elif self.name=="lotka":
            self.u0 = np.array([1.,2.])
            self.T_fin= 100.
        elif self.name=="threeBodies":
            self.u0 = np.array([0,0,0,0,149*10**9,0,0,30*10**3,-226*10**9,0,0,-24.0*10**3])
            self.T_fin= 10.**8.
        else:
            raise ValueError("Problem not defined")

    def flux(self,u,t=0):
        if self.name=="linear_scalar":
            return linear_scalar_flux(u,t,self.k_coef)
        elif self.name=="nonlinear_scalar":
            return nonlinear_scalar_flux(u,t,self.k_coef)
        elif self.name=="linear_system2":
            return linear_system2_flux(u,t)
        elif self.name=="linear_system3":
            return linear_system3_flux(u,t)
        elif self.name=="nonlinear_system3":
            return nonlinear_system3_flux(u,t)
        elif self.name=="SIR":
            return SIR_flux(u,t)
        elif self.name=="nonLinearOscillator":
            return nonLinearOscillator_flux(u,t)
        elif self.name=="nonLinearOscillatorDamped":
            return nonLinearOscillatorDamped_flux(u,t)
        elif self.name=="Robertson":
            return Robertson_flux(u,t)
        elif self.name=="lotka":
            return lotka_flux(u,t)
        elif self.name=="threeBodies":
            return threeBodies_flux(u,t)
        else:
            raise ValueError("Flux not defined for this problem")

    def jacobian(self,u,t=0):
        if self.name=="linear_scalar":
            return linear_scalar_jacobian(u,t,self.k_coef)
        elif self.name=="nonlinear_scalar":
            return nonlinear_scalar_jacobian(u,t,self.k_coef)
        elif self.name=="linear_system2":
            return linear_system2_jacobian(u,t)
        elif self.name=="linear_system3":
            return linear_system3_jacobian(u,t)
        elif self.name=="SIR":
            return SIR_jacobian(u,t)
        elif self.name=="Robertson":
            return Robertson_jacobian(u,t)
        elif self.name=="lotka":
            return lotka_jacobian(u,t)
        else:
            raise ValueError("Jacobian not defined for this problem")

    def exact(self,u,t):
        if self.name=="linear_scalar":
            return linear_scalar_exact_solution(u,t,self.k_coef)
        elif self.name=="nonlinear_scalar":
            return nonlinear_scalar_exact_solution(u,t,self.k_coef)
        elif self.name=="linear_system2":
            return linear_system2_exact_solution(u,t)
        elif self.name=="linear_system3":
            return linear_system3_exact_solution(u,t)
        elif self.name=="nonLinearOscillator":
            return nonLinearOscillator_exact_solution(u,t)
        elif self.name=="nonLinearOscillatorDamped":
            return nonLinearOscillatorDamped_exact_solution(u,t)
        else:
            raise ValueError("Exact solution not defined for this problem")

    def exact_solution_times(self,u0,tt):
        exact_solution=np.zeros((len(u0),len(tt)))
        for it, t in enumerate(tt):
            exact_solution[:,it]=self.exact(u0,t)
        return exact_solution

    def prod_dest(self,u,t=0):
        if self.name=="linear_system2":
            return linear_system2_production_destruction(u,t)
        if self.name=="nonlinear_system3":
            return nonlinear_system3_production_destruction(u,t)
        elif self.name=="Robertson":
            return Robertson_production_destruction(u,t)
        elif self.name=="SIR":
            return SIR_production_destruction(u,t)
        else:
            raise ValueError("Prod Dest not defined for this problem")


#!/usr/bin/env python3
import sys
from mpi4py import MPI
import numpy as np

np.random.seed(2017)

comm = MPI.COMM_WORLD
size = comm.Get_size()
rank = comm.Get_rank()

def inside_circle(total_count):

    hname = MPI.Get_processor_name()

    x = np.float32(np.random.uniform(size=total_count))
    y = np.float32(np.random.uniform(size=total_count))

    radii = np.sqrt(x*x + y*y)

    count = len(radii[np.where(radii<=1.0)])

    return count

def estimate_pi(n_samples):

    counts = inside_circle(n_samples)
    return (4.0 * sum(counts) / total_count)

if __name__=='__main__':

    n_samples = 10000
    if len(sys.argv) > 1:
        n_samples = int(sys.argv[1])

    if rank == 0:
        partitions = [ int(n_samples/size) for item in range(size)]
        counts = [ int(0) ] *size
    else:
        partitions = None
        counts = None

    partition_item = comm.scatter(partitions, root=0)
    count_item = comm.scatter(counts, root=0)

    count_item = inside_circle(partition_item)

    counts = comm.gather(count_item, root=0)
    if rank == 0:
        my_pi = 4.0 * sum(counts) / n_samples
        sizeof = np.dtype(np.float32).itemsize
        print("[     mpi version] required memory %.3f MB" % (n_samples*sizeof*3/(1024*1024)))
        print("[using %3i cores ] pi is %f from %i samples" % (size,my_pi,n_samples))


import numpy as np

# Create numpy arrays, list and change elements

a=np.array([1,2,3]) # create a 1D array
print('Dimensions of the array = ',a.ndim) # print the dimensions of the array
print('Shape of the array = ', a.shape) # print the shape of the array
a=np.array([ [1,2,3] ])
print('Dimensions of the array = ', a.ndim) # print the dimensions of the array
print('Shape of the array = ', a.shape) # print the shape of the array

b = np.array([[1,2,3],[4,5,6]])   # Create a rank 2 array
print('Shape of the array = ',b.shape)                     # Prints "(2, 3)"
print('Print select elements of b array')
print(b[0, 0], b[0, 1], b[1, 0])   # Prints "1 2 4"
print(b[0][0], b[0][1], b[0][1])   # Prints "1 2 4"
print('Modify array elements in location 0,2')
b[0,2]=999
print('New value in b[0,2] = ', b[0,2])  # [[  1   2   3]
 				         # [  4   5 999]]
print('New b array = ')
print(b)
print()
print('Create an array of zeros')
a = np.zeros((2,2))  # Create an array of all zeros
print(a)             # Prints "[[ 0.  0.]
                     #          [ 0.  0.]]"

print()
print('Create an array of ones')
b = np.ones((1,2))   # Create an array of all ones
print(b)             # Prints "[[ 1.  1.]]"
print()
print('Create an identity matrix')
d = np.eye(2)        # Create a 2x2 identity matrix
print(d)              # Prints "[[ 1.  0.]
                     #          [ 0.  1.]]"
print()
print('Create a random 2x2 array')
e = np.random.random((2,2)) # Create an array filled with random values
print(e)                     # Might print "[[ 0.91940167  0.08143941]
                            #               [ 0.68744134  0.87236687]]"
print()
print('Create a 1D random integer array between 10-100')
e = np.random.random_integers(10,100,10) # print 10 random integers between 10 to 100
print(e)
print()
print('Create a 10x10 random integer array between 10-100')
e = np.random.random_integers(10,100,(10,10)) # print 100 random integers and place them in 10x10 array
print(e)
print()
wait = input("PRESS ENTER TO CONTINUE.")

#Slicing: Numpy arrays can be sliced. Since arrays may be multidimensional, you must specify a slice for each dimension of the array:

print('Create a 3x4 array')
a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])
print(a)
# [[ 1  2  3  4]
#  [ 5  6  7  8]
#  [ 9 10 11 12]]
print()
print('Pull out subarray first 2 rows and columns 1-2')
# Use slicing to pull out the subarray consisting of the first 2 rows
# and columns 1 and 2; b is the following array of shape (2, 2):
b = a[:2, 1:3] # [[2 3]
               #  [6 7]]
print(b)
print()

# Modifying a slice of an array modifies the original array
print('Modify a slice and compare to the original array')
print('Value of element 0,1 of a is',a[0, 1])   # Prints "2"
print('Modify 0,0 of array b to value 77')
b[0, 0] = 77    # b[0, 0] is the same piece of data as a[0, 1]
print('Value of element 0,1 of a is now ',a[0, 1])   # Prints "77"
print()

# Create the following rank 2 array with shape (3, 4)
# [[ 1  2  3  4]
#  [ 5  6  7  8]
#  [ 9 10 11 12]]
a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])
print()

wait = input("PRESS ENTER TO CONTINUE.")

# Two ways of accessing the data in the middle row of the array.
# Mixing integer indexing with slices yields an array of lower rank,
# while using only slices yields an array of the same rank as the
# original array:
row_r1 = a[1, :]    # Rank 1 view of the second row of a
row_r2 = a[1:2, :]  # Rank 2 view of the second row of a
print('Print extracted row, shape and dims = ',row_r1, row_r1.shape,row_r1.ndim)  # Prints "[5 6 7 8] (4,) 1"
print('Print extracted row, shape and dims = ',row_r2, row_r2.shape,row_r2.ndim)  # Prints "[[5 6 7 8]] (1, 4) 2"

# We can make the same distinction when accessing columns of an array:
col_r1 = a[:, 1]
col_r2 = a[:, 1:2]
print('Print extracted column = ') # Prints "[ 2  6 10]"
print(col_r1)
print('Print shape and dims of extracted column =', col_r1.shape,col_r1.ndim)  # Prints "(3,) 1"
print('Print extracted column = ') # Prints "[[ 2]
                                   #          [ 6]
                                   #          [10]] (3, 1)"
print(col_r2)
print('Print shape and dims of extracted column = ', col_r2.shape,col_r1.ndim)  # Print "(3,1) 2"

wait = input("PRESS ENTER TO CONTINUE.")

#Array indexing:

print('Create an 4x3 integer array')
a = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
print('Shape of the array is =', a.shape)
print()
# Create an array of indices
print('Create 1D index array')
b = np.array([0, 2, 0, 1])
print(b)
print()

# Select one element from each row of a using the indices in b
print('Create a range of indices from 0-3 using arange = ', np.arange(4))
print('Use this range to reference indices of the a array')
print(a[np.arange(4), b])  # Prints "[ 1  6  7 11]"

# Mutate one element from each row of a using the indices in b
print('Modify the indexed elements by adding 10')
a[np.arange(4), b] += 10

print('Modified array then becomes = ',a)  # prints "array([[11,  2,  3],
         #                [ 4,  5, 16],
         #                [17,  8,  9],
         #                [10, 21, 12]])

wait = input("PRESS ENTER TO CONTINUE.")

#Reference elements by boolean masks
print('Create an 3x2 numpy array')
a = np.array([[1,2], [3, 4], [5, 6]])

print('Apply a logical mask for all elements that larger than 2')
bool_idx = (a > 2)  # Find the elements of a that are bigger than 2;
                    # this returns a numpy array of Booleans of the same
                    # shape as a, where each slot of bool_idx tells
                    # whether that element of a is > 2.

print(bool_idx)      # Prints "[[False False]
                    #          [ True  True]
                    #          [ True  True]]"

# We use boolean array indexing to construct a rank 1 array
# consisting of the elements of a corresponding to the True values
# of bool_idx
print('Extracted array elements where boolean condition is true = ',a[bool_idx])  # Prints "[3 4 5 6]"

# We can do all of the above in a single concise statement:
print('The boolean condition can be an input to the array')
print(a[a > 2])     # Prints "[3 4 5 6]"

wait = input("PRESS ENTER TO CONTINUE.")

#Some arithmetic
print('Create two 2x2 arrays')
x = np.array([[1,2],[3,4]], dtype=np.float64)
y = np.array([[5,6],[7,8]], dtype=np.float64)
print()
# Elementwise sum; both produce the array
# [[ 6.0  8.0]
#  [10.0 12.0]]
#print x + y
print('Add them')
print(np.add(x, y))
print()
# Elementwise difference; both produce the array
# [[-4.0 -4.0]
#  [-4.0 -4.0]]
#print x - y
print('Subtracted them')
print(np.subtract(x, y))
print()

# Elementwise product; both produce the array
# [[ 5.0 12.0]
#  [21.0 32.0]]
#print x * y
print('Multiply by elements')
print(np.multiply(x, y))
print()

# Elementwise division; both produce the array
# [[ 0.2         0.33333333]
#  [ 0.42857143  0.5       ]]
#print x / y
print('Divide by elements')
print(np.divide(x, y))

# Elementwise square root; produces the array
# [[ 1.          1.41421356]
#  [ 1.73205081  2.        ]]
print('Square root')
print(np.sqrt(x))

x = np.array([[1,2],[3,4]])
y = np.array([[5,6],[7,8]])

print()
print('Create two 1D arrays and treat them as vectors')
v = np.array([9,10])
print(v)
w = np.array([11, 12])
print(w)
print()

# Inner product of vectors; both produce 219
#print v.dot(w)
print('Inner product = ',np.dot(v, w))

# Matrix / vector product; both produce the rank 1 array [29 67]
#print x.dot(v)
print('Matrix * vector product =',np.dot(x, v))

# Matrix / matrix product; both produce the rank 2 array
# [[19 22]
#  [43 50]]
#print(x.dot(y))
print('Matrix * Matrix product')
print(np.dot(x, y))

wait = input("PRESS ENTER TO CONTINUE.")

print('Create a 2x2 array')
x = np.array([[1,2],[3,4]])
print(x)
print()
print('Sum of all elements = ',np.sum(x))  # Compute sum of all elements; prints "10"
print('Sum of all columns =',np.sum(x, axis=0))  # Compute sum of each column; prints "[4 6]"
print('Sum of all rows = ',np.sum(x, axis=1))  # Compute sum of each row; prints "[3 7]"

x = np.array([[1,2], [3,4]])
#print x    # Prints "[[1 2]
           #          [3 4]]"
print('Transpose Matrix = ',x.T)  # Prints "[[1 3]
           #          [2 4]]"
print('Transpose Matrix (alt)= ',np.transpose(x)) # transpose matrix x using transpose

wait = input("PRESS ENTER TO CONTINUE.")

# We will add the vector v to each row of the matrix x,
# storing the result in the matrix y
print('Create a 4x3 array')
x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
print(x)
print()
print('Create a vector with the same number of row elements')
v = np.array([1, 0, 1])
print(v)
print()
print('Create an empty matrix with the same shape as x')
y = np.empty_like(x)   # Create an empty matrix with the same shape as x
print(y)
print()

# Add the vector v to each row of the matrix x with an explicit loop
print('Add the vector to each extracted row i x[i,:]')
for i in range(4):
    y[i, :] = x[i, :] + v

# Now y is the following
# [[ 2  2  4]
#  [ 5  5  7]
#  [ 8  8 10]
#  [11 11 13]]
print('Modified array')
print(y)
print()

wait = input("PRESS ENTER TO CONTINUE.")

print('Add vector to all matrix rows using tile')
# We will add the vector v to each row of the matrix x,
# storing the result in the matrix y
x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
print('1D vector - same number of elements as the row elements of the target array')
v = np.array([1, 0, 1])
print(v)
print('tile the vector - replicate the vector 4 times and stack it to form an array')
vv = np.tile(v, (4, 1))  # Stack 4 copies of v on top of each other
print(vv)                 # Prints "[[1 0 1]
                         #          [1 0 1]
                         #          [1 0 1]
                         #          [1 0 1]]"
print('tiled vector can directly added to matrix')
y = x + vv  # Add x and vv elementwise
print(y)  # Prints "[[ 2  2  4
         #          [ 5  5  7]
         #          [ 8  8 10]
         #          [11 11 13]]"

wait = input("PRESS ENTER TO CONTINUE.")

print('Compute outer product of vectors')
print('Create vector 1x3 and vector 1x2')
v = np.array([1,2,3])  # v has shape (3,)
w = np.array([4,5])    # w has shape (2,)
print(v)
print(w)
print()

# To compute an outer product, we first reshape v to be a column
# vector of shape (3, 1); we can then broadcast it against w to yield
# an output of shape (3, 2), which is the outer product of v and w:
# [[ 4  5]
#  [ 8 10]
#  [12 15]]
print('Compute outer/tensor product v^T.w')
print('reshape vector v = ')
print(np.reshape(v,(3,1)))
print('Directly multiply 3x1 to 1x2 vectors to yield 3x2 matrix')
print(np.reshape(v, (3, 1)) * w)

wait = input("PRESS ENTER TO CONTINUE.")

print('Add a vector to each column of a matrix')
print('Create a 2x3 matrix')
x = np.array([[1,2,3], [4,5,6]])
print(x)
print()
print('Create a 1x2 vector')
w = np.array([4,5])
print(w)
print()
# x has shape (2, 3) and w has shape (2,).
# If we transpose x then it has shape (3, 2) and can be broadcast
# against w to yield a result of shape (3, 2); transposing this result
# yields the final result of shape (2, 3) which is the matrix x with
# the vector w added to each column. Gives the following matrix:
# [[ 5  6  7]
#  [ 9 10 11]]
print('Transpose x')
print(x.T)
print()
print('We can add the 1x2 vector')
print(x.T+w)
print()
print('We can transpose the 3x2 matrix back to 2x3')
print((x.T + w).T)
print()


"""
Common test functions for optimizers.

Also see: https://en.wikipedia.org/wiki/Test_functions_for_optimization
"""

def rosenbrock(x, y):
    """
    Rosenbrock function. Minimum: f(1, 1) = 0.

    https://en.wikipedia.org/wiki/Rosenbrock_function
    """
    return (1 - x) ** 2 + 100 * (y - x ** 2) ** 2

rosenbrock.errordef = 1

def rosenbrock_grad(x, y):
    """Gradient of Rosenbrock function."""
    return (-400 * x * (-(x ** 2) + y) + 2 * x - 2, -200 * x ** 2 + 200 * y)

def ackley(x, y):
    """
    Ackley function. Minimum: f(0, 0) = 0.

    https://en.wikipedia.org/wiki/Ackley_function
    """
    from math import sqrt, exp, cos, pi, e

    term1 = -20 * exp(-0.2 * sqrt(0.5 * (x ** 2 + y ** 2)))
    term2 = -exp(0.5 * (cos(2 * pi * x) + cos(2 * pi * y)))
    return term1 + term2 + 20 + e

ackley.errordef = 1

def beale(x, y):
    """
    Beale function. Minimum: f(3, 0.5) = 0.

    https://en.wikipedia.org/wiki/Test_functions_for_optimization
    """
    term1 = 1.5 - x + x * y
    term2 = 2.25 - x + x * y ** 2
    term3 = 2.625 - x + x * y ** 3
    return term1 * term1 + term2 * term2 + term3 * term3

beale.errordef = 1

def matyas(x, y):
    """
    Matyas function. Minimum: f(0, 0) = 0.

    https://en.wikipedia.org/wiki/Test_functions_for_optimization
    """
    return 0.26 * (x ** 2 + y ** 2) - 0.48 * x * y

matyas.errordef = 1

def sphere_np(x):
    """
    Sphere function for variable number of arguments. Minimum: f(0, ..., 0) = 0.

    https://en.wikipedia.org/wiki/Test_functions_for_optimization
    """
    import numpy as np

    return np.sum(x ** 2)

sphere_np.errordef = 1


import numpy as np

print "Executing: 08_Standardizing_Data.py"

# First 20 countries with employment data
countries = np.array([
    'Afghanistan', 'Albania', 'Algeria', 'Angola', 'Argentina',
    'Armenia', 'Australia', 'Austria', 'Azerbaijan', 'Bahamas',
    'Bahrain', 'Bangladesh', 'Barbados', 'Belarus', 'Belgium',
    'Belize', 'Benin', 'Bhutan', 'Bolivia',
    'Bosnia and Herzegovina'
])

# Employment data in 2007 for those 20 countries
employment = np.array([
    55.70000076,  51.40000153,  50.5       ,  75.69999695,
    58.40000153,  40.09999847,  61.5       ,  57.09999847,
    60.90000153,  66.59999847,  60.40000153,  68.09999847,
    66.90000153,  53.40000153,  48.59999847,  56.79999924,
    71.59999847,  58.40000153,  70.40000153,  41.20000076
])

# Change this country name to change what country will be printed when you
# click "Test Run". Your function will be called to determine the standardized
# score for this country for each of the given 5 Gapminder variables in 2007.
# The possible country names are available in the Downloadables section.

country_name = 'United States'

def standardize_data(values):
    '''
    Fill in this function to return a standardized version of the given values,
    which will be in a NumPy array. Each value should be translated into the
    number of standard deviations that value is away from the mean of the data.
    (A positive number indicates a value higher than the mean, and a negative
    number indicates a value lower than the mean.)
    '''
    standardized_values = (values - values.mean()) / values.std()
    return standardized_values


# Question 1: Create a 4X2 integer array and Prints its attributes
# Note: The element must be a type of unsigned int16. And print the following Attributes: –
#
# The shape of an array.
# Array dimensions.
# The Length of each element of the array in bytes.
import numpy as np

Array = np.empty([4, 2], dtype=np.uint16)
print("Array Shape is: ", Array.shape)
print("Array dimensions are ", Array.ndim)
print("Length of each element of array in bytes is ", Array.itemsize)
# Question 2: Create a 5X2 integer array from a range between 100 to 200 such that the difference between each element is 10
import numpy as  np

a = np.arange(100, 200, 10)
b = a.reshape(5, 2)
print(b)
# Question 3: Following is the provided numPy array. return array of items in the third column from all rows
import numpy as np

sampleArray = np.array([[11, 22, 33], [44, 55, 66], [77, 88, 99]])

sampleArray = numpy.array([[11, 22, 33], [44, 55, 66], [77, 88, 99]])

newArray = sampleArray[..., 1]
print(newArray)
# Question 4: Following is the given numpy array return array of odd rows and even columns
import numpy

sampleArray = numpy.array([[3, 6, 9, 12], [15, 18, 21, 24],
                           [27, 30, 33, 36], [39, 42, 45, 48], [51, 54, 57, 60]])
print("Printing Input Array")
print(sampleArray)

print("\n Printing array of odd rows and even columns")
newArray = sampleArray[::2, 1::2]
print(newArray)
# Question 5: Add the following two NumPy arrays and Modify a result array by calculating the square of each element
# import numpy
#
# arrayOne = numpy.array([[5, 6, 9], [21 ,18, 27]])
# arrayTwo = numpy.array([[15 ,33, 24], [4 ,7, 1]])
import numpy

arrayOne = numpy.array([[5, 6, 9], [21, 18, 27]])
arrayTwo = numpy.array([[15, 33, 24], [4, 7, 1]])

resultArray = arrayOne + arrayTwo
print("addition of two arrays is \n")
print(resultArray)

for num in numpy.nditer(resultArray, op_flags=['readwrite']):
    num[...] = num * num
print("\nResult array after calculating the square root of all elements\n")
print(resultArray)
# Question 6: Split the array into four equal-sized sub-arrays
import numpy

print("Creating 8X3 array using numpy.arange")
sampleArray = numpy.arange(10, 34, 1)
sampleArray = sampleArray.reshape(8, 3)
print(sampleArray)

print("\nDividing 8X3 array into 4 sub array\n")
subArrays = numpy.split(sampleArray, 4)
print(subArrays)
# Question 7; Sort following NumPy array
# 7.1- by the second row and
# 7.2-by the second column
import numpy

print("Printing Original array")
sampleArray = numpy.array([[34, 43, 73], [82, 22, 12], [53, 94, 66]])
print(sampleArray)

sortArrayByRow = sampleArray[:, sampleArray[1, :].argsort()]
print("Sorting Original array by secoond row")
print(sortArrayByRow)

print("Sorting Original array by secoond column")
sortArrayByColumn = sampleArray[sampleArray[:, 1].argsort()]
print(sortArrayByColumn)
# Question 8: Following is the 2-D array. Print max from axis 0 and min from axis 1
# import numpy
# sampleArray = numpy.array([[34,43,73],[82,22,12],[53,94,66]])
import numpy

print("Printing Original array")
sampleArray = numpy.array([[34, 43, 73], [82, 22, 12], [53, 94, 66]])
print(sampleArray)

minOfAxisOne = numpy.amin(sampleArray, 1)
print("Printing amin Of Axis 1")
print(minOfAxisOne)

maxOfAxisOne = numpy.amax(sampleArray, 0)
print("Printing amax Of Axis 0")
print(maxOfAxisOne)
# Question 9: Following is the input NumPy array delete column two and insert following new column in its place.
# import numpy
# sampleArray = numpy.array([[34,43,73],[82,22,12],[53,94,66]])
#
# newColumn = numpy.array([[10,10,10]])
import numpy

print("Printing Original array")
sampleArray = numpy.array([[34, 43, 73], [82, 22, 12], [53, 94, 66]])
print(sampleArray)

print("Array after deleting column 2 on axis 1")
sampleArray = numpy.delete(sampleArray, 1, axis=1)
print(sampleArray)

arr = numpy.array([[10, 10, 10]])

print("Array after inserting column 2 on axis 1")
sampleArray = numpy.insert(sampleArray, 1, arr, axis=1)
print(sampleArray)
# Question 10: Create a two 2-D array and Plot it using matplotlib
import numpy

print("Printing Original array")
sampleArray = numpy.array([[34, 43, 73], [82, 22, 12], [53, 94, 66]])
print(sampleArray)

print("Array after deleting column 2 on axis 1")
sampleArray = numpy.delete(sampleArray, 1, axis=1)
print(sampleArray)

arr = numpy.array([[10, 10, 10]])

print("Array after inserting column 2 on axis 1")
sampleArray = numpy.insert(sampleArray, 1, arr, axis=1)
print(sampleArray)


import numpy as np
import torch

"""

Exercise 1.1: Diagonal Gaussian Likelihood

Write a function that takes in PyTorch Tensors for the means and
log stds of a batch of diagonal Gaussian distributions, along with a
PyTorch Tensor for (previously-generated) samples from those
distributions, and returns a Tensor containing the log
likelihoods of those samples.

"""

def gaussian_likelihood(x, mu, log_std):
    """
    Args:
        x: Tensor with shape [batch, dim]
        mu: Tensor with shape [batch, dim]
        log_std: Tensor with shape [batch, dim] or [dim]

    Returns:
        Tensor with shape [batch]
    """
    m = torch.distributions.normal.Normal(mu, torch.exp(log_std))
    return m.log_prob(x).sum(axis=-1)

if __name__ == "__main__":
    """
    Run this file to verify your solution.
    """
    from spinup.exercises.common import print_result
    from spinup.exercises.pytorch.problem_set_1_solutions import (
        exercise1_1_soln,
    )

    batch_size = 32
    dim = 10

    x = torch.rand(batch_size, dim)
    mu = torch.rand(batch_size, dim)
    log_std = torch.rand(dim)

    your_gaussian_likelihood = gaussian_likelihood(x, mu, log_std)
    true_gaussian_likelihood = exercise1_1_soln.gaussian_likelihood(
        x, mu, log_std
    )

    your_result = your_gaussian_likelihood.detach().numpy()
    true_result = true_gaussian_likelihood.detach().numpy()

    correct = np.allclose(your_result, true_result)
    print_result(correct)


import numpy as np
from os.path import exists
from matplotlib import pyplot as plt
from sklearn.manifold import TSNE

def t_sne(n_components=2):
    img = np.load(r'../data/sampled_image.npy')
    img = img.reshape((-1, img.shape[1]*img.shape[2]))
    x = TSNE(n_components=n_components).fit_transform(img)
    np.save('tsne.npy', x)

def kde(x, y, X, Y, h1, h2, kernel1, kernel2):
    kx = kernel1((x-X)/h1)
    ky = kernel2((y-Y)/h2)
    p = 1/(len(X)*h1*h2)*np.sum(kx*ky)
    return p

def gaussian(x):
    return 1/(2*np.pi)**0.5*np.exp(-x*x/2)

def epanechnikov(x):
    x_ = 3/4*(1-x*x)
    x_[(x > 1) | (x < -1)] = 0
    return x_

def densitymap(data, h1, h2, kernel1, kernel2, n=1000):
    x = np.linspace(min(data[:, 0]), max(data[:, 0]), n)
    y = np.linspace(min(data[:, 1]), max(data[:, 1]), n)
    contour = np.zeros((n, n))
    if kernel1 == 'gaussian':
        func1 = gaussian
    elif kernel1 == 'epanechnikov':
        func1 = epanechnikov
    if kernel2 == 'gaussian':
        func2 = gaussian
    elif kernel2 == 'epanechnikov':
        func2 = epanechnikov
    for i in range(n):
        for j in range(n):
            contour[i][j] = kde(x[i], y[j], data[:, 0], data[:, 1], h1, h2, func1, func2)
    X, Y = np.meshgrid(x, y)
    plt.figure(figsize=(12, 12))
    a = plt.contourf(X, Y, contour, cmap='Reds', alpha=1)
    plt.contour(X, Y, contour)
    plt.colorbar(a)
    plt.title('density map-%s-%s-%.1f-%.1f' % (kernel1, kernel2, h1, h2))
    plt.savefig('density map-%s-%s-%.1f-%.1f.png' % (kernel1, kernel2, h1, h2))
    plt.close()

if __name__ == "__main__":
    if not exists('tsne.npy'):
        t_sne()
    data = np.load('tsne.npy')
    label = np.load('../data/sampled_label.npy')
    f = plt.figure(figsize=(12, 12))
    for i in range(10):
        plt.scatter(data[label == i, 0], data[label == i, 1], label='%i' % i)
    plt.legend(loc='best')
    plt.title('T-SNE decomposition')
    plt.savefig('scatter.png')
    plt.close()
    densitymap(data, 3, 3, 'epanechnikov', 'epanechnikov')
    densitymap(data, 2, 3, 'epanechnikov', 'epanechnikov')
    densitymap(data, 2, 2, 'epanechnikov', 'epanechnikov')
    densitymap(data, 2, 2, 'gaussian', 'gaussian')
    densitymap(data, 1.5, 1.5, 'gaussian', 'gaussian')
    densitymap(data, 5, 5, 'gaussian', 'gaussian')
    densitymap(data, 3, 5, 'gaussian', 'epanechnikov')
    densitymap(data, 1.5, 3, 'gaussian', 'epanechnikov')


import numpy as np

def bias(obs, model) -> float:
    "Bias (model - obs)"
    return np.mean(model - obs)

def mean_absolute_error(
    obs: np.ndarray, model: np.ndarray, weights: np.ndarray = None
) -> float:
    """Mean Absolute Error (MAE)"""

    error = np.average(np.abs(model - obs), weights=weights)
    return error

def rmse(
    obs: np.ndarray,
    model: np.ndarray,
    weights: np.ndarray = None,
    unbiased: bool = False,
) -> float:
    return root_mean_squared_error(obs, model, weights, unbiased)

def root_mean_squared_error(
    obs: np.ndarray,
    model: np.ndarray,
    weights: np.ndarray = None,
    unbiased: bool = False,
) -> float:
    """Root Mean Squared Error (RMSE)"""
    residual = obs - model
    if unbiased:
        residual = residual - residual.mean()
    error = np.sqrt(np.average(residual ** 2, weights=weights))

    return error

def nash_sutcliffe_efficiency(obs, model) -> float:
    """Nash-Sutcliffe Efficiency (NSE)"""
    error = 1 - (np.sum((obs - model) ** 2) / np.sum((model - np.mean(model)) ** 2))

    return error

def corr_coef(obs, model) -> float:

    return np.corrcoef(obs, model)[0, 1]

def scatter_index(obs, model) -> float:

    return np.sqrt(
        np.sum(((model - model.mean()) - (obs - obs.mean())) ** 2) / np.sum(obs ** 2)
    )

def r2(obs, model) -> float:
    """Coefficient of determination"""

    residual = model - obs

    SSt = np.sum(obs ** 2)
    SSr = np.sum(residual ** 2)

    return 1 - SSr / SSt


import matplotlib.pyplot as plt
import numpy as np

from pydmd import DMD

# We create the input data by summing two different functions
# $f_1(x,t) = \text{sech}(x+3)\exp(i2.3t)$
# $f_2(x,t) = 2\text{sech}(x)\tanh(x)\exp(i2.8t)$.

def f1(x,t):
    return 1./np.cosh(x+3)*np.exp(2.3j*t)

def f2(x,t):
    return 2./np.cosh(x)*np.tanh(x)*np.exp(2.8j*t)

x = np.linspace(-5, 5, 65)
t = np.linspace(0, 4*np.pi, 129)

xgrid, tgrid = np.meshgrid(x, t)

X1 = f1(xgrid, tgrid)
X2 = f2(xgrid, tgrid)
X = X1 + X2

# The plots below represent these functions and the dataset.

titles = ['$f_1(x,t)$', '$f_2(x,t)$', '$f$']
data = [X1, X2, X]

fig = plt.figure(figsize=(17, 6))
for n, title, d in zip(range(131, 134), titles, data):
    plt.subplot(n)
    plt.pcolor(xgrid, tgrid, d.real)
    plt.title(title)
plt.colorbar()
plt.show()

# Now we have the temporal snapshots in the input matrix rows: we can easily create a new DMD instance and exploit it in order to compute the decomposition on the data. Since the snapshots must be arranged by columns, in this case we need to transpose the matrix.

dmd = DMD(svd_rank=2)
dmd.fit(X.T)

# The `dmd` object contains the principal information about the decomposition:
# - the attribute `modes` is a 2D numpy array where the columns are the low-rank structures individuated;
# - the attribute `dynamics` is a 2D numpy array where the rows refer to the time evolution of each mode;
# - the attribute `eigs` refers to the eigenvalues of the low dimensional operator;
# - the attribute `reconstructed_data` refers to the approximated system evolution.
#
# Moreover, some helpful methods for the graphical representation are provided.

# Thanks to the eigenvalues, we can check if the modes are stable or not: if an eigenvalue is on the unit circle, the corresponding mode will be stable; while if an eigenvalue is inside or outside the unit circle, the mode will converge or diverge, respectively. From the following plot, we can note that the two modes are stable.

for eig in dmd.eigs:
    print('Eigenvalue {}: distance from unit circle {}'.format(eig, np.abs(np.sqrt(eig.imag**2+eig.real**2) - 1)))

dmd.plot_eigs(show_axes=True, show_unit_circle=True)

# We can plot the modes and the dynamics:

for mode in dmd.modes.T:
    plt.plot(x, mode.real)
    plt.title('Modes')
plt.show()

for dynamic in dmd.dynamics:
    plt.plot(t, dynamic.real)
    plt.title('Dynamics')
plt.show()

# Finally, we can reconstruct the original dataset as the product of modes and dynamics. We plot the evolution of each mode to emphasize their similarity with the input functions and we plot the reconstructed data.

fig = plt.figure(figsize=(17,6))

for n, mode, dynamic in zip(range(131, 133), dmd.modes.T, dmd.dynamics):
    plt.subplot(n)
    plt.pcolor(xgrid, tgrid, (mode.reshape(-1, 1).dot(dynamic.reshape(1, -1))).real.T)

plt.subplot(133)
plt.pcolor(xgrid, tgrid, dmd.reconstructed_data.T.real)
plt.colorbar()

plt.show()

# We can also plot the absolute error between the approximated data and the original one.

plt.pcolor(xgrid, tgrid, (X-dmd.reconstructed_data.T).real)
fig = plt.colorbar()

# The reconstructed system looks almost equal to the original one: the dynamic mode decomposition made possible the identification of the meaningful structures and the complete reconstruction of the system using only the collected snapshots.


# -*- coding: utf-8 -*-
"""
Created on Fri Mar  1 17:58:33 2019

@author: Ham

HackerRanch Challenge: Min and Max

min

The tool min returns the minimum value along a given axis.

import numpy

my_array = numpy.array([[2, 5],
                        [3, 7],
                        [1, 3],
                        [4, 0]])

print numpy.min(my_array, axis = 0)         #Output : [1 0]
print numpy.min(my_array, axis = 1)         #Output : [2 3 1 0]
print numpy.min(my_array, axis = None)      #Output : 0
print numpy.min(my_array)                   #Output : 0
By default, the axis value is None.
Therefore, it finds the minimum over all the dimensions of the input array.

max

The tool max returns the maximum value along a given axis.

import numpy

my_array = numpy.array([[2, 5],
                        [3, 7],
                        [1, 3],
                        [4, 0]])

print numpy.max(my_array, axis = 0)         #Output : [4 7]
print numpy.max(my_array, axis = 1)         #Output : [5 7 3 4]
print numpy.max(my_array, axis = None)      #Output : 7
print numpy.max(my_array)                   #Output : 7
By default, the axis value is None.
Therefore, it finds the maximum over all the dimensions of the input array.

Task

You are given a 2-D array with dimensions NxM.
Your task is to perform the min function over axis 1
and then find the max of that.

Input Format

The first line of input contains the space separated values of N and M.
The next N lines contains M space separated integers.

Output Format

Compute the min along axis 1 and then print the max of that result.

Sample Input

4 2
2 5
3 7
1 3
4 0

Sample Output

3

Explanation

The min along axis 1 = [2 3 1 0]
The max of [2 3 1 0] = 3

"""

import numpy

# ignoring 2nd int of 1st line, M
a = [list(map(int, input().strip().split()))
     for _ in range(int(input().strip().split()[0]))]
print(numpy.max(numpy.min(a, axis=1)))


import matplotlib.pyplot as plt
import matplotlib.image as mpimg
from matplotlib import colors
# from numba import jlt
import cv2
import numpy as np

MAX_ITERATIONS = 200
HEIGHT = 600
WIDTH = int(HEIGHT * 1.5)

def map(number, l_ini, r_ini, l_final, r_final):
	fraction = (number - l_ini) / (r_ini - l_ini)
	value = fraction * (r_final - l_final) + l_final
	return value

# @jlt
def plot_Mandelbrot_Set(image, min_x, max_x, min_y, max_y):
	for i in range(WIDTH):
		x = map(i, 0, WIDTH, min_x, max_x)
		for j in range(HEIGHT):
			z = 0 + 0j
			y = map(j, 0, HEIGHT, min_y, max_y)
			c = complex(x, y)
			curr_iteration = 0

			while abs(z) < 2 and curr_iteration < MAX_ITERATIONS:
				z = z*z + c
				curr_iteration += 1

			# if curr_iteration == MAX_ITERATIONS:
			# 	image[j][i] = 0
			# else:
			# 	image[j][i] = 255
			image[j][i] = curr_iteration

		if i % 100 == 0:
			print("Calculating Column {}".format(i))
	return image

def plot_set(image, cmap='jet', gamma=0.3):
	norm = colors.PowerNorm(gamma)
	plt.imshow(image, cmap=cmap, norm=norm)
	plt.show()

mandelbrotSet = [[0 for _ in range(WIDTH)] for _ in range(HEIGHT)]
mandelbrotSet = plot_Mandelbrot_Set(mandelbrotSet, -2.5, 1, -1, 1)

plot_set(mandelbrotSet,cmap='hot')

# cv2.imshow("set", np.array(mandelbrotSet)/255.0)
# plt.imshow(mandelbrotSet)
# plt.show()


from numpy import *
from matplotlib.pyplot import *

def solver(I, a, T, dt, theta):
    """Solve u'=-a*u, u(0)=I, for t in (0,T] with steps of dt."""
    dt = float(dt)            # avoid integer division
    Nt = int(round(T/dt))     # no of time intervals
    T = Nt*dt                 # adjust T to fit time step dt
    u = zeros(Nt+1)           # array of u[n] values
    t = linspace(0, T, Nt+1)  # time mesh

    if theta == 0:
        a = a*(1 - 0.5*a*dt)
    elif theta == 1:
        a = a*(1 + 0.5*a*dt)
    else:
        a = a*(1 - 1./12*a**2*dt**2)

    u[0] = I                  # assign initial condition
    for n in range(0, Nt):    # n=0,1,...,Nt-1
        u[n+1] = (1 - (1-theta)*a*dt)/(1 + theta*dt*a)*u[n]
    return u, t

def exact_solution(t, I, a):
    return I*exp(-a*t)

def explore(I, a, T, dt, theta=0.5, makeplot=True):
    """
    Run a case with the solver, compute error measure,
    and plot the numerical and exact solutions (if makeplot=True).
    """
    u, t = solver(I, a, T, dt, theta)  # Numerical solution
    u_e = exact_solution(t, I, a)
    e = u_e - u
    E = sqrt(dt*sum(e**2))
    if makeplot:
        figure()                         # create new plot
        t_e = linspace(0, T, 1001)       # very fine mesh for u_e
        u_e = exact_solution(t_e, I, a)
        plot(t,   u,   'r--o')           # red dashes w/circles
        plot(t_e, u_e, 'b-')             # blue line for u_e
        legend(['numerical', 'exact'])
        xlabel('t')
        ylabel('u')
        title('Method: theta-rule, theta=%g, dt=%g' % (theta, dt))
        theta2name = {0: 'FE', 1: 'BE', 0.5: 'CN'}
        savefig('%s_%g.png' % (theta2name[theta], dt))
        show()
    return E

def define_command_line_options():
    import argparse
    parser = argparse.ArgumentParser()
    parser.add_argument('--I', '--initial_condition', type=float,
                        default=1.0, help='initial condition, u(0)',
                        metavar='I')
    parser.add_argument('--a', type=float,
                        default=1.0, help='coefficient in ODE',
                        metavar='a')
    parser.add_argument('--T', '--stop_time', type=float,
                        default=1.0, help='end time of simulation',
                        metavar='T')
    parser.add_argument('--makeplot', action='store_true',
                        help='display plot or not')
    parser.add_argument('--dt', '--time_step_values', type=float,
                        default=[1.0], help='time step values',
                        metavar='dt', nargs='+', dest='dt_values')
    return parser

def read_command_line():
    parser = define_command_line_options()
    args = parser.parse_args()
    print 'I={}, a={}, T={}, makeplot={}, dt_values={}'.format(
        args.I, args.a, args.T, args.makeplot, args.dt_values)
    return args.I, args.a, args.T, args.makeplot, args.dt_values

from math import log

def main():
    I, a, T, makeplot, dt_values = read_command_line()
    r = {}  # estimated convergence rates
    for theta in 0, 0.5, 1:
        E_values = []
        for dt in dt_values:
            E = explore(I, a, T, dt, theta, makeplot=False)
            E_values.append(E)

        # Compute convergence rates
        m = len(dt_values)
        r[theta] = [log(E_values[i-1]/E_values[i])/
                    log(dt_values[i-1]/dt_values[i])
                    for i in range(1, m, 1)]

    for theta in r:
        print '\nPairwise convergence rates for theta=%g:' % theta
        print ' '.join(['%.2f' % r_ for r_ in r[theta]])
    return r

def verify_convergence_rate():
    r = main()
    tol = 0.1
    expected_rates = {0: 1, 1: 1, 0.5: 2}
    for theta in r:
        r_final = r[theta][-1]
        diff = abs(expected_rates[theta] - r_final)
        if diff > tol:
            return False
    return True  # all tests passed

# main program
main()


# coding: utf-8

# # Function hadamardmatrix

# ## Synopse
# Kernel matrix for the Hadamard Transform.
#
#    - **A = hadamardmatrix(N)**
#        - Output:
#            - **A**: Image.
#        - Input:
#            - **N**: Double.

# ## Function code

# In[5]:

import numpy as np

def hadamardmatrix(N):

    def bitsum(x):
        s = 0 * x
        while x.any():
            s += x & 1
            x >>= 1
        return s

    n = np.floor(np.log(N)/np.log(2))

    if 2**n != N:
        raise Exception('error: size {0} is not multiple of power of 2'.format(N))

    u, x = np.meshgrid(range(N), range(N))

    A = ((-1)**(bitsum(x & u)))/np.sqrt(N)
    return A

# In[1]:

testing = (__name__ == "__main__")

if testing:
    get_ipython().system(' jupyter nbconvert --to python hadamardmatrix.ipynb')
    import numpy as np
    import sys,os
    import matplotlib.image as mpimg
    ea979path = os.path.abspath('../../')
    if ea979path not in sys.path:
        sys.path.append(ea979path)
    import ea979.src as ia

# ## Examples
#
# ### Example 1

# In[2]:

if testing:
    A = ia.hadamardmatrix(128)
    ia.adshow(ia.normalize(A, [0, 255]))

# ### Example 2

# In[4]:

if testing:
    A = ia.hadamardmatrix(4)
    print(A)
    print(np.dot(A, np.transpose(A)))

# ## Measuring time:

# In[5]:

if testing:
    print('Computational time is:')
    get_ipython().magic('timeit ia.hadamardmatrix(128)')

# In[ ]:


# util.py

from math import floor, log, sqrt
import numpy
from numpy import dot, eye

EPS = 1.e-4 # tolerance for floating-point comparison

def is_unitary(A):
    """Indicates whether or not the matrix A is unitary."""
    return numpy.max(abs(dot(A, A.conj().T) - eye(A.shape[0]))) < EPS

def gcd(a, b):
    """Returns the greatest common divisor of a and b, using the Euclidean
    algorithm."""
    if a <= 0 or b <= 0:
        raise ValueError('Arguments must be positive integers')

    while b != 0:
        tmp = b
        b = a % b
        a = tmp
    return a

def is_prime(n):
    """Tests whether n is prime.

    This uses a naive algorithm that would be useless for numbers of substantial
    size, but is fine for the purposes of QAS, which are understanding and
    simulating the use of quantum computing rather than actually solving
    difficult problem instances.
    """
    if  n <= 1:
        raise ValueError('n must be greater than 1')

    # trial  division
    for k in range(2, int(floor(sqrt(n))) + 1):
        if n % k == 0:
            return False
    return True

def int_root(n):
    """Checks whether n is the k-th power of an integer for some k > 1. If so,
    it returns the root r such that r^k = n. Otherwise, returns -1."""
    if n <= 0:
        raise ValueError('n must be positive')
    k = 2
    while k <= log(n, 2):
        root = n**(1. / k)
        iroot = round(root)
        if iroot**k == n:
            return iroot
        k += 1
    return -1


import numpy as np

def cartesian_to_celestial(vector):
    """
    Convert the Cartesian vector [x, y, z] to spherical coordinates [r, theta, phi].
    The parameter r is the radial distance, theta is the polar angle, and phi is the azimuth.

    Arguments:
        :np.ndarray: cartesian vector [x, y, z]

    Returns:
        :np.ndarray: spherical coordinate vector [phi, theta, r]
    """
    vector = np.atleast_2d(vector)
    D = np.linalg.norm(vector, axis = -1)
    unit = np.array([v/np.linalg.norm(v) for v in vector])
    dec = np.arcsin(unit[:,2])
    ra = np.arctan2(unit[:,0], unit[:,1])
    ra[ra<0] += 2*np.pi
    return np.array([ra,dec,D]).T

def celestial_to_cartesian(vector):
    """
    Convert the celestial coordinate vector [phi, theta, r] to the Cartesian vector [x, y, z].
    The parameter r is the radial distance, theta is the polar angle, and phi is the azimuth

    Arguments:
        :np.ndarray vector: celestial coordinate vector [ra, dec, dist]

    Returns:
        :np.ndarray: cartesian vector [x, y, z]
    """
    vector = np.atleast_2d(vector)
    # Trig alias.
    cos_theta = np.cos(vector[:,1])
    # The vector.
    x = vector[:,2] * np.sin(vector[:,0]) * cos_theta
    y = vector[:,2] * np.cos(vector[:,0]) * cos_theta
    z = vector[:,2] * np.sin(vector[:,1])
    return np.array([x,y,z]).T

def Jacobian(cartesian_vect):
    """
    Computes the jacobian of celestial transformation for a cartesian vector

    Arguments:
        :np.ndarray cartesian_vect: cartesian vector [x, y, z]

    Returns:
        :np.ndarray: Jacobian of the transformation
    """
    return Jacobian_in_celestial(cartesian_to_celestial(np.atleast_2d(cartesian_vect)))

def inv_Jacobian(celestial_vect):
    """
    Computes the inverse jacobian of celestial transformation for a celestial vector

    Arguments:
        :np.ndarray cartesian_vect: cartesian vector [ra, dec, D]

    Returns:
        :np.ndarray: inverse Jacobian of the transformation
    """
    detJ = Jacobian_in_celestial(np.atleast_2d(celestial_vect))
    return 1/detJ

def Jacobian_in_celestial(celestial_vect):
    """
    Computes the jacobian of celestial transformation

    Arguments:
        :np.ndarray cartesian_vect: cartesian vector [ra, dec, D]

    Returns:
        :np.ndarray: Jacobian of the transformation
    """
    d = celestial_vect[:,2]
    theta = celestial_vect[:,1]
    return d*d*np.cos(theta)


"""
Exercise 6.1.9: Dipole fixed point
"""
import argparse
import matplotlib.pyplot as plt
import numpy as np
import sys

from phase_plane.runge_kutta import runge_kutta

def f(v):
    """
    The right-hand side of the system of differential equations.

    ..math:: \dot{x} = 2xy, \dot{y} = y^2-x^2
    """
    x = v[0]
    y = v[1]
    return np.array([2 * x * y, y**2 - x**2])

def setup_cli(args):
    """
    Setup up command-line parser.
    """
    parser = argparse.ArgumentParser(description='Exercise 6.1.8: Van der Pol oscillator.')
    parser.add_argument('-p', type=int, default=15, help='The number of points to use in the x and y direction.')
    parser.add_argument('--x_min', type=float, default=-3.5, help='Minimal value of x to be plotted.')
    parser.add_argument('--x_max', type=float, default=+3.5, help='Minimal value of x to be plotted.')
    parser.add_argument('--y_min', type=float, default=-3.5, help='Minimal value of y to be plotted.')
    parser.add_argument('--y_max', type=float, default=+3.5, help='Minimal value of y to be plotted.')
    parser.add_argument('--delta_t', type=float, default=0.01, help='Time step used in the numerical solution of the DE.')
    parser.add_argument('--end_t', type=float, default=1.0, help='Final time in the solution of the DE (Starting from t=0).')
    return parser.parse_args(args)

if __name__ == "__main__":
    # Parse command-line arguments
    args = setup_cli(sys.argv[1:])

    # Draw vector field
    x, y = np.meshgrid(np.linspace(args.x_min, args.x_max, args.p), np.linspace(args.y_min, args.y_max, args.p))
    u = 2*x*y
    v = y**2 - x**2

    plt.title('Dipole Fixed Point')
    plt.xlabel('x')
    plt.ylabel('y')
    plt.xlim(args.x_min, args.x_max)
    plt.ylim(args.y_min, args.y_max)
    plt.quiver(x, y, u, v)

    # Draw phase portraits
    x0 = [0.5, 0.5]
    t, xy = runge_kutta(f, x0, 0, 100, 0.01)
    x, y = xy.T[0], xy.T[1]
    plt.plot(x, y, c=f"C1", label=f'x0={x0}')

    x0 = [-3., -3.0]
    t, xy = runge_kutta(f, x0, 0, 100, 0.01)
    x, y = xy.T[0], xy.T[1]
    plt.plot(x, y, c=f"C2", label=f'x0={x0}')

    x0 = [-2.5, -1.5]
    t, xy = runge_kutta(f, x0, 0, 100, 0.01)
    x, y = xy.T[0], xy.T[1]
    plt.plot(x, y, c=f"C3", label=f'x0={x0}')

    x0 = [-2.5, -1.]
    t, xy = runge_kutta(f, x0, 0, 100, 0.01)
    x, y = xy.T[0], xy.T[1]
    plt.plot(x, y, c=f"C4", label=f'x0={x0}')

    x0 = [-2.5, 1.]
    t, xy = runge_kutta(f, x0, 0, 100, 0.01)
    x, y = xy.T[0], xy.T[1]
    plt.plot(x, y, c=f"C5", label=f'x0={x0}')

    x0 = [0.5, 0.5]
    t, xy = runge_kutta(f, x0, 0, 100, 0.01)
    x, y = xy.T[0], xy.T[1]
    plt.plot(x, y, c=f"C6", label=f'x0={x0}')

    # Plot everything
    plt.legend()
    plt.show()


"""
stats functions for mean, median, mode,
variance, standard deviation, and coefficient of variation
"""

import numpy as np

class Stats:

    def __init__(self, data):
        self.data = list(data)
        self.size = len(data)

    def mean(self):
        """
        function to calculate mean of data
        """
        mean = sum(self.data)/self.size
        return mean

    def median(self):
        """
        function to calculate median of data
        """
        self.data.sort()

        if len(self.data) % 2 == 1:
            median = self.data[int(self.size/2)]
        else:
            median = (self.data[int(self.size/2 - 1)] +
                    self.data[int(self.size/2)]) / 2
        return median

    def mode(self):
        """
        function to get mode of data, only returns the first it encounters if
        there are more than 1 mode
        """
        mode = max(self.data, key=self.data.count)
        return mode

    def variance(self, sample=True):
        """
        function to calculate variance of data

        by default, it calculates sample variance, change sample=False if you
        want to calculate population.
        """
        distance_squared = list(map(lambda x: (x - sum(self.data)/self.size)**2, self.data))

        if sample == True:
            variance = sum(distance_squared)/(self.size - 1)
        if sample == False:
            variance = sum(distance_squared)/(self.size)
        return variance

    def stddev(self, sample=True):
        """
        function to calculate standard deviation of data

        by default, it calculates sample standard deviation, change
        sample=False if you want to calculate population.
        """
        distance_squared = list(map(lambda x: (x - sum(self.data)/self.size)**2, self.data))

        if sample == True:
            variance = sum(distance_squared)/(self.size - 1)
            stddev = variance**(1/2)
        if sample == False:
            variance = sum(distance_squared)/(self.size)
            stddev = variance**(1/2)
        return stddev

    def coeffvar(self, sample=True):
        """
        function to calculate the coefficient of variance of data

        by default, it calculates sample coefficient of variance, change
        sample=False if you want to calculate population.
        """
        mean = sum(self.data)/self.size
        distance_squared = list(map(lambda x: (x - sum(self.data)/self.size)**2, self.data))

        if sample == True:
            variance = sum(distance_squared)/(self.size - 1)
            stddev = variance**(1/2)
            coeffvar = stddev/mean
        if sample == False:
            variance = sum(distance_squared)/(self.size)
            stddev = variance**(1/2)
            coeffvar = stddev/mean
        return coeffvar