# data_images.py
# -------------------------------------------------------------------------
# Illustrate differences between image and Cartesian coordinates.
# -------------------------------------------------------------------------
#%% Setup
import numpy as np
import matplotlib.pyplot as plt

# Define a coordinate grid.
# Same spacing, but twice as many points along x-axis
x_max, y_max = 2, 1
x_num, y_num = 200, 100

# Create coordinate arrays.
x = np.linspace(0,x_max,x_num)
y = np.linspace(0,y_max,y_num)

#%% Generate data to plot.
# Assign function values to placeholder array.
z = np.zeros((x_num,y_num))
for i in range(x_num):
	for j in range(y_num):
		z[i][j] = (x[i] - 2*y[j])**2

# Use meshgrid to generate the same function values.
X,Y = np.meshgrid(x,y)
Z = (X-2*Y)**2

#%% Visualize results.
fig, ax = plt.subplots(2,3, figsize=(12,6))
fig.suptitle(r"Plots of $f(x,y) = (x-2y)^2$")

ax[0,0].imshow(z)
ax[0,0].set_title("Loop: Image Coordinates")

ax[0,1].imshow(z, origin="lower")
ax[0,1].set_title("Loop: Spatial Coordinates")

ax[0,2].imshow(Z)
ax[0,2].set_title("meshgrid: Image Coordinates")

ax[1,0].imshow(z.transpose(), origin="lower")
ax[1,0].set_title("Loop: Transpose + Spatial Coordinates")

ax[1,1].imshow(Z, origin="lower")
ax[1,1].set_title("meshgrid: Spatial Coordinates")

ax[1,2].pcolormesh(X, Y, Z, shading='auto')
ax[1,2].axis('image')
ax[1,2].set_title("pcolormesh")

plt.show()


# pylint: disable=invalid-name

import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt

# CUSTOMIZABLE: Collect/Prepare data
datapoint_size = 1000
batch_size = 1000
steps = 10000
actual_W1 = 2
actual_W2 = 5
actual_b = 7
learn_rate = 0.001
log_file = "logs/feature_2"

# Model linear regression y = Wx + b
x = tf.placeholder(tf.float32, [None, 2], name="x")
W = tf.Variable(tf.zeros([2, 1]), name="W")
b = tf.Variable(tf.zeros([1]), name="b")
with tf.name_scope("Wx_b") as scope:
    product = tf.matmul(x, W)
    y = product + b

# Add summary ops to collect data
W_hist = tf.summary.histogram("weights", W)
b_hist = tf.summary.histogram("biases", b)
y_hist = tf.summary.histogram("y", y)

y_ = tf.placeholder(tf.float32, [None, 1])

# Cost function sum((y_-y)**2)
with tf.name_scope("cost") as scope:
    cost = tf.reduce_mean(tf.square(y_ - y))
    cost_sum = tf.summary.scalar("cost", cost)

# Training using Gradient Descent to minimize cost
with tf.name_scope("train") as scope:
    train_step = tf.train.GradientDescentOptimizer(learn_rate).minimize(cost)

all_xs = []
all_ys = []
for i in range(datapoint_size):
    # Create fake data for y = 2.x_1 + 5.x_2 + 7
    x_1 = i % 10
    x_2 = np.random.randint(datapoint_size / 2) % 10
    y = actual_W1 * x_1 + actual_W2 * x_2 + actual_b
    # Create fake data for y = W.x + b where W = [2, 5], b = 7
    all_xs.append([x_1, x_2])
    all_ys.append(y)

all_xs = np.array(all_xs)
all_ys = np.transpose([all_ys])

sess = tf.Session()

# Merge all the summaries and write them out to logs
merged = tf.summary.merge_all()
writer = tf.summary.FileWriter(log_file, sess.graph)

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

for i in range(steps):
    if datapoint_size == batch_size:
        batch_start_idx = 0
    elif datapoint_size < batch_size:
        raise ValueError("datapoint_size: %d, must be greater than batch_size: %d" % (
            datapoint_size, batch_size))
    else:
        batch_start_idx = (i * batch_size) % (datapoint_size - batch_size)

    batch_end_idx = batch_start_idx + batch_size
    batch_xs = all_xs[batch_start_idx:batch_end_idx]
    batch_ys = all_ys[batch_start_idx:batch_end_idx]
    xs = np.array(batch_xs)
    ys = np.array(batch_ys)
    all_feed = {x: all_xs, y_: all_ys}

    # Record summary data, and the accuracy every 10 steps
    if i % 10 == 0:
        result = sess.run(merged, feed_dict=all_feed)
        writer.add_summary(result, i)
    else:
        feed = {x: xs, y_: ys}
        sess.run(train_step, feed_dict=feed)
    print("After %d iteration:" % i)
    print("W: %s" % sess.run(W))
    print("b: %f" % sess.run(b))
    print("cost: %f" % sess.run(cost, feed_dict=all_feed))

# close the writer when you're done using it
writer.flush()
writer.close()

# Step 9: output the values of w and b
w_value, b_value = sess.run([W, b])

# NOTE: W should be close to actual_W1, actual_W2, and b should be close
# to actual_b
# NOTE: Run tensorboard --logdir=path/to/log-directory to visualize


from numpy import quantile, corrcoef
from numpy.random import seed, normal

# Correlation arising from selection (see start of Chapter 6).
seed(5)
N = 200  # The number of grant proposals.
P = 0.1  # The proportion of proposals that get accepted.
news = normal(size=N)
trust = normal(size=N)
# Simulate the selection process by finding the top 10% of combined scores.
score = news + trust
accepted_score = quantile(score, 1 - P)
selected = score >= accepted_score
# Find that the correlation coefficient of truly uncorrelated values now ...
correlation_coef = corrcoef(news[selected], trust[selected])
rounded_correlation_coef = round(correlation_coef[0][1], 2)
print(f"The apparent correlation is {rounded_correlation_coef}.")


# plots.py
import matplotlib
matplotlib.rcParams = matplotlib.rc_params_from_file('../../matplotlibrc')

from matplotlib import pyplot as plt
import numpy as np
from scipy import linalg as la
from scipy import optimize as opt

def newtonsMethod1d(f, df, ddf, x, niter=10):   # Keep!
    '''
    Perform Newton's method to minimize a function from R to R.
    Inputs:
        f -- objective function (twice differentiable)
        df -- first derivative
        ddf -- second derivative
        x -- initial guess
        niter -- integer, giving the number of iterations
    Returns:
        the approximated minimizer
    '''
    for i in xrange(niter):
        x = x-df(x)/ddf(x)
    return x, f(x)

def myFunc(x):   # Keep!
    return 4*x**2 - 13*x + 40 + 6*np.sin(4*x)
def myDFunc(x):   # Keep!
    return 8*x - 13+24*np.cos(4*x)
def myDDFunc(x):   # Keep!
    return 8-96*np.sin(4*x)

def newton():  # Keep!
    x1,f1 = newtonsMethod1d(myFunc, myDFunc, myDDFunc, 1, niter=200)
    x2,f2 = newtonsMethod1d(myFunc, myDFunc, myDDFunc, 4, niter=200)
    dom = np.linspace(-10,10,100)
    plt.plot(dom, myFunc(dom))
    plt.plot(x1, f1, '*')
    plt.plot(x2, f2, '*')
    plt.annotate('Global Minimum', xy=(x1, f1), xytext=(-4, 200),
                arrowprops=dict(facecolor='black', shrink=0.1),)
    plt.annotate('Local Minimum', xy=(x2,f2), xytext=(2, 175),
                    arrowprops=dict(facecolor='black', shrink=0.1),)
    plt.savefig('newton.pdf')
    plt.clf()

newton()


import numpy as np

# This file contains the suggested examples from Section 9.3.2
# they all assume the input x is of the correct dimension, and a column vector

def obj_quadratic_r2(x, gamma=2):
    """ This is the objective function:
    f(x) = 1/2 * (x_1^2 + gamma*x_2^2)

    Args:
        x: input, a 2x1 numpy array
        gamma: defaults to 2, can be used to control the condition number of
            the sublevel sets of the function.
            condition number = max(gamma, 1/gamma)
    """
    _A = np.array(
        [[1, 0],
         [0, gamma]], dtype=float
    )
    return 0.5 * x.T @ _A @ x

def obj_quadratic_r2_jac(x, gamma=2):
    """ This is the objective function:
    f(x) = 1/2 * (x_1^2 + gamma*x_2^2)

    Args:
        x: input, a 2x1 numpy array
        gamma: defaults to 2, can be used to control the condition number of
            the sublevel sets of the function.
            condition number = max(gamma, 1/gamma)
    """
    _A = np.array(
        [[1, 0],
         [0, gamma]], dtype=float
    )
    return _A @ x

def obj_nonquadratic_r2(x):
    """ This is the objective function:
    f(x) = exp(x_1 + 3x_2 - 0.1) + exp(x_1 - 3x_2 - 0.1) + exp(-x_1 - 0.1)

    Args:
        x: input, a 2x1 numpy array. Recommend keeping inputs reasonably small.
    """
    x1, x2 = x.flatten()
    return np.exp(x1+3*x2-0.1) + np.exp(x1-3*x2-0.1) + np.exp(-x1-0.1)


import numpy as np

class Distance:

    @staticmethod
    def euclidian_distance(item_1, item_2):
        return np.sqrt(np.sum((item_1 - item_2) ** 2))

    @staticmethod
    def hamming_distance(item_1, item_2):
        return np.sum(np.abs(item_1 - item_2))/len(item_1)

    @staticmethod
    def manhattan_distance(item_1, item_2):
        return np.sum(np.abs(item_1 - item_2))

    @staticmethod
    def minkowski_distance(item_1, item_2, p):
        return np.sum((item_1 - item_2) ** p)**(1/p)


from scipy.integrate import simps
from scipy.integrate import trapz
from scipy.integrate import romb
import numpy as np

def f(x):
    """
    """
    return 1

def g(x):
    """
    Function taken from https://www.math.duke.edu/vigre/pruv/studentwork/atwood.nearsing.pdf
    """

    a = 10e-3

    return f(x)* np.log(x**2 + a**2)

def simpson(f, a, b, n):
    """
    Simpson composite rule
    """
    h=(b-a)/n
    k=0.0
    x=a + h
    for i in range(1,n/2 + 1):
        k += 4.*f(x)
        x += 2.*h

    x = a + 2.*h
    for i in range(1,n/2):
        k += 2.*f(x)
        x += 2.*h
    return (h/3.)*(f(a)+f(b)+k)

# Computing integral using less interval
# Correct answer is -3.99372

I = -3.99372

i1 = simpson(g, -1., 1., 2**5+ 1)

i2 = simpson(g, -1., 1., 2**10+1)

print 'Reference answer is ' + str(I)
print 'Previous code answer is ' + str(i1)

print 'Current code answer is ' + str(i2)

print 'Previous code absolute error is ' + str(np.abs(I-i1))

print 'Current code absolute error is ' + str(np.abs(I-i2))


#%%
'''
reproduction of https://ipython-books.github.io/134-simulating-a-stochastic-differential-equation/

Stochastic differential equations (SDEs) model dynamical systems that are subject to noise.
In this recipe, we simulate an Ornstein-Uhlenbeck process, which is a solution of the Langevin equation.
The Ornstein-Uhlenbeck process is stationary, Gaussian, and Markov, which makes it a good candidate to represent stationary random noise.
We will simulate this process with a numerical method called the Euler-Maruyama method.
'''
#%%
import numpy as np
import matplotlib.pyplot as plt
#%%
b = 0.5
sigma = 1.
#%%
dt = .001  # Time step.
T = 1.  # Total time.
n = int(T / dt)  # Number of time steps.
t = np.linspace(0., T, n)  # Vector of times.
#%%
x = np.zeros(n)
#%%
'''
discretized stochastic differential equation and process
x_{t+1} = x_t + (-b * x_t) * dt + sigma * (dt)^1/2 * N(0, 1)

where
b = 1/2, sigma = 1
x_{t+1} = x_t + (-1/2 * x_t) * dt + 1 * (dt)^1/2 * N(0, 1)
and (-1/2 * x_t) = score function of N(0, 1)
and distribution of x_T converges to N(0, \sigma^2 / 2b) = N(0, 1)
'''
for i in range(n - 1):
    x[i + 1] = x[i] + (-b * x[i]) * dt + sigma * np.sqrt(dt) * np.random.randn()
#%%
fig, ax = plt.subplots(1, 1, figsize=(8, 4))
ax.plot(t, x, lw=2)
ax.set_title('simulation of langevin equation')
#%%
ntrials = 10000
X = np.zeros(ntrials)
# We create bins for the histograms.
bins = np.linspace(-3., 3., 100)
fig, ax = plt.subplots(1, 1, figsize=(8, 4))
for i in range(n):
    # We update the process independently for all trials
    X += (-b * X) * dt + sigma * np.sqrt(dt) * np.random.randn(ntrials)
    # We display the histogram for a few points in time (10000 points of process)
    if i in (5, 50, 900):
        hist, _ = np.histogram(X, bins=bins, density=True)
        ax.plot((bins[1:] + bins[:-1]) / 2, hist,
                {5: '-', 50: '-.', 900: '--', }[i],
                label=f"t={i * dt:.2f}")
hist, _ = np.histogram(np.random.randn(X.shape[0]), bins=bins, density=True)
ax.plot((bins[1:] + bins[:-1]) / 2, hist, ':', label='N(0,1)')
ax.legend()
#%%
# '''
# numerical solution
# '''
# np.random.seed(520)
# ntrials = 10000
# # true
# X = np.zeros(ntrials)
# fig, ax = plt.subplots(1, 1, figsize=(8, 4))
# for i in range(n):
#     X += (-b * X) * dt + sigma * np.sqrt(dt) * np.random.randn(ntrials)
# hist, _ = np.histogram(np.random.randn(X.shape[0]), density=True)
# ax.plot(hist, '-.', label='N(0,1)')

# # solution
# X0 = np.random.normal(0, 1, (ntrials, ))
# X = np.exp(-b * T) * X0 + np.sum(sigma * np.exp(-b * (T - dt)) * np.random.normal(0, dt, (ntrials, ntrials)), axis=1)
# hist, _ = np.histogram(X, density=True)
# ax.plot(hist, '-', label='solution')
# ax.legend()
#%%
'''
The error of the Euler-Maruyama method is of order sqrt(dt). The Milstein method is a more precise numerical scheme, of order dt.
'''
#%%


# -*- coding: utf-8 -*-
"""
Spyder Editor

This is a temporary script file.
"""
# for math
import numpy as np
# for physical cosntants
import scipy.constants as const
# for plots
import matplotlib.pyplot as plt

# charge settings
N_1 = -1
N_2 = 1
N_3 = -1
N_4 = 1

# coulomb constant
k_C = 1 / (4 * np.pi * const.epsilon_0)

# charges
q_1 = N_1 * const.e
q_2 = N_2 * const.e
q_3 = N_3 * const.e
q_4 = N_4 * const.e

# position of the charged points
q_1_x = 0.5
q_1_y = 0.5
q_2_x = 0.5
q_2_y = - 0.5
q_3_x = -0.5
q_3_y = -0.5
q_4_x = -0.5
q_4_y = 0.5

print('charges')
print('q_1 = ', q_1, 'x = ', q_1_x, 'y = ', q_1_y)
print('q_2 = ', q_2, 'x = ', q_2_x, 'y = ', q_2_y)
print('q_3 = ', q_3, 'x = ', q_3_x, 'y = ', q_3_y)
print('q_4 = ', q_4, 'x = ', q_4_x, 'y = ', q_4_y)

# Meshgrid
size = 1
s = (size / 2)
n_s = 100
x, y = np.meshgrid(np.linspace(-s, s, n_s),
                   np.linspace(-s, s, n_s))

# radius
r_1 = np.sqrt((q_1_x - x)**2 + (q_1_y - y)**2)
r_2 = np.sqrt((q_2_x - x)**2 + (q_2_y - y)**2)
r_3 = np.sqrt((q_3_x - x)**2 + (q_3_y - y)**2)
r_4 = np.sqrt((q_4_x - x)**2 + (q_4_y - y)**2)

# helper varables
k_1 = q_1 / (r_1*r_1*r_1)
k_2 = q_2 / (r_2*r_2*r_2)
k_3 = q_3 / (r_3*r_3*r_3)
k_4 = q_4 / (r_4*r_4*r_4)

# https://www.geeksforgeeks.org/how-to-plot-a-simple-vector-field-in-matplotlib/

# Directional vectors
E_x = k_C * (k_1 * (q_1_x - x) + k_2 * (q_2_x - x) + k_3 * (q_3_x - x) + k_4 * (q_4_x - x));
E_y = k_C * (k_1 * (q_1_y - y) + k_2 * (q_2_y - y) + k_3 * (q_3_y - y) + k_4 * (q_4_y - y));

# Plotting Vector Field with QUIVER
plt.quiver(x, y, E_x, E_y, color='g')
plt.title('Vector Field')

# Setting x, y boundary limits
boundary = 1
plt.xlim(-boundary, boundary)
plt.ylim(-boundary, boundary)

# Show plot with gird
plt.grid()
plt.show()

# Depict illustration
plt.figure(figsize=(10, 10))
plt.streamplot(x,y,E_x,E_y, density=1.4, linewidth=None, color='#A23BEC')
plt.plot(q_1_x,q_1_y,'-or')
plt.plot(q_2_x,q_2_y,'-og')
plt.plot(q_3_x,q_3_y,'-ob')
plt.plot(q_4_x,q_4_y,'-oc')
plt.title('Electromagnetic Field')

boundary = 0.6
plt.xlim(-boundary, boundary)
plt.ylim(-boundary, boundary)

# Show plot with gird
plt.grid()
plt.show()


from math import factorial

import matplotlib.pylab as plt
from numpy import ones, copy, cos, tan
from numpy import sqrt, pi, exp, linspace, zeros

def gaussxw(N):
    # Initial approximation to roots of the Legendre polynomial
    a = linspace(3, 4 * N - 1, N) / (4 * N + 2)
    x = cos(pi * a + 1 / (8 * N * N * tan(a)))

    # Find roots using Newton's method
    epsilon = 1e-15
    delta = 1.0
    while delta > epsilon:
        p0 = ones(N, float)
        p1 = copy(x)
        for k in range(1, N):
            p0, p1 = p1, ((2 * k + 1) * x * p1 - k * p0) / (k + 1)
        dp = (N + 1) * (p0 - x * p1) / (1 - x * x)
        dx = p1 / dp
        x -= dx
        delta = max(abs(dx))

    # Calculate the weights
    w = 2 * (N + 1) * (N + 1) / (N * N * (1 - x * x) * dp * dp)

    return x, w

def gaussxwab(N, a, b):
    x, w = gaussxw(N)
    return 0.5 * (b - a) * x + 0.5 * (b + a), 0.5 * (b - a) * w

def H(n, x):
    def H_iter(a, b, count):
        if count == 0:
            return b
        else:
            return H_iter(2 * x * a - 2 * (count - 1) * b, a, count - 1)

    return H_iter(2 * x, 1, n)

def wave_func(n, x):
    return (1 / (sqrt((2 ** n) * factorial(n) * sqrt(pi)))) * exp(-0.5 * (x ** 2)) * H(n, x)

N = 200
d = linspace(-4, 4, N)
y = zeros([N, 4], float)
for j in range(0, 4, 1):
    for i in range(0, N, 1):
        y[i, j] = wave_func(j, d[i])
y2 = []
d2 = linspace(-10, 10, 500)
for m in range(0, 500, 1):
    y2.append(wave_func(30, d2[m]))
f1 = plt.figure(1)
plt.plot(d2, y2, 'b-', label=r"$\psi_{30}$", linewidth=1)
plt.xlabel("x")
plt.ylabel(r"$\psi(x)$")
f2 = plt.figure(2)
plt.plot(d, y[:, 0], label=r"$\psi_0$")
plt.plot(d, y[:, 1], label=r"$\psi_1$")
plt.plot(d, y[:, 2], label=r"$\psi_2$")
plt.plot(d, y[:, 3], label=r"$\psi_3$")
plt.xlabel("x")
plt.ylabel(r"$\psi(x)$")
plt.show()

Ankit Khandelwal_HW2/exercise 5/exercise 5a.py


# Copyright 2017 Battelle Energy Alliance, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# from https://en.wikipedia.org/wiki/Test_functions_for_optimization
#
# takes any number of input parameters x[i]
# returns value in "ans"
# optimal minimum at f(1,1,...,1,1) = 0, only minimum for up to 3 inputs
# note for 4 to 7 inputs, a second local minima exists near (-1,1,...,1), and it gets complicated after that
# parameter range is -inf <= x[i] <= inf

import numpy as np

def evaluate2d(X,Y):
  return 100*(Y-X*X)**2 + (X-1)**2

def evaluate(*args):#xs):
  xs = np.array(args)
  return np.sum( 100.*(xs[1:] - xs[:-1]**2)**2 + (xs[:-1] - 1.)**2 )

def run(self,Inputs):
  self.ans = evaluate(Inputs.values())


import numpy as np
import matplotlib.pyplot as pyplot
import scipy.spatial.distance as sd
import sys
import os
import copy

sys.path.append(os.path.dirname(os.getcwd())+"/code_material_python")
from helper import *
from graph_construction.generate_data import *

def build_similarity_graph(X, var=1, eps=0, k=0):
  """     Computes the similarity matrix for a given dataset of samples.

   Input
   X:
       (n x m) matrix of m-dimensional samples
   k and eps:
       controls the main parameter of the graph, the number
       of neighbours k for k-nn, and the threshold eps for epsilon graphs
   var:
       the sigma value for the exponential function, already squared

   Output
   W:
       (n x n) dimensional matrix representing the adjacency matrix of the graph
   similarities:
       (n x n) dimensional matrix containing
       all the similarities between all points (optional output)
  """

  assert eps + k != 0, "Choose either epsilon graph or k-nn graph"

  if eps:
    print("Constructing eps-Graph ...")
  else:
    print("Constructing k-NN Graph ...")

  # euclidean distance squared between points
  dists = sd.squareform(sd.pdist(X))**2
  similarities = np.exp(-dists/(2*var))

  if eps:
    W = similarities * (similarities-eps>=0)
    print("eps-Graph constructed !")
    return W, similarities

  if k:
    W = similarities.copy()
    for i in range(W.shape[0]):
      W[i,i] = 0
      kNearestNodes = np.argsort(-W[i,:])
      kIdx = kNearestNodes[k:]
      W[i,kIdx] = 0
    print("k-NN Graph constructed !")
    return np.maximum(W, W.T), similarities

def plot_similarity_graph(X, Y, eps=0.1, k=0, var=1):

    W, similarities = build_similarity_graph(X, var, eps=eps, k=k)
    plot_graph_matrix(X,Y,W)

def how_to_choose_epsilon(gen_param):

    # the number of samples to generate
    num_samples = 100
    gen_param =   gen_param
    [X, Y] = worst_case_blob(num_samples,gen_param)

    var =  0.5

    dists = sd.squareform(sd.pdist(X))**2
    similarities = np.exp(-dists/(2*var))

    # Building the max spanning tree
    max_tree = max_span_tree(similarities)
    A = similarities*max_tree
    # Finding the optimal epsilon
    eps = np.min(A[np.where(max_tree>0)])
    print("Best epsilon found: ", eps)

    plot_similarity_graph(X, Y, eps=eps, var=var)
    return eps

how_to_choose_epsilon(2)
[X,Y] = blobs(200,2,0.2)
[X, Y] = worst_case_blob(100,3)
[X, Y] = two_moons(200,1,2)
plot_similarity_graph(X, Y, eps=eps, k=0, var=0.5)
plot_similarity_graph(X, Y, eps=0, k=10, var=0.5)


# Plot error surface for linear regression model.
# Based on https://github.com/probml/pmtk3/blob/master/demos/contoursSSEdemo.m

import superimport

import numpy as np
import matplotlib.pyplot as plt
import pyprobml_utils as pml

from mpl_toolkits.mplot3d import axes3d, Axes3D

np.random.seed(0)

N = 21
x = np.linspace(0.0, 20, N)
X0 = x.reshape(N,1)
X = np.c_[np.ones((N,1)), X0]
w = np.array([-1.5, 1/9.])
y =  w[0]*x + w[1]*np.square(x)
y = y + np.random.normal(0, 1, N) * 2

w = np.linalg.lstsq(X, y, rcond=None)[0]
W0, W1 = np.meshgrid(np.linspace(-8,0,100), np.linspace(-0.5,1.5,100))

SS = np.array([sum((w0*X[:,0] + w1*X[:,1] - y)**2) for w0, w1 in zip(np.ravel(W0), np.ravel(W1))])
SS = SS.reshape(W0.shape)

plt.figure()
plt.contourf(W0, W1, SS)
pml.savefig('linregHeatmapSSE.pdf')
plt.colorbar()
plt.show()

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
surf = ax.plot_surface(W0, W1, SS)
pml.savefig('linregSurfSSE.pdf')
plt.show()

fig,ax = plt.subplots()
CS = plt.contour(W0, W1, SS, levels=np.linspace(0,2000,10), cmap='jet')
plt.plot(w[0], w[1],'x')
pml.savefig('linregContoursSSE.pdf')
plt.show()


import scipy as sp

w = sp.poly1d([1, 2, 3, 4])

# metoda trapezow
a = 1
b = 3

def ctN(a, b, Np):
    x = sp.linspace(a, b, Np + 1)
    y = w(x)
    dx = x[1] - x[0]

    return (sum(y[1:-1]) + (y[0] + y[-1]) / 2) * dx

def ctS(a, b, Np):
    x = sp.linspace(a, b, Np + 1)
    y = w(x)
    dx = x[1] - x[0]

    return sum((y[1:] + y[:-1]) / 2) * dx

def cS(a, b, Np):
    x = sp.linspace(a, b, Np + 1)
    y = w(x)
    dx = x[1] - x[0]
    return (y[0] + y[-1] + 2 * sum(y[2:-1:2]) + 4 * sum(y[1:-1:2])) * dx / 3

"""metoda newtona"""

def It38(a, b, Np):
    x = sp.linspace(a, b, Np + 1)
    y = w(x)
    dx = x[1] - x[0]
    return (y[0] + y[-1] + 2 * sum(y[3:-3:3]) + 3 * sum(y[1:Np:3]) + 3 * sum(y[2:-1:3])) * 3 * dx / 8

def cw(a, b):
    tmp = w.integ()
    return tmp(b) - tmp(a)

lp = [12, 24, 36, 60, 90]
wd = cw(a, b)
"""
for i in range(len(lp)):
    print("wartosc dokladna: {}".format(wd))
    c1 = ctN(a,b,lp[i])
    b1= (c1-wd)/wd
    c2 = ctN(a, b, lp[i]*2)
    b2 = (c2 - wd) / wd
    cr= 4*c2/3-c1/3
    br=(cr-wd)/wd
    print('liczby podzialu: {} i {}\nc1 = {}, b1 = {:6.2e}\nc = {}, b2 = {:6.2e}\n cr = {}, br = {:6.2e}'.format(lp[1],lp[i]*2,c1,b1,c2,b2,cr,br))
"""
for i in range(len(lp)):
    print("wartosc dokladna: {}".format(wd))
    c1 = It38(a, b, lp[i])
    b1 = (c1 - wd) / wd
    c2 = It38(a, b, lp[i] * 2)
    b2 = (c2 - wd) / wd
    cr = 10 * c2 / 15 - c1 / 15
    br = (cr - wd) / wd
    print('liczby podzialu: {} i {}\nc1 = {}, b1 = {:6.2e}\nc = {}, b2 = {:6.2e}\n cr = {}, br = {:6.2e}\n\n'.format(
        lp[1],
        lp[
            i] * 2,
        c1, b1,
        c2, b2,
        cr,
        br))


# You have an N by N board. Write a function that, given N, returns the
# number of possible arrangements of the board where N queens can be
# placed on the board without threatening each other, i.e. no two
# queens share the same row, column, or diagonal.

import numpy as np

def place_queen(board, queen_row):
    if queen_row in board:
        return False

    queen_col = len(board)
    for col, row in enumerate(board):
        if abs(row - queen_row) == abs(col - queen_col):
            return False
    return True

def queens_on_board(N, board = []):
    if N == len(board):
        return 1

    variations = 0
    for row in range(N):
        if place_queen(board, row):
            variations += queens_on_board(N, board + [row])
    return variations

# Driver code:
result = queens_on_board(4)
print(result)

result = queens_on_board(1)
print(result)

result = queens_on_board(2)
print(result)

result = queens_on_board(10)
print(result)


import scipy as sp
import scipy.linalg as la
import numpy as np
'''
U,s,Vh = la.svd(A)
S = sp.diag(s)
S = S*(S>tol)
r = sp.count_nonzero(S)
B = sp.dot(U,sp.sqrt(S))
C = sp.dot(sp.sqrt(S),Vh)
B = B[:,0:r]
C = C[0:r,:]
'''

#Problem 3
#When I feed the second example matrix into my function,
#it comes out with "almost" the correct Drazin Inverse,
#but the top two rows are 1/2 of what they should be.
#The other matricies come out right
def drazin(A,tol):
    CB = A.copy()

    Bs = []
    Cs = []
    k = 1

    while( not (sp.absolute(CB)<tol).all() and sp.absolute(la.det(CB)) < tol):
        U,s,Vh = la.svd(CB)
        S = sp.diag(s)
        S = S*(S>tol)
        r = sp.count_nonzero(S)
        B = sp.dot(U,sp.sqrt(S))
        C = sp.dot(sp.sqrt(S),Vh)
        B = B[:,0:r]
        Bs.append(B)
        C = C[0:r,:]
        Cs.append(C)
        CB = sp.dot(C,B)
        k+=1

    D = sp.eye(A.shape[0])
    for B in Bs:
        D = sp.dot(D,B)
    if( (sp.absolute(CB)<tol).all() ):
        D = sp.dot( D,CB)
    else:
        D = sp.dot( D,np.linalg.matrix_power(CB,-(k+1)))
    for C in reversed(Cs):
        D = sp.dot(D,C)
    return D


import matplotlib.pyplot as plt
from numpy import arange, ones, zeros
from numpy import sum as npsum

from scipy.optimize import least_squares
from scipy.special import gamma

from autocorrelation import autocorrelation

def FitFractionalIntegration(dx, l_, d0):
    # Fit of a fractional integration process on X
    #  INPUTS
    #  x         : [vector] (1 x t_end) data dx=diff[x]
    #  l_        : [scalar] fractional integration process is approximated considering the first l_ terms of its Taylor expansion
    #  d0        : [scalar] initial guess for the parameter d
    # OUTPUTS
    # d          : [scalar] estimate of d (where d+1 is the order of the fractional integration process)
    # epsFI      : [vector] (1 x t_end) residuals of the fractional integration process fit
    #             The operator (1+L)**{d} is computed by means of its Taylor expansion truncated at order l_(see the note below)
    # coeff      : [vector] (l_+1 x 1) first l_+1 coefficients (including coeff_0=1) are considered in the Taylor expansion
    #Note: If L is the lag operator the residuals are defined as eps = (1-L)**(1+d)X =(1-L)**d dX , where (1-L)**{d} \approx \sum_l=0**{l_} coeff_l L**l

    # options
    # if exist(OCTAVE_VERSION,builtin) == 0
    #     options = optimoptions(lsqnonlin, TolX, 10**-9, TolFun, 10**-9, MaxFunEvals, 1200, MaxIter, 400, Display, off)
    # else:
    #     options = optimset(TolX, 10**-9, TolFun, 10**-9, MaxFunEvals, 1200, MaxIter, 400, Display, off)

    lb = -0.5
    ub = 0.5
    res = least_squares(objective,d0,args=(dx,l_),bounds=(lb,ub),ftol=1e-9,xtol=1e-9)
    d, exitFlag, resNorm = res.x, res.status, None
    epsFI, coeff = FractIntegrProcess(d,dx,l_+1)

    return d, epsFI, coeff, exitFlag, resNorm

def objective(d, dx, l_):
    eps, _ = FractIntegrProcess(d,dx,l_)
    F = npsum(autocorrelation(eps,10)**2)
    return F

def FractIntegrProcess(d,x,l_):
    # estimate a fractional integration process
    #Compute the first l_ coeff and the approximated residuals of a Fractional Integration Process of order d+1

    t_ = x.shape[0]
    l = arange(1,l_)
    coeff = ones((1,l_))
    coeff[0,1:l_] = (-1)**l*gamma(1+d)/gamma(l+1)/gamma(1+d-l)

    eps = zeros((1,t_-l_+1))
    for t in range(l_,t_):
        if t==l_:
            LX = x[t-1::-1]
        else:
            LX = x[t-1:t-l_-1:-1]
        eps[0,t-l_] = coeff@LX.T
    return eps, coeff


import numpy as np

EXAMPLE=3

if EXAMPLE==1:
    '''
    The trasition matrix defines the Markov Chain. If you change to higher dimentions and want to start from
    a state diferent from 0, then you should change the dimension of variables v and state, accordingly.
    '''
    Transition=np.array([\
                [0.5,0.3,0.1,0.1],\
                [0.05,0.45,0.4,0.1],\
                [0.25,0.35,0.3,0.1],\
                [0.4,0.1,0.25,0.25]
                ])#Reminder: the sum of each row sums up to 1.

if EXAMPLE==2:
    '''
    The trasition matrix defines the Markov Chain. If you change to higher dimentions and want to start from
    a state diferent from 0, then you should change the dimension of variables v and state, accordingly.
    '''
    Transition=np.array([\
                [0.2,0.7,0.1],\
                [0,0,1],\
                [1,0,0]\
                ])#Reminder: the sum of each row sums up to 1.

'''
Generate a random Markov Chain (with N_dim #states) and see if it reaches equilibrium (the most probable scenario is that it will, since I generate random rows
with numbers that add up to 1)
'''
N_dim=5
if EXAMPLE==3:
    Transition=np.random.dirichlet(np.ones(N_dim),N_dim)

#=============================================================Begin
#Number of steps in both the Iteration and Simulation.
N_tot=5000
#Doing the following you start at state 0 automatically.
len_T=len(Transition[0])
init_s=np.zeros(len_T)
init_s[0]=1

'''
Iterative solution to w.P=w.
Iteratively find w^{(n)}=w^{(0)}.P^{(n+1)}.
'''
#v=[1,0,0,0]#play around with this (the final result should not change as long as the v.v=1)
v=init_s[:]#start at state 0 automatically

'''
Simulation.
Simulate the Markov Chain
'''
#state=[1,0,0,0]#This is the initial sate vector, which indicates the current state. e.g [1,0,0] indicates that the system is in state 0 (I start counting from 0).
state=init_s[:]#start at state 0 automatically
_visits=np.zeros(len(state))

for i in np.arange(N_tot):

    '''
    Iterative solution:
    Calculate v^{(n+1)}=P^{T}v^{(n)}
    '''
    v=np.dot(Transition.T,v)

    '''
    Simulation:
    The next state in the simulation is determined by the multinomial distribution,
    which is included in numpy ( you can find how to samlpe from the multinomial in misc/multinomial.py ).
    '''
    state= np.random.multinomial(1,np.dot(Transition.T,state))
    _visits+=state#Fortunately, all notations click together. Since states are defined in "binary", we can add them up to obtain the number of visits for each state.

print( "iterative=", v)

s=np.array(_visits)/float(N_tot)
print( 'simulation=', s)#probabilities is the fraction of visits over time.

print( r"Maximum discrepancy:" , np.max(np.abs(v-s))/np.max(np.abs(v)) , r"%" )

#=============================================================Done

#


'''
Write a short Python function that takes a positive integer n and returns
the sum of the squares of all the positive integers smaller than n.
'''

import numpy as np

def squaresum(a: int):
    arr = np.arange(a) * np.arange(a)
    arr = np.sum(arr)
    return arr

'''
Write a short Python function that takes a positive integer n and returns
the sum of the squares of all the odd positive integers smaller than n.
'''

def squaresumodds(a: int):
    arr = np.arange(a) * np.arange(a)
    i = 0
    res = []
    while i < len(arr):
        if bool(arr[i]&(1<<0)):
            res.append(1)
        else:
            res.append(0)
        i += 1
    arr = arr * np.array(res)
    arr = np.sum(arr)
    return arr

'''
The sum of the squares of the first ten natural numbers is,

The square of the sum of the first ten natural numbers is,

Hence the difference between the sum of the squares of the first ten natural numbers and the square of the sum is .

Find the difference between the sum of the squares of the first one hundred natural numbers and the square of the sum.

'''
def sumsquaredif(a: int):
    sum_squares = squaresum(a)
    arr = np.arange(a)
    arr = np.sum(arr)*np.sum(arr)
    return (arr - sum_squares)

def main():
    a = 101
    print('a vector: ', np.arange(a))
    print('sum of squares of a: ', squaresum(a))
    print('sum of squares of odds of a: ', squaresumodds(a))
    print('difference between sum of squares: ', sumsquaredif(a))

if __name__=='__main__':
    main()


#!/usr/bin/env python3
"""
Markov Module
"""
import numpy as np

def markov_chain(P, s, t=1):
    """
    Determines the probability of a markov chain being in a particular state
    after a specified number of iterations:

    P is a square 2D numpy.ndarray of shape (n, n) representing the transition
    matrix
        P[i, j] is the probability of transitioning from state i to state j
        n is the number of states in the markov chain
    s is a numpy.ndarray of shape (1, n) representing the probability of
    starting in each state
    t is the number of iterations that the markov chain has been through

    Returns: a numpy.ndarray of shape (1, n) representing the probability of
    being in a specific state after t iterations, or None on failure
    """
    if type(P) is not np.ndarray or len(P.shape) != 2:
        return None
    if type(s) is not np.ndarray or len(s.shape) != 2:
        return None
    if P.shape[0] != P.shape[1] or s.shape[0] != 1:
        return None
    if P.shape[0] != s.shape[1]:
        return None
    if type(t) is not int or t <= 0:
        return None
    if np.sum(P, axis=1).all() != 1:
        return None
    if np.sum(s) != 1:
        return None

    st = np.linalg.matrix_power(P, t)
    sm = np.matmul(s, st)
    return sm


from math import *

import scipy.constants as sc

def simpsons_rule(f, a, b):
    c = (a + b) / 2.0
    h3 = abs(b - a) / 6.0
    return h3 * (f(a) + 4.0 * f(c) + f(b))

def recursive_asr(f, a, b, eps, whole):
    c = (a + b) / 2.0
    left = simpsons_rule(f, a, c)
    right = simpsons_rule(f, c, b)
    if abs(left + right - whole) <= 15 * eps:
        return left + right + (left + right - whole) / 15.0
    return recursive_asr(f, a, c, eps / 2.0, left) + recursive_asr(f, c, b, eps / 2.0, right)

def adaptive_simpsons_rule(f, a, b, eps):
    return recursive_asr(f, a, b, eps, simpsons_rule(f, a, b))

def f(x):
    return x ** 3 / (exp(x) - 1)

Ans = adaptive_simpsons_rule(f, 0 + 10 ** -10, 100, 10 ** -10)

stefan = Ans * sc.Boltzmann ** 4 / 4 / pi ** 2 / sc.speed_of_light ** 2 / sc.hbar ** 3
print(stefan, 'value from program')
print(sc.Stefan_Boltzmann, 'Actural value')

Ankit Khandelwal_HW2/exercise 4/exercise 4.py


"""
Mapping between Ternary and Cartesian Coordinates.

Functions for converting ternary coordinates into cartesian system used in Matplotlib and vice-versa. All the values will be scaled so that the side length of the triangle is equal to one.
"""

import numpy as np

# Define constants to avoid code repetitions
_sqrt3 = np.sqrt(3.)
_half_sqrt3 = _sqrt3 / 2.

# Ternary to Cartesian Mapping
def ternaryToCartesian(coordinates):
    """
    Maps ternary coordinates to cartesian coordinates.

    Consider an equilateral ternary plot where a = 1 is placed at (0,0) and b = 1 is placed at (1,0). Then c = 1 will be at (1/2, sqrt(3)/2).
    The 3-tuple (a,b,c) will have the cartesian coordinates (b+c/2, sqrt(3)c/2, z), where a+b+c = 1.

    Parameters
    ----------
    coordinates: list / tuple / numpy array of size three
                 The coordinates to be converted from ternary to cartesian

    Returns
    -------
    numpy array of size two
    """
    return(np.array([(coordinates[1] + coordinates[2] / 2.), (_half_sqrt3 * coordinates[2])]))

# Cartesian to Ternary Mapping
def cartesianToTernary(coordinates, sigma = 1.):
    """
    Maps cartesian coordinates to ternary coordinates.

    Mapping from cartesian to ternary coordinates requires an additional equation. If the sum of the ternary coordinates is known (say n), one can use the equations
    for ternary to cartesian mapping and a+b+c = n to get (x-y/sqrt(3), 2y/sqrt(3), n-a-b)

    Parameters
    ----------
    coordinates: list / tuple / numpy array of size two
                The coordinates to be converted from cartesian to ternary

    sigma: Real
            Sum of (a, b, c) that the ternary coordinates should sum to.

    Returns
    -------
    numpy array of size three
    """
    c = coordinates[1] / _half_sqrt3
    b = coordinates[0] - c / 2.
    a = sigma - (b + c)
    return(np.array([a,b,c]))


import numpy as np

def tilde_w(w, dt):
    return (2./dt)*np.arcsin(w*dt/2.)

def plot_frequency_approximations():
    w = 1  # relevant value in a scaled problem
    stability_limit = 2./w
    dt = np.linspace(0.2, stability_limit, 111)  # time steps
    series_approx = w + (1./24)*dt**2*w**3
    P = 2*np.pi/w  # one period
    num_timesteps_per_period = P/dt  # more instructive
    import scitools.std as plt
    plt.plot(num_timesteps_per_period, tilde_w(w, dt), 'r-',
             num_timesteps_per_period, series_approx, 'b--',
             legend=('exact discrete frequency', '2nd-order expansion'),
             xlabel='no of time steps per period',
             ylabel='numerical frequency')
    plt.savefig('discrete_freq.png')
    plt.savefig('discrete_freq.pdf')

plot_frequency_approximations()


import numpy as np
from sklearn import linear_model, datasets
import matplotlib.pyplot as plt

def onehot(y):
    n = len(np.unique(y))
    m = y.shape[0]
    b = np.zeros((m, n))
    for i in xrange(m):
        b[i, y[i]] = 1
    return b

def softmax(X):
    return (np.exp(X).T / np.sum(np.exp(X), axis=1)).T

def h_func(theta, X):
    h = np.dot(np.c_[np.ones(X.shape[0]), X], theta)
    return softmax(h)

def h_gradient(theta, X, y, lam=0.1):
    n = X.shape[0]
    y_mat = onehot(y)
    preds = h_func(theta, X)
    return -1./n * np.dot(np.c_[np.ones(n), X].T, y_mat - preds) + lam * theta

def softmax_cost_func(theta, X, y, lam=0.1):
    n = X.shape[0]
    y_mat = onehot(y)
    return -1./n * np.sum(y_mat * np.log(h_func(theta, X))) + lam/2. * np.sum(theta * theta)

# gradient descent
def softmax_grad_desc(theta, X, y, lr=.01, converge_change=.0001, max_iter=100, lam=0.1):
    # normalize
    #X = (X - np.mean(X, axis=0)) / np.std(X, axis=0)

    cost_iter = []
    cost = softmax_cost_func(theta, X, y, lam=lam)
    cost_iter.append([0, cost])
    change_cost = 1
    i = 1
    while change_cost > converge_change and i < max_iter:
        pre_cost = cost
        theta -= lr * h_gradient(theta, X, y)
        cost = softmax_cost_func(theta, X, y)
        cost_iter.append([i, cost])
        change_cost = abs(pre_cost - cost)
        i += 1
    return theta, np.array(cost_iter)

def softmax_pred_val(theta, X):
    probs = h_func(theta, X)
    preds = np.argmax(probs, axis=1)
    return probs, preds

def softmax_regression():
    # Load the diabetes dataset
    dataset = datasets.load_digits()

    # Use all the features
    X = dataset.data[:, :]
    y = dataset.target[:, None]

    # Gradiend Descent
    theta = np.random.rand(X.shape[1]+1, len(np.unique(y)))
    fitted_val, cost_iter = softmax_grad_desc(theta, X, y, lr=0.01, max_iter=1000, lam=0.1)
    probs, preds = softmax_pred_val(fitted_val, X)

    #print(fitted_val)
    print(cost_iter[-1,:])
    print('Accuracy: {}'.format(np.mean(preds[:, None] == y)))

    plt.plot(cost_iter[:, 0], cost_iter[:, 1])
    plt.ylabel("Cost")
    plt.xlabel("Iteration")
    plt.show()

def main():
    softmax_regression()

if __name__ == "__main__":
    main()


#!/usr/bin/python3
# reflection.py

import sys
import os
import numpy as np

class Reflection:
    """
    Class for calculating the reflection of a, through the orthogonal matrix of v.

    ...

    Attributes
    ----------
    v: numpy array
        vector, shape(m,1), to initialize the Housholder transformation matrix.

    Methods
    -------
    __mul__(a)
        Transforms the vector a using the Housholder transformation
        H = I - 2((vv(T)) / |v|**2).
    """

    def __init__(self, v):
        """
        Vector v shape(m,1), to initialize the Housholder transformation.
        """

        self.v = v

    def __mul__(self, a):
        """
        Transforms the vector a using the Housholder transformation H = I - 2((vv(T)) / |v|**2).

        Calculate the matrix product for the
        reflection of vector a orthogonal matrix H.
        The dimension of a needs to be bigger or equal
        to the dimesion of v.
        If the dimension of v is smaller than the dimension of a,
        v can be filled with zeros.

        Parameters
        ----------
        a: numpy array
            vector, shape(m,1) input vector to be transformed.

        Returns
        -------
        reflection: numpy array
            vector, shape(m,1), a reflected through H.
        """

        if len(a) < len(self.v):
            raise Exception('Length of a is smaller than length of v!')
        elif len(a) > len(self.v):
            differenceav = (len(a) - len(self.v))
            add = np.zeros(differenceav)
            velong = np.insert(self.v,0,add).reshape(len(a),1) # add zeros at the end
            self.v = velong
        else:
            self.v = self.v

        gamma = ((np.linalg.norm(self.v))**2)/2
        vvtrans = self.v * np.transpose(self.v)
        H =  np.identity((len(a))) - (vvtrans/gamma)
        reflection = np.dot(H,a)

        return(reflection)


import random

import numpy as np

class Sudoku:
    def __init__(self, sudoku=None):
        self.sudoku = sudoku

    def is_valid(self, r: int, c: int, v: int) -> bool:
        """Check if sudoku[r,c] can be value v"""
        if (
            v in self.sudoku[r, :]
            or v in self.sudoku[:, c]
            or v
            in self.sudoku[r // 3 * 3 : r // 3 * 3 + 3, c // 3 * 3 : c // 3 * 3 + 3]
        ):
            return False
        return True

class SudokuSolver(Sudoku):
    """Sudoku solver class"""

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    def sudoku_solver_backtrack(self, r: int = 0, c: int = 0) -> np.array:

        if c == 9:
            return self.sudoku_solver_backtrack(r + 1, 0)

        if r == 9:
            return self.sudoku

        if self.sudoku[r, c] != 0:
            return self.sudoku_solver_backtrack(r, c + 1)

        for i in range(1, 10):
            if self.is_valid(r, c, i):
                self.sudoku[r, c] = i
                solution = self.sudoku_solver_backtrack(r, c + 1)
                if solution is not False:
                    return solution

            self.sudoku[r, c] = 0
        return False

class SudokuGenerator(SudokuSolver):
    """Sudoku generator class"""

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    def sudoku_generator_backtrack(self, sudoku: np.array, level: int) -> np.array:
        """Use backtrack solver to generate sudoku"""

        res = sudoku.copy()

        remove_value = []

        while len(remove_value) < 81 - level:

            while True:
                r, c = random.randrange(0, 9), random.randrange(0, 9)
                if (r, c) not in remove_value:
                    break

            res[r, c] = 0

            self.sudoku = res.copy()
            if self.sudoku_solver_backtrack(0, 0) is not False:
                remove_value.append((r, c))
                res[r, c] = 0
        return res

    def sudoku_generator(self, seed, level: int) -> None:
        """sudoku generator"""

        assert level >= 17, "Level should >=17 to have unique solution!"

        while True:
            sudoku = np.zeros([9, 9], dtype=int)

            for i in range(3):
                seed = hash(str(seed))
                random.seed(seed)
                nums = [x for x in range(1, 10)]
                random.shuffle(nums)

                for j in range(3):
                    sudoku[3 * i + j, 3 * i : 3 * i + 3] = nums[3 * j : 3 * j + 3]

            self.sudoku = sudoku
            sudoku = self.sudoku_solver_backtrack(0, 0)
            if sudoku is not False:
                break
        random.seed(seed + level)
        self.sudoku = self.sudoku_generator_backtrack(sudoku, level)


"""
implementation of gradient descent
n the solution of the linear equation
https://en.wikipedia.org/wiki/Gradient_descent#Solution_of_a_linear_system
"""

import numpy as np
from tqdm import trange

def cost_function(y_true, y_pred):
    """Computes the cost of linear regression
    """
    n, _ = y_true.shape
    cost = 1 / (2 * n) * np.sum((y_true - y_pred) ** 2)
    return cost

def normalize(X):
    """Returns a normalized version of X where
    the mean value of each feature is 0
    and the standard deviation is 1
    """
    # calculate mean value along zero axis
    X_mean = np.mean(X, axis=0)
    # calculate standard deviation along zero axis
    X_std = np.std(X, axis=0)
    # Standard scaler
    # z = (x - mu) / sigma
    X_norm = (X - X_mean) / X_std
    return X_norm, X_std

def gradient_descent(X, y, theta=None, alpha=0.05, num_epoch=10, verbose=True):
    """Performs gradient descent to learn theta
    by taking n steps
    """
    n, m = X.shape
    if theta is None:
        # set theta as random weights
        theta = np.random.rand(m + 1, 1)
    # add intercept value to X
    X0 = np.concatenate([np.ones((n, 1)), X], axis=1)
    # set dict with costs values
    cost = {}
    t = trange(num_epoch)
    for epoch in t:
        # set new theta value
        # theta = theta - alpha * 1 / m * X' * (X * theta - y)
        theta = theta - alpha * 1 / n * X0.T @ (X0 @ theta - y)
        # calculate predicted value with new theta
        y_pred = X0 @ theta
        # calculate cost value
        cost[epoch] = cost_function(y, y_pred)
        if verbose:
            t.set_description(
                "epoch: {:4d} cost: {:.4f}".format(epoch, cost[epoch]))
    return theta

def inverse_transform(theta_normalize, X, X_std):
    """transform theta normilize to original feature space
    """
    n = X_std.shape[0]
    # rescale theta
    theta_rescaled = (theta_normalize.flatten()[1:] / X_std).reshape((n, 1))
    # get predictions
    y_pred = X @ theta_rescaled
    # calculate mean bias values
    theta_0 = (y - y_pred).mean()
    # concatenate
    theta = np.concatenate([[[theta_0]], theta_rescaled], axis=0)
    return theta

if __name__ in '__main__':
    # set X vector
    X = np.array([
        [-1, 0],
        [1, 100],
        [2, 200],
        [3, 300],
        [4, 400],
        [5, 500],
    ])
    # set y based on equation y = 5 + X0 * 20 + X1 * 1
    theta_true = np.array([
        [5.], [20.], [1.]
        ])
    y = X @ theta_true[1:, :] + theta_true[0, :]
    print("X:\n{}".format(X))
    print("y:\n{}".format(y))
    # transfom all components in X to normalize view
    # for proper working of the gradient descent
    X_normalize, X_std = normalize(X)
    # obtaine theta (normalize) vector using gradient descent algorithm
    theta_normilize = gradient_descent(
        X_normalize, y, alpha=0.1, num_epoch=10000, verbose=True)
    # convert theta normilize to original feature space
    theta = inverse_transform(theta_normilize, X, X_std)
    print("\n\n")
    print("theta:\n{}".format(theta))
    print("theta_true:\n{}".format(theta_true))


import pandas as pd
import numpy as np
import math
import pdb

def average(series):
    a1 = sum(series)
    b1 = len(series)
    c1 = a1/b1
    """
    print(c1)
    """

    return c1
    """
    implements the average of a pandas series from scratch
    suggested functions:
    len(list)
    sum(list)
    you should get the same result as calling .mean() on your series
    https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.mean.html
    See numpy documenation for implementation details:
    https://docs.scipy.org/doc/numpy/reference/generated/numpy.mean.html
    """
    """
        things = [1,3,5,7,9]
        average(things)
    """
def standard_deviation(series):
    a1 = average(series)
    sum1 = 0
    for i in range(0,len(series)):
        sum1 = sum1 + (series[i]-a1)**2
    b1 = sum1 / (len(series)-1)
    c1 = math.sqrt(b1)
    """
    print(c1)
    """
    return c1

    """
    implements the sample standard deviation of a series from scratch
    you may need a for loop and your average function
    also the function math.sqrt
    you should get the same result as calling .std() on your data
    https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.std.html
    See numpy documenation for implementation details:
    https://docs.scipy.org/doc/numpy/reference/generated/numpy.std.html

    """
    """
    things = [1,3,5,7,9]
    standard_deviation(things)
    print(np.std(things))
    """

def bubbleSort(arr):
    n = len(arr)
    for i in range(n):
        for j in range(0, n-i-1):
            if arr[j] > arr[j+1] :
                arr[j], arr[j+1] = arr[j+1], arr[j]
    return arr

def median(series):
    """
    finds the median of the series from scratch
    you may need to sort your values and use
    modular division
    this number should be the same as calling .median() on your data
    See numpy documenation for implementation details:
    https://docs.scipy.org/doc/numpy/reference/generated/numpy.median.html
    https://pandas.pydata.org/pandas-docs/version/0.23.0/generated/pandas.Series.median.html
    """
    a1 = bubbleSort(series)
    print(a1)
    b1 = len(a1)
    med = 0
    if b1%2 == 0:
        med = (a1[b1/2]+a1[b1/2 + 1])/2

    else:
        med = (a1[b1//2])
    return med
    """
    things = [3,5,9,7,1]
    median(things)
    """


import numpy as np
import matplotlib.pyplot as plt
plt.style.use('seaborn-whitegrid')

def f(x) :

    s = np.power(x,3)  - x - 1

    return s

def f_p(x):

    s = 3*np.power(x,2)  - 1

    return s

def Newton_Raphson(x0,Tol,Nmax) :

    x=x0 - f(x0)/f_p(x0)
    e=abs(x-x0)
    n=1
    while n < Nmax and e > Tol :
          x0 = x
          x = x0 - f(x0)/f_p(x0)
          e=abs(x-x0)
          n += 1

    return x,n,f(x)

#------------ MAIN PROGRAMME -------------#

x0=1.5 ;Tol=10**(-8) ;Nmax=100
x,n,fx = Newton_Raphson(x0,Tol,Nmax)

print ('Approximate Solution is ' , x )
print ('number of steps is ' , n)
print ('Value at approximate solution is ' , fx)

t=np.linspace(0,2,100)
y=f(t)

plt.plot(t,y,'grey')
plt.legend(['f(x)'])
plt.ylabel('y')
plt.xlabel('x')
plt.show()


#################################################################################
#        DERIVATIVE ERROR ESTIMATION AND THE RICHARDSON EXTRAPOLATION METHOD
#    This program computes:
#    1) the Richardson derivative of f(x) = sin(x) at x = 1 using an adaptative scheme,
#    2) for a relative error < 1e-7,
#
#    (Marina von Steinkirch, spring 2013)
#
#################################################################################

import math
import numpy
import pylab

""" Functions """

def func(x):
    """ the function to be plotted """
    fx = numpy.sin(x)
    return fx

def fprime(x):
    """ the analytic derivative of func(x) """
    fp = numpy.cos(x)
    return fp

def machine_precision():
    """ calculates the machine precision, 2*eps"""
    x = 1.0
    eps = 1.0
    while (not x + eps == x):
        eps = eps/2.0
    return 2.0*eps

def delta1(h, x):
    """ calculates the second-order centered difference """
    d1 = (func(x+h) - func(x-h))/(2.0*h)
    return d1

def relative_error(fa, fn):
    """ calculates the relative error """
    e = abs( ( fa - fn ) / fa )
    return e

def absolute_error(fa, fn):
    """ calculates the relative error """
    e = abs(  fa - fn  )
    return e

def richardson_derivative(h, x):
    """ calculate the derivative using delta1 for h and h/2 """
    d = delta1(h, x)
    h = h/2
    d1 = delta1(h, x)
    f1 =  (4*d1-d)/3

    # MZ -- why is there an h**2 here?
    epsilon = h*h*abs(d-d1)
    return f1, epsilon

def printing(n, h, f1, fp, e, er, ea):
    print "\n________________________________________________________________________________"
    print "Iteration n = ", int(n)
    print "The distance between two points in this grid (h) is:    ", h
    print "Calculated (Richardsob) Derivative of f(x)=sin(x) at x = 1:    ", f1
    print "Analytic First Derivative of f(x)=sin(x) at x = 1:    ", fp
    print "Truncated Error (from the Taylor approx):    ", e
    print "Relative Error:    ", er
    print "Absolute Error:    ", ea
    return 0

""" Variables """

CONST_EPS = 10**(-6)            # relative error
CONST_XL = 0.0              # most left point
CONST_XR = math.pi          # most right point: 3.14 > x=1,
CONST_X = 1.0               # point where we are calculating the derivative

h_array = []
er_array = []
ea_array = []
epsilon_array = []

epsilon = 1.1*10**(-6)
n = 0.0

""" Main Program """
while (epsilon >= CONST_EPS):
    n += 1
    h = abs((CONST_XR - CONST_XL)/(2*float(n)))        # distance in the grid

    # MZ -- the error you are asked to monitor is the error between
    # the difference with h and the one with h/2
    f1, epsilon = richardson_derivative(h, CONST_X)
    error_r = relative_error(f1, fprime(CONST_X))
    error_a = absolute_error(f1, fprime(CONST_X))

    printing(int(n), h, f1, fprime(CONST_X), epsilon, error_r, error_a)

    h_array.append(h)
    er_array.append(error_r)
    ea_array.append(error_a)
    epsilon_array.append(epsilon)

""" Plotting the Errors vs h """
pylab.loglog(h_array, er_array, 'go',  label="Relative Error")
pylab.loglog(h_array, ea_array, 'r*',  label="Absolute Error")
pylab.loglog(h_array, epsilon_array,'b--',  label="Truncated Error $O(h^4)$")

leg = pylab.legend(loc=4,labelspacing=0.1)
ltext = leg.get_texts()
pylab.setp(ltext, fontsize='small')
leg.draw_frame(1)

pylab.xlabel('Log( Griding Distance h)')
pylab.ylabel('Log (Error)')
pylab.grid(True)

pylab.savefig("der_error.png")

""" Plotting the Errors vs n """
pylab.clf()
pylab.cla()
nlist = list(range(1, int(n)+1, 1))
pylab.loglog(nlist, er_array, 'go',  label="Relative Error")
pylab.loglog(nlist, ea_array, 'r*',  label="Absolute Error")
pylab.loglog(nlist, epsilon_array,'b--',  label="Truncated Error $O(h^4)$")

leg = pylab.legend(loc=1,labelspacing=0.1)
ltext = leg.get_texts()
pylab.setp(ltext, fontsize='small')
leg.draw_frame(1)

pylab.xlabel('Log (Number of Steps n)')
pylab.ylabel('Log (Error)')
pylab.grid(True)

pylab.savefig("der_error2.png")

print "\nMachine precision: ", machine_precision()
print "Done!"


#!/usr/bin/python3

"""
The riddle:
Given an array of N integer numbers, where all the numbers appear an even
amount of time except for a single number that appears an odd amount of times.
Find the number that appears an odd amount of times in the array, using O(1) memory space
and O(N) running time efficiency.

Some examples:
[2,2,1] --> 1
[14,14,14,14,4,4,4] --> 4
[1,2,1,4,2,4,5,1,1] --> 5

"""

import numpy as np

N = 2000

def solution(arr):
  """
	Apply xor on all of the numbers, numbers that appear even amount of times cancel themselves
	using xor and the only number that appear an odd amount of times stays.

	@param List[int] arr : the array as described in the riddle documentation.
	@return int : the unique odd number.
  """
  if len(arr) == 0:
    raise ValueError('Wrong input format')
  stored = arr[0]   # O(1) space for integer storage
  for number in arr[1:]:  # linear traverse (O(N))
    stored ^= number
  return stored

def generate_random_test_array(n=N):
  """ returns a random array that fits the input requirements and the expected
      solution for that generated array. """
  assert n > 1
  half = np.random.randint(100, size=n//2)
  odd = half[0]
  full = np.hstack((half, half, [odd]))
  np.random.shuffle(full)
  return full, odd

def test_solution():
  if not solution([2,2,1]) == 1:
    return False
  if not solution([14,14,14,14,4,4,4]) == 4:
    return False
  if not solution([1,2,1,4,2,4,5,1,1]) == 5:
    return False
  for _ in range(10):
    arr, expected = generate_random_test_array()
    if not solution(arr) == expected:
      return False
  return True


import sympy
from typing import Tuple

x = sympy.symbols('x')

def bisection_root_finder(eqn: sympy.Basic, low: float, high: float, tolerance: float) -> Tuple[float, int, float]:
    """
    Given a single-variable sympy equation with x as the defined symbol, the low end of an interval, the high end of the interval,
    and the tolerance, it will calculate the root contained in the interval using the bisection method.
    It returns a tuple containing the root and the iterations taken

    If it takes more than 100 iterations, it breaks and returns early
    """
    root = 0

    if eqn.evalf(subs={x: root}) == 0:
        return root
    low_answer = eqn.evalf(subs={x: low})
    high_answer = eqn.evalf(subs={x: high})

    root = (low + high)/2
    iterations = 0

    while high-low > tolerance:
        low_answer = eqn.evalf(subs={x: low})
        high_answer = eqn.evalf(subs={x: high})

        if low_answer*high_answer >= 0:  # They're both on the same side of the axis, this is an issue
            return None
        else:
            mid = (low+high)/2
            root = mid
            if high_answer * eqn.evalf(subs={x: mid}) >= 0:
                high = mid
            else:
                low = mid
        iterations += 1
        if iterations > 100:
            break
    return root, iterations

def newton_raphson_root_finder(equation: sympy.Basic, first_guess: float, tolerance: float) -> Tuple[float, int]:
    """
    Given a single-variable sympy equation with x as the defined symbol, an initial guess, and a tolerance,
    this function will return a tuple containing the root and the iterations taken to find the root.
    It uses the Newton-Raphson method to find the root.
    """
    error = 1_000  # Starting with a high initial error
    x_o = first_guess
    f = equation
    f_prime = sympy.diff(equation, x)
    iterations = 0
    while error > tolerance:
        root = x_o - f.evalf(subs={x: x_o}, chop=True) / f_prime.evalf(subs={x: x_o}, chop=True)
        error = abs(root - x_o)
        x_o = root
        iterations += 1
    return root, iterations

def secant_root_finder(eqn: sympy.Basic, x0: float, x1: float, tolerance: float) -> Tuple[float, int]:
    """
    Given a sympy equation with x as the symbol, two initial guesses on the x-axis and a tolerance,
    It will find the root using the secant method

    Returns tuple containing root, number of iterations taken
    """
    error = 1_000  # High initial error
    iterations = 0

    while error > tolerance:
        # Calculating slope of the line between the two points
        slope = (eqn.evalf(subs={x: x1}) - eqn.evalf(subs={x: x0})) / (x1 - x0)

        # Calculating the next point
        root = x0 - ((eqn.evalf(subs={x: x0}))/slope)

        # Prep for next iteration
        error = abs(x0 - root)
        x0 = x1
        x1 = root
        iterations += 1
    return root, iterations


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

### Defining theta
theta = math.pi/4

### Generates count number of random values in the range [0, 1]
def getU(count):
	u = []
	for i in range(count):
		key = random.rand()
		u.append(key)

	return u

def getX(u):
	x = []
	for t in u:
		res = 0.50 - 0.50*math.cos(math.pi*t)
		x.append(res)

	return x

def getSampleMeanVariance(x):
	sum = 0.00
	for i in x:
		sum += i

	avg = sum/(len(x))

	cnt = 0.00
	for i in x:
		cnt += (i-avg)**2

	variance = cnt/(len(x)-1)
	return avg, variance

def plotCDF(data):
	data_size = len(data)

	data_set = sorted(set(data))
	bins = np.append(data_set, data_set[-1]+1)

	counts, bin_edges = np.histogram(data, bins=bins, density=False)

	counts = counts.astype(float)/data_size

	cdf = np.cumsum(counts)

	plt.plot(bin_edges[0:-1], cdf, linestyle='--', marker='o', color='b')
	plt.ylim((0, 1))
	plt.ylabel("CDF")
	plt.grid(True)

	plt.show()

# Plots y = (2/pi) arc sin(root(x))
def plotActualDistributionFunction():
	in_array = np.linspace(-1.00, 1.00, 10000)
	out_array = np.arcsin(in_array)

	# print("in_array : ", in_array)
	# print("\nout_arraywith arcsin : ", out_array)

	# red for numpy.arcsin()
	plt.plot(in_array, out_array,
	            color = 'blue', marker = "*")

	plt.title("Y = F(x)")
	plt.xlabel("X")
	plt.ylabel("Y")
	plt.show()

def execute(cnt):
	print("For input size of : " + str(cnt))
	u = getU(cnt)
	u.sort()
	# print(u)
	x = getX(u)
	# print(x)

	sMean, sVariance = getSampleMeanVariance(x)
	print("Sample Mean: " + str(sMean))
	print("Sample Variance: " + str(sVariance))
	print()
	plotCDF(x)

def main():
	plotActualDistributionFunction()

	execute(10)
	execute(100)
	execute(1000)
	execute(10000)
	execute(100000)

if __name__ == '__main__':
	main()


import numpy as np

#creating arrays
array = np.zeros(10, dtype='int')
# array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
# print(array)

#creating a 3 row x 5 column matrix
array = np.ones((3,5), dtype=float)
# array([[ 1.,  1.,  1.,  1.,  1.],
#       [ 1.,  1.,  1.,  1.,  1.],
#       [ 1.,  1.,  1.,  1.,  1.]])
# print(array)

#creating a matrix with a predefined value
array = np.full((3,5),1.23)
# array([[ 1.23,  1.23,  1.23,  1.23,  1.23],
#       [ 1.23,  1.23,  1.23,  1.23,  1.23],
#       [ 1.23,  1.23,  1.23,  1.23,  1.23]])
# print(array)

#create an array with a set sequence
array = np.arange(0, 20, 2)
# array([0, 2, 4, 6, 8,10,12,14,16,18])
# print(array)

#create an array of even space between the given range of values
array = np.linspace(0, 1, 5)
# array([ 0., 0.25, 0.5 , 0.75, 1.])
# print(array)

#create a 3x3 array with mean 0 and standard deviation 1 in a given dimension
array = np.random.normal(0, 1, (3,3))
# array([[ 0.72432142, -0.90024075,  0.27363808],
#       [ 0.88426129,  1.45096856, -1.03547109],
#       [-0.42930994, -1.02284441, -1.59753603]])
# print(array)

#create an identity matrix
array = np.eye(3)
# array([[ 1.,  0.,  0.],
#       [ 0.,  1.,  0.],
#       [ 0.,  0.,  1.]])

#set a random seed
np.random.seed(0)
x1 = np.random.randint(10, size=6) #one dimension
x2 = np.random.randint(10, size=(3,4)) #two dimension
x3 = np.random.randint(10, size=(3,4,5)) #three dimension
print("x3 ndim:", x3.ndim)
print("x3 shape:", x3.shape)
print("x3 size: ", x3.size)
# ('x3 ndim:', 3)
# ('x3 shape:', (3, 4, 5))
# ('x3 size: ', 60)
# ..............................................................................

# print the results at any level
print(array)


from matplotlib import pyplot
from numpy.random import normal
from numpy import hstack, exp, asarray
from sklearn.neighbors import KernelDensity
from mpl_toolkits.mplot3d import Axes3D
from scipy.stats import multivariate_normal

import numpy as np

def bimodalDist():
    sample1 = normal(loc = 20, scale = 5, size = 300)
    sample2 = normal(loc = 40, scale = 5, size = 700)

    sample = hstack((sample1, sample2))

    model = KernelDensity(bandwidth = 2, kernel = 'gaussian')
    sample = sample.reshape((len(sample), 1))
    model.fit(sample)

    values = asarray([value for value in range(1, 60)])
    values = values.reshape((len(values), 1))

    probabilities = model.score_samples(values)
    probabilities = exp(probabilities)

    pyplot.hist(sample, bins = 60, density = True)
    pyplot.plot(values[:], probabilities)
    pyplot.show()

    return None

def meshPlot():
    mu_x = 0
    var_x = 10.

    mu_y = 0
    var_y = 10.

    x = np.linspace(-10,10,500)
    y = np.linspace(-10,10,500)
    X, Y = np.meshgrid(x,y)
    pos = np.empty(X.shape + (2,))
    pos[:, :, 0] = X
    pos[:, :, 1] = Y

    rv = multivariate_normal([mu_x, mu_y],[[var_x,0],[0,var_y]])

    fig = pyplot.figure()
    ax = fig.gca(projection='3d')
    ax.plot_surface(X, Y, rv.pdf(pos), cmap='viridis', linewidth=0)

    ax.set_xlabel('X axis')
    ax.set_ylabel('Y axis')
    ax.set_zlabel('Z axis')
    pyplot.show()
    return None

def pdf(data, mean: float, variance: float):
    s = 1/(np.sqrt(2*np.pi*variance))
    s = s * (np.exp(-(np.square(data - mean)/(2*variance))))
    return s

def pdfClustering(X):
    k = 3
    weights = np.ones((k)) / k

    #k value will give the base for the cluster number
    means = np.random.choice(X, k)
    variances = np.random.random_sample(size=k)

    eps = 1e-8
    for step in range(25):

        pyplot.figure(figure=(10,6))
        axes = plt.gca()
        pyplot.xlabel("$x$")
        pyplot.ylable("pdf")
        pyplot.title("Iteration {}".format(step))
        pyplot.scatter(X, [0.] * len(X), color = 'navy', s = 30, marker = 2, label = "Train Data")

        pyplot.plot(bins, )

def gaussianModels():
    n_samples = 200
    mu1, sigma1 = -4, 1.2
    mu2, sigma2 =  4, 1.8
    mu3, sigma3 =  0, 1.6

    x1 = np.random.normal(mu1, np.sqrt(sigma1), n_samples)
    x2 = np.random.normal(mu2, np.sqrt(sigma2), n_samples)
    x3 = np.random.normal(mu3, np.sqrt(sigma3), n_samples)

    print(x1)
    print(x2)
    print(x3)

    X = np.array(list(x1) + list(x2) + list(x3))
    np.random.shuffle(X)
    print(X.shape)
    bins = np.linspace(np.min(X), np.max(X), 200)

    pyplot.figure(figsize=(10,7))
    pyplot.xlabel("$x$")
    pyplot.ylabel("pdf")
    pyplot.scatter(X, [0.005] * len(X), color='green', s=30, marker=2, label="Train data")

    pyplot.plot(bins, pdf(bins, mu1, sigma1), color='red', label="True pdf")
    pyplot.plot(bins, pdf(bins, mu2, sigma2), color='red')
    pyplot.plot(bins, pdf(bins, mu3, sigma3), color='red')

    pyplot.legend()
    pyplot.plot()
    pyplot.show()
    return X, bins, mu1, mu2, mu3, sigma1, sigma2, sigma3

if __name__ == '__main__':

    #meshPlot()
    #bimodalDist()
    data, bins, mu1, mu2, mu3, sigma1, sigma2, sigma3 = gaussianModels()
    pdfClustering(data)


# -*- coding:utf-8 -*-
# =========================================================================== #
# Project : MLStudio                                                          #
# File    : \regression.py                                                    #
# Python  : 3.8.3                                                             #
# --------------------------------------------------------------------------- #
# Author  : John James                                                        #
# Company : nov8.ai                                                           #
# Email   : jjames@nov8.ai                                                    #
# URL     : https://github.com/nov8ai/MLStudio                                #
# --------------------------------------------------------------------------- #
# Created       : Thursday, July 16th 2020, 2:25:57 am                        #
# Last Modified : Thursday, July 16th 2020, 2:25:58 am                        #
# Modified By   : John James (jjames@nov8.ai)                                 #
# --------------------------------------------------------------------------- #
# License : BSD                                                               #
# Copyright (c) 2020 nov8.ai                                                  #
# =========================================================================== #
import math
import numpy as np

from mlstudio.supervised.metrics.base import BaseRegressionMetric
# --------------------------------------------------------------------------- #
class ResidualSumSquaredError(BaseRegressionMetric):
    """Computes sum squared residuals given"""

    _mode  = 'min'
    _code = 'SSR'
    _name  = 'residual_sum_squared_error'
    _label  = "Residual Sum Squared Error"

    _best  = np.min
    _better  = np.less
    _worst  = np.Inf
    _epsilon_factor  = -1

    def __call__(self, y, y_pred, *args, **kwargs):
        e = y - y_pred
        return np.sum(e**2)

class TotalSumSquaredError(BaseRegressionMetric):
    """Computes total sum of squares"""

    _mode  = 'min'
    _code = "SST"
    _name  = 'total_sum_squared_error'
    _label  = "Total Sum Squared Error"

    _best  = np.min
    _better  = np.less
    _worst  = np.Inf
    _epsilon_factor  = -1

    def __call__(self, y, y_pred, *args, **kwargs):
        y_avg = np.mean(y)
        e = y-y_avg
        return np.sum(e**2)

class R2(BaseRegressionMetric):
    """Computes coefficient of determination."""

    _mode  = 'max'
    _code = "R2"
    _name  = 'R2'
    _label  = 'Coefficient of Determination (R2)'

    _best  = max
    _better  = np.greater
    _worst  = -np.Inf
    _epsilon_factor  = 1

    def __call__(self, y, y_pred, *args, **kwargs):
        self._ssr = ResidualSumSquaredError()
        self._sst = TotalSumSquaredError()
        r2 = 1 - (self._ssr(y, y_pred)/self._sst(y, y_pred))
        return r2

class AdjustedR2(BaseRegressionMetric):
    """Computes adjusted coefficient of determination."""

    _mode  = 'max'
    _code = "AR2"
    _name  = 'adjusted_r2'
    _label  = "Adjusted R2"

    _best  = max
    _better  = np.greater
    _worst  = -np.Inf
    _epsilon_factor  = 1

    def __call__(self, y, y_pred, n_features, *args, **kwargs):
        r2_scorer = R2()
        r2 = r2_scorer(y, y_pred)
        n = y.shape[0]
        p = n_features
        ar2 = 1 - (1 - r2) * (n-1) / (n-p-1)
        return ar2

class PercentVarianceExplained(BaseRegressionMetric):
    """Computes proportion of variance explained."""

    _mode  = 'max'
    _code = "PVE"
    _name  = 'percent_variance_explained'
    _label  = "Percent Variance Explained"

    _best  = max
    _better  = np.greater
    _worst  = -np.Inf
    _epsilon_factor  = 1

    def __call__(self, y, y_pred, *args, **kwargs):
        var_explained = 1 - (np.var(y-y_pred) / np.var(y))
        return var_explained * 100

class MeanAbsoluteError(BaseRegressionMetric):
    """Computes mean absolute error given data and parameters."""

    _mode  = 'min'
    _code = "MAE"
    _name  = 'mean_absolute_error'
    _label  = "Mean Absolute Error"

    _best  = np.min
    _better  = np.less
    _worst  = np.Inf
    _epsilon_factor  = -1

    def __call__(self, y, y_pred, *args, **kwargs):
        e = abs(y-y_pred)
        return np.mean(e)

class MeanSquaredError(BaseRegressionMetric):
    """Computes mean squared error given data and parameters."""

    _mode  = 'min'
    _code = "MSE"
    _name  = 'mean_squared_error'
    _label  = "Mean Squared Error"

    _best  = np.min
    _better  = np.less
    _worst  = np.Inf
    _epsilon_factor  = -1

    def __call__(self, y, y_pred, *args, **kwargs):
        e = y - y_pred
        return np.mean(e**2)

class NegativeMeanSquaredError(BaseRegressionMetric):
    """Computes negative mean squared error given data and parameters."""

    _mode  = 'max'
    _code = "NMSE"
    _name  = 'negative_mean_squared_error'
    _label  = "Negative Mean Squared Error"

    _best  = max
    _better  = np.greater
    _worst  = -np.Inf
    _epsilon_factor  = 1

    def __call__(self, y, y_pred, *args, **kwargs):
        e = y - y_pred
        return -np.mean(e**2)

class RootMeanSquaredError(BaseRegressionMetric):
    """Computes root mean squared error given data and parameters."""

    _mode  = 'min'
    _code = "RMSE"
    _name  = 'root_mean_squared_error'
    _label  = "Root Mean Squared Error"

    _best  = np.min
    _better  = np.less
    _worst  = np.Inf
    _epsilon_factor  = -1

    def __call__(self, y, y_pred, *args, **kwargs):
        e = y-y_pred
        return np.sqrt(np.mean(e**2))

class NegativeRootMeanSquaredError(BaseRegressionMetric):
    """Computes negative root mean squared error given data and parameters."""

    _mode  = 'max'
    _code = "NRMSE"
    _name  = 'negative_root_mean_squared_error'
    _label  = "Negative Root Mean Squared Error"

    _best  = max
    _better  = np.greater
    _worst  = -np.Inf
    _epsilon_factor  = 1

    def __call__(self, y, y_pred, *args, **kwargs):
        e = y-y_pred
        return -np.sqrt(np.mean(e**2))

class MeanSquaredLogError(BaseRegressionMetric):
    """Computes mean squared log error given data and parameters."""

    _mode  = 'min'
    _code = "MSLE"
    _name  = 'mean_squared_log_error'
    _label  = "Mean Squared Log Error"

    _best  = np.min
    _better  = np.less
    _worst  = np.Inf
    _epsilon_factor  = -1

    def __call__(self, y, y_pred, *args, **kwargs):
        e = np.log(y+1)-np.log(y_pred+1)
        y = np.clip(y, 1e-15, 1-1e-15)
        y_pred = np.clip(y_pred, 1e-15, 1-1e-15)
        e = np.log(y)-np.log(y_pred)
        return np.mean(e**2)

class MedianAbsoluteError(BaseRegressionMetric):
    """Computes median absolute error given data and parameters."""

    _mode  = 'min'
    _code = "MdAE"
    _name  = 'median_absolute_error'
    _label  = "Median Absolute Error"

    _best  = np.min
    _better  = np.less
    _worst  = np.Inf
    _epsilon_factor  = -1

    def __call__(self, y, y_pred, *args, **kwargs):
        return np.median(np.abs(y_pred-y))

class MeanAbsolutePercentageError(BaseRegressionMetric):
    """Computes mean absolute percentage given data and parameters."""
    _mode  = 'min'
    _code = "MAPE"
    _name  = 'mean_absolute_percentage_error'
    _label  = "Mean Absolute Percentage Error"

    _best  = np.min
    _better  = np.less
    _worst  = np.Inf
    _epsilon_factor  = -1

    def __call__(self, y, y_pred, *args, **kwargs):
        return 100*np.mean(np.abs((y-y_pred)/y))


# This pattern is the same for more inputs and weights. Weights and inputs have the same length
# inputs = [1, 2, 4]
# weights = [0.2, 0.8, -0.5]
# bias = 2

# output = inputs[0] * weights[0] + inputs[1] * weights[1] + inputs[2] * weights[2] + bias

# print(output)

# With multiple layers
# inputs = [1, 2, 3, 2.5]

# weights1 = [0.2, 0.8, -0.5, 1]
# weights2 = [0.5, -0.91, 0.26, -0.5]
# weights3 = [-0.26, -0.27, 0.17, 0.87]

# bias1 = 2
# bias2 = 3
# bias3 = 0.5

# outputs = [
#     # Neuron 1:
#     inputs[0] * weights1[0]
#     + inputs[1] * weights1[1]
#     + inputs[2] * weights1[2]
#     + inputs[3] * weights1[3]
#     + bias1,
#     # Neuron 2:
#     inputs[0] * weights2[0]
#     + inputs[1] * weights2[1]
#     + inputs[2] * weights2[2]
#     + inputs[3] * weights2[3]
#     + bias2,
#     # Neuron 3:
#     inputs[0] * weights3[0]
#     + inputs[1] * weights3[1]
#     + inputs[2] * weights3[2]
#     + inputs[3] * weights3[3]
#     + bias3,
# ]

# print(outputs)

# A more organized way
# inputs = [1, 2, 3, 2.5]
# weights = [[0.2, 0.8, -0.5, 1], [0.5, -0.91, 0.26, -0.5], [-0.26, -0.27, 0.17, 0.87]]
# biases = [2, 3, 0.5]

# # Output of current layer
# layer_outputs = []
# # For each neuron
# for neuron_weights, neuron_bias in zip(weights, biases):
#     # Zeroed output of given neuron
#     neuron_output = 0
#     # For each input and weight to the neuron
#     for n_input, weight in zip(inputs, neuron_weights):
#         # Multiply this input by associated weight
#         # and add to the neuron’s output variable
#         neuron_output += n_input * weight
#     # Add bias
#     neuron_output += neuron_bias
#     # Put neuron’s result to the layer’s output list
#     layer_outputs.append(neuron_output)

# print(layer_outputs)

# How to calculate a dot product
# a = [1, 2, 3]
# b = [2, 3, 4]

# dot_product = a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
# print(dot_product)

# With NumPy
# import numpy as np

# inputs = [1.0, 2.0, 3.0, 2.5]
# weights = [0.2, 0.8, -0.5, 1.0]
# bias = 2.0

# outputs = np.dot(weights, inputs) + bias

# print(outputs)

# Three neurons
# import numpy as np

# inputs = [1.0, 2.0, 3.0, 2.5]
# weights = [[0.2, 0.8, -0.5, 1], [0.5, -0.91, 0.26, -0.5], [-0.26, -0.27, 0.17, 0.87]]
# biases = [2.0, 3.0, 0.5]

# layer_outputs = np.dot(weights, inputs) + biases

# print(layer_outputs)

# import numpy as np

# a = [1, 2, 3]
# print(np.array([a]))

# a = [1, 2, 3]
# print(np.expand_dims(np.array(a), axis=0))

# import numpy as np

# a = [1, 2, 3]
# b = [2, 3, 4]

# a = np.array([a])
# b = np.array([b]).T

# print(np.dot(a, b))

# import numpy as np

# inputs = [[1.0, 2.0, 3.0, 2.5], [2.0, 5.0, -1.0, 2.0], [-1.5, 2.7, 3.3, -0.8]]
# weights = [[0.2, 0.8, -0.5, 1.0], [0.5, -0.91, 0.26, -0.5], [-0.26, -0.27, 0.17, 0.87]]
# biases = [2.0, 3.0, 0.5]

# layer_outputs = np.dot(inputs, np.array(weights).T) + biases

# print(layer_outputs)

# import numpy as np
# import nnfs

# nnfs.init()

# print(np.random.randn(2, 5))
# print(np.zeros((2, 5)))

import numpy as np
import nnfs

nnfs.init()

n_inputs = 2
n_neurons = 4

weights = 0.01 * np.random.randn(n_inputs, n_neurons)
biases = np.zeros((1, n_neurons))

print(weights)
print(biases)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon Sep 16 10:05:07 2019

@author: amandaash
"""
import numpy as np
import matplotlib.pyplot as plt
import random as rand

#first derivatives
x = np.arange(-2*np.pi, 2*np.pi, 0.01)
f_x = np.sin(x)
f_prime_numpy = np.gradient(f_x, 0.01)
f_prime = []

for step in range(len(list(x))):
    if step >= 0:
        derivative = (f_x[step]-f_x[step-1])/(x[step]-x[step-1])
        f_prime.append(derivative)
    else:
        continue
plt.title('first derivative sin(x)')
plt.plot(x[1:], f_prime[1:], '.', label = 'forward difference', alpha = 0.2, color = 'b')
plt.plot(x, f_prime_numpy, '.', label = 'numpy', alpha = 0.2, color = 'r')
plt.plot(x, np.cos(x), '.', label = 'exact', alpha = 0.2, color = 'g')
plt.legend()
plt.savefig('first_derivative.pdf')
plt.show()

error_forward = (np.cos(x)[1:] - f_prime[1:])/np.cos(x)[1:]
plt.title('first derivative error forward difference')
plt.plot(x[1:], error_forward, '.')
plt.savefig('forward_diff_err.pdf')
plt.show()

error_numpy = (np.cos(x) - f_prime_numpy)/(np.cos(x))
plt.title('first derivative error numpy')
plt.plot(x[:-1], error_numpy[:-1], '.')
plt.savefig('grad_err.pdf')
plt.show()

#second derivatives
f_prime_prime_numpy = np.gradient(f_prime_numpy, 0.01)
f_prime_prime = []
for step in range(len(list(x))):
    if step >= 0:
        derivative = (f_prime[step]-f_prime[step-1])/(x[step]-x[step-1])
        f_prime_prime.append(derivative)
    else:
        continue
plt.title('second derivative sin(x)')
plt.plot(x[2:], f_prime_prime[2:], '.', label = 'forward difference', alpha = 0.2, color = 'b')
plt.plot(x, f_prime_prime_numpy, '.', label = 'numpy', alpha = 0.2, color = 'r')
plt.plot(x, -np.sin(x), '.', label = 'exact', alpha = 0.2, color = 'g')
plt.legend()
plt.savefig('2nd_derivative.pdf')
plt.show()

error_forward_2 = (-np.sin(x)[2:] - f_prime_prime[2:])/(-np.sin(x)[2:])
plt.title('second derivative error forward difference')
plt.plot(x[2:], error_forward_2, '.')
plt.savefig('2nd_derivative_err_forward_diff.pdf')
plt.show()

error_numpy_2 = (-np.sin(x) - f_prime_prime_numpy)/-np.sin(x)
plt.title('second derivative error numpy')
plt.plot(x[1:-2], error_numpy_2[1:-2], '.')
plt.savefig('2nd_derivative_err_numpy.pdf')
plt.show()

#random noise
epsilon_array = []
for n in range(len(list(x))):
    epsilon_array.append(rand.random()*0.001)
f_x = np.sin(x) + epsilon_array
f_prime_numpy = np.gradient(f_x, 0.01)
f_prime = []

for step in range(len(list(x))):
    if step >= 0:
        derivative = (f_x[step]-f_x[step-1])/(x[step]-x[step-1])
        f_prime.append(derivative)
    else:
        continue
plt.title('first derivative sin(x) + $\epsilon$')
plt.plot(x[1:], f_prime[1:], '.', label = 'forward difference', alpha = 0.2, color = 'b')
plt.plot(x, f_prime_numpy, '.', label = 'numpy', alpha = 0.2, color = 'r')
plt.plot(x, np.cos(x), '.', label = 'exact', alpha = 0.2, color = 'g')
plt.legend()
plt.savefig('noisy_derivative.pdf')
plt.show()

error_forward = np.cos(x)[1:] - f_prime[1:]
plt.title('first derivative error forward difference')
plt.plot(x[1:], error_forward, '.')
plt.show()

error_numpy = np.cos(x) - f_prime_numpy
plt.title('first derivative error numpy')
plt.plot(x[:-1], error_numpy[:-1], '.')
plt.show()

#second derivatives
f_prime_prime_numpy = np.gradient(f_prime_numpy, 0.01)
f_prime_prime = []
for step in range(len(list(x))):
    if step >= 0:
        derivative = (f_prime[step]-f_prime[step-1])/(x[step]-x[step-1])
        f_prime_prime.append(derivative)
    else:
        continue
plt.title('second derivative sin(x) + $\epsilon$')
plt.plot(x[2:], f_prime_prime[2:], '.', label = 'forward difference', alpha = 0.2, color = 'b')
plt.plot(x, f_prime_prime_numpy, '.', label = 'numpy', alpha = 0.2, color = 'r')
plt.plot(x, -np.sin(x), '.', label = 'exact', alpha = 0.2, color = 'g')
plt.legend()
plt.show()

error_forward_2 = -np.sin(x)[2:] - f_prime_prime[2:]
plt.title('second derivative error forward difference')
plt.plot(x[2:], error_forward_2, '.')
plt.show()

error_numpy_2 = -np.sin(x) - f_prime_prime_numpy
plt.title('second derivative error numpy')
plt.plot(x[1:-2], error_numpy_2[1:-2], '.')
plt.show()


from unittest import TestCase

import numpy as np

def read_input(filename="input"):
    with open(filename) as f:
        lines = [line.strip() for line in f.readlines() if line.strip()]
    inp = [int(val) for val in lines[0].split(',')]  # parse here...
    return inp

def part_1(inp):
    arr = np.array(inp)
    return find_minimum(arr, calc_fuel)

def find_minimum(arr, func):
    _min = min(arr)
    _max = max(arr)
    _min_fuel_found = 999999999999
    for n in range(_min, _max + 1):
        fuel = func(arr, n)
        if fuel < _min_fuel_found:
            _min_fuel_found = fuel
    return _min_fuel_found

def calc_fuel(arr, pos):
    return np.abs(arr - pos).sum()

def part_2(inp):
    arr = np.array(inp)
    return find_minimum(arr, calc_fuel_2)

def calc_fuel_2(arr, pos):
    deltas = np.abs(arr - pos)
    fuel_cost = (deltas / 2) * (deltas + 1)
    return fuel_cost.sum()

def main(input_file):
    """Solve puzzle and connect part 1 with part 2 if needed."""
    # part 1
    inp = read_input(input_file)
    p1 = part_1(inp)
    print(f"Solution to part 1: {p1}")

    # part 2
    inp = read_input(input_file)
    p2 = part_2(inp)
    print(f"Solution to part 2: {p2}")
    return p1, p2

def test_sample_1(self):
    inp = read_input("sample_1")
    self.assertEqual(37, part_1(inp))
    self.assertEqual(168, part_2(inp))

def test_sample_2(self):
    pass

if __name__ == "__main__":
    print('*** solving tests ***')
    test_sample_1(TestCase())
    test_sample_2(TestCase())
    print('*** solving main ***')
    main("input")


import numpy as np

versicolor_petal_length = [4.7, 4.5, 4.9, 4.0,  4.6, 4.5, 4.7, 3.3, 4.6, 3.9, 3.5, 4.2, 4.0,  4.7, 3.6, 4.4, 4.5, 4.1,
     4.5, 3.9, 4.8, 4.0,  4.9, 4.7, 4.3, 4.4, 4.8, 5.0,  4.5, 3.5, 3.8, 3.7, 3.9, 5.1, 4.5, 4.5,
     4.7, 4.4, 4.1, 4.0,  4.4, 4.6, 4.0,  3.3, 4.2, 4.2, 4.2, 4.3, 3.0,  4.1]

# Array of differences to mean: differences
difference = versicolor_petal_length - np.mean(versicolor_petal_length)
#print(difference)

# Square the differences: diff_sq
diff_sq = difference **2

# Compute the mean square difference: variance_explicit
variance_explicit = np.mean(diff_sq)

# Compute the variance using NumPy: variance_np
variance_np = np.var(versicolor_petal_length)

# Print the results
print(variance_explicit, variance_np)

standard_dev_exp = np.sqrt(variance_explicit)
standard_dev_np = np.std(versicolor_petal_length)

print(standard_dev_exp, standard_dev_np)


#!/usr/bin/env python
# coding: utf-8

# OBJECTIVE : The dataset contains detailed attributes for every player registered in the latest edition of FIFA 19 database. Our objective is to create Linear, Multiple and Polynomail Regression models to predict the potential of a player based on several attributes.

# In[88]:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

# In[89]:

# reading dataset
data=pd.read_csv("../../../input/karangadiya_fifa19/data.csv")

# In[90]:

# displaying first 5 rows
data.head()

# In[91]:

data.shape #(no. of rows, no. of columns)

# In[92]:

data.describe()

# In[93]:

# finding any null values in data
data.isnull().any()

# #  Linear Regression - Predicting Potential based on Age of the player

# In[94]:

# x = Age(independent variable)
x=data.iloc[:,3]

# In[95]:

x.head()

# In[96]:

x.isnull().any()

# In[97]:

# y = Potential(dependent variable)
y=data.iloc[:,8]

# In[98]:

y.head()

# In[99]:

y.isnull().any()

# In[100]:

plt.bar(data["Age"],data["Potential"])
plt.xlabel("Age of Player")
print()

# In[101]:

# splitting data into train and tet set
from sklearn.model_selection import train_test_split

# In[102]:

x_train,x_test,y_train,y_test=train_test_split(x,y,test_size=0.2,random_state=0)

# In[103]:

from sklearn.linear_model import LinearRegression

# In[104]:

# making object regressor of class LinearRegression
regressor=LinearRegression()

# I was facing errors with fitting the data so we reshape x_train and y_train by first converting them into ndarray.

# In[105]:

type(x_train)
type(y_train)

# In[106]:

x_train=np.array(x_train)
y_train=np.array(y_train)

# In[107]:

type(x_train)
type(y_train)

# In[108]:

x_train=x_train.reshape(-1,1)
y_train=y_train.reshape(-1,1)

# In[109]:

# fitting training set into object regressor
regressor.fit(x_train,y_train)

# To avoid error in prediting we reshape x_test also.

# In[110]:

x_test=np.array(x_test)

# In[111]:

x_test=x_test.reshape(-1,1)

# In[112]:

# Predicting y from test set
y_pred= regressor.predict(x_test)

# In[113]:

# Visualising training dataset
plt.scatter(x_train,y_train,color="red")
plt.xlabel("Age of Player")
plt.ylabel("Potential of Player")
plt.plot(x_train, regressor.predict(x_train),color="blue") # To draw line of regression
print()

# In[114]:

# Visualising test dataset
plt.scatter(x_test,y_test,color="red")
plt.xlabel("Age of Player")
plt.ylabel("Potential of Player")
plt.plot(x_train, regressor.predict(x_train),color="blue")
print()

# In[115]:

# Finding intercept of linear regression line
regressor.intercept_

# In[116]:

# Finding coefficient of linear regression line
regressor.coef_

# In[117]:

# Finding mean squared error of linear regression model
from sklearn.metrics import mean_squared_error

# In[118]:

mean_squared_error(y_test,y_pred)

# # Multiple regression - Predicting potential based on age, agility, balance, stamina, strength, composure
#

# In[119]:

# independent variables are - Age, Agility, Balance, stamina, Strength, Composure
x=data.iloc[:,[3,66,68,71,72,79]]

# In[120]:

x.head()

# In[121]:

# checking if there are null values in x and then filling them.
x.isnull().any()

# In[122]:

x=x.fillna(method='ffill')

# In[123]:

x.isnull().any()

# In[124]:

# dependent variable = Potential
y=data.iloc[:,8]

# In[125]:

y.head()

# In[126]:

y.isnull().any()

# In[127]:

sns.lineplot(x="Potential", y="Age",data=data,label="Age", ci= None)
sns.lineplot(x="Potential", y="Agility",data=data,label="Agility", ci= None)
sns.lineplot(x="Potential", y="Balance",data=data,label="Balance", ci= None)
sns.lineplot(x="Potential", y="Stamina",data=data,label="Stamina", ci= None)
sns.lineplot(x="Potential", y="Strength",data=data,label="Strength", ci= None)
sns.lineplot(x="Potential", y="Composure",data=data,label="Composure", ci= None)

# In[128]:

x_train,x_test,y_train,y_test=train_test_split(x,y,test_size=0.2)

# In[129]:

regressor=LinearRegression()

# In[130]:

regressor.fit(x_train,y_train)

# In[131]:

regressor.predict(x_test)

# In[132]:

# Visualising Actual and predicted values of Potential of player
plt.scatter(y_test,y_pred)
plt.xlabel("Actual Potential")
plt.ylabel("Predicted Potential")
print()

# Seems like the actual and predicted values are very close to each other.

# In[133]:

regressor.intercept_

# In[134]:

regressor.coef_

# Backward Elimination - Making optimal regression model by finding the statistical significance of all independent variables

# In[135]:

# let us take the significance level (SL)= 0.05
import statsmodels.formula.api as sm

# In[136]:

# fitting all variables in the model
regressor_OLS=sm.OLS(endog=y,exog=x).fit()

# In[137]:

# Finding statistical summary of all variables
regressor_OLS.summary()

# As we see all the P- values are less than SL(0.05), that means all the variables are significant and none of them can be removed.
# t-value shows the statistical significane of each variable.
# F-static shows us how significant the fit is.
# Adjusted- R is 0.986 that means our model explains 98.6% variables in dependent variables.

# # Polynomial Regression - Predicting potential based on the age of player

# In[138]:

# independent variable= age
x=data.iloc[:,3]

# In[139]:

x.head()

# In[140]:

# dependent variable = potential
y=data.iloc[:,8]

# In[141]:

y.head()

# In[142]:

x_train,x_test,y_train,y_test=train_test_split(x,y,test_size=0.2,random_state=42)

# In[143]:

x_train=np.array(x_train)
y_train=np.array(y_train)

# In[144]:

x_train=x_train.reshape(-1,1)
y_train=y_train.reshape(-1,1)

# In[145]:

lin_reg_1=LinearRegression()

# In[146]:

lin_reg_1.fit(x_train,y_train)

# In[147]:

x_test=np.array(x_test)

# In[148]:

x_test=x_test.reshape(-1,1)

# In[149]:

y_pred_1=lin_reg_1.predict(x_test)

# In[150]:

# Making polynomail regression model
from sklearn.preprocessing import PolynomialFeatures

# In[151]:

poly_reg=PolynomialFeatures(degree=3)

# In[152]:

x=np.array(x)

# In[153]:

x=x.reshape(-1,1)

# In[154]:

# Making polynomial matrix of x of degree 3
x_poly=poly_reg.fit_transform(x)

# In[155]:

x_poly

# In[156]:

x_poly_train,x_poly_test,y_train,y_test=train_test_split(x_poly,y,test_size=0.2, random_state=42)

# In[157]:

# Making another object to fit polynomial set
lin_reg_2=LinearRegression()

# In[158]:

lin_reg_2.fit(x_poly_train,y_train)

# In[159]:

y_pred_2=lin_reg_2.predict(x_poly_test)

# In[160]:

# Visualizing Linear Regression Model
plt.scatter(x_test,y_test,color='red')
plt.xlabel("Age of Player")
plt.ylabel("Potential of Player")
plt.title("Linear Regression Curve ")
plt.plot(x_train,lin_reg_1.predict(x_train),color='blue')
print()

# In[161]:

# Visualizing Polynomial Regression Model
plt.scatter(x_test,y_test,color='red')
plt.xlabel("Age of Player")
plt.ylabel("Potential of Player")
plt.title("Polynomial Regression Curve ")
plt.plot(x_train,lin_reg_2.predict(poly_reg.fit_transform(x_train)),color='blue')
print()

# In[162]:

mean_squared_error(y_test,y_pred_2)

# We can see the mean squared error of polynomail regression model < mean squared error of linear regression model. So polynomail regression model is more accurate.


import numpy as np
import scipy as sp
from scipy import spatial

def paired_points_matching(source, target):
    """
    Calculates the transformation T that maps the source to the target
    :param source: A N x 3 matrix with N 3D points
    :param target: A N x 3 matrix with N 3D points
    :return:
        T: 4x4 transformation matrix mapping source onto target
        R: 3x3 rotation matrix part of T
        t: 1x3 translation vector part of T
    """

    T = np.eye(4)
    R = np.eye(3)
    t = np.zeros((1, 3))

    N = source.shape[0]

    centroidSource = np.mean(source, axis=0)
    centroidTarget = np.mean(target, axis=0)

    srcCentrAlign = source - np.tile(centroidSource, (N, 1))
    trgCentrAlign = target - np.tile(centroidTarget, (N, 1))

    covMatrix = np.dot(srcCentrAlign.T, trgCentrAlign)

    uMat, sMat, vMat = np.linalg.svd(covMatrix)

    R = np.dot(vMat.T, uMat.T)

    t = - (np.dot(R, centroidSource)) + centroidTarget

    T[:3, :3] = R
    T[:3, 3] = t

    return T, R, t

def find_nearest_neighbor(src, dst):
    """
    Finds the nearest neighbor of every point in src in dst
    :param src: A N x 3 point cloud
    :param dst: A N x 3 point cloud
    :return: the
    """
    tree = sp.spatial.KDTree(dst)
    distance, index = tree.query(src)

    return distance, index

def icp(source, target, init_pose=None, max_iterations=1000, tolerance=0.0001):
    """
    Iteratively finds the best transformation that mapps the source points onto the target
    :param source: A N x 3 point cloud
    :param target: A N x 3 point cloud
    :param init_pose: A 4 x 4 transformation matrix for the initial pose
    :param max_iterations: default 10
    :param tolerance: maximum allowed error
        :return: A 4 x 4 rigid transformation matrix mapping source to target
            the distances and the error
    """
    # T = np.eye(4)
    # distances = 0
    # error = 0

    # Your code goes here

    src_init = np.dot(init_pose[:3, :3], source.T).T
    src_init = src_init + np.tile(init_pose[:3, 3], (source.shape[0], 1))

    tmp_trg = np.zeros_like(source)

    if init_pose is None:
        T = np.eye(4)
    else:
        T = init_pose

    tmp_tol = np.inf
    error = np.inf

    k = 0

    while tmp_tol > tolerance and k < max_iterations:
        distance, idx = find_nearest_neighbor(src_init, target)
        for ii, el in enumerate(idx):
            tmp_trg[ii] = target[el]

        T_tmp, R_tmp, t_tmp = paired_points_matching(src_init, tmp_trg)

        src_init = np.dot(R_tmp, src_init.T).T
        src_init = src_init + np.tile(t_tmp, (source.shape[0], 1))
        T = np.dot(T_tmp, T)

        err_tmp = error
        error = np.sum(distance) / distance.shape[0]
        error = np.sqrt(error)
        tmp_tol = err_tmp - error

        k += 1

    print("Iterations: ", k)
    return T, distance, error

def get_initial_pose(template_points, target_points):
    """
    Calculates an initial rough registration
    (Optionally you can also return a hand picked initial pose)
    :param source:
    :param target:
    :return: A transformation matrix
    """
    T = np.eye(4)

    # Your code goes here

    centr_tmpl = np.mean(template_points, axis=0)
    centr_target = np.mean(target_points, axis=0)
    t = centr_target - centr_tmpl

    T[:3, 3] = t

    return T


import numpy as np
from .integrate import Integrate

class Simpson(Integrate):
    """
    Approximate the integral of f(x) from a to b by Simpson's rule.

    Simpson's rule approximates the integral of f(x) dx by the sum:
    (dx/3) sum(f(x_{2i-2} + 4f(x_{2i-1}) + f(x_{2i})) from i = 1 to N/2 where N is the number of periods.
    dx = (b - a)/N
    x_i = a + i*dx

    Parameters
    ----------
    f : function
        A single variable function f(x), ex: lambda x:np.exp(x**2)
    """

    def __init__(self, f):
        Integrate.__init__(self, f)
        self.N = 250

    def compute_integral(self, a, b, N=250):
        """
        Parameters
        ----------
        a , b : numbers
        Interval of integration [a,b] defult to [-1,1]

        N : even integer
        Number of sub-intervals of [a,b]

        Returns
        -------
        float
            Approximation of the integral of f(x) from a to b using
            Simpson's rule with N subintervals of equal length.

        Examples
        --------
        >>> compute_integral(0,1,10), f = lambda x : 3*x**2
        1.0
        """
        self.a = a
        self.b = b
        self.N = N

        if self.N % 2 == 1:
            raise ValueError("N must be an even integer.")
        dx = (self.b - self.a) / self.N
        x = np.linspace(self.a, self.b, self.N+1)
        y = [self.f(i) for i in x]
        ans = dx/3 * np.sum(y[0:-1:2] + 4*y[1::2] + y[2::2])
        return ans