import numpy as np
from hilbert_tensor import make_hilbert_tensor
from tensor_train_from_tensor_action import tensor_train_from_tensor_action
from tensor_operations import dense_tensor_action, make_tensor_train_with_conventional_method, build_dense_tensor_from_tensor_train
import scipy.io as sio
import pickle

generate_data=True
save_data = True
make_plot=True
save_plot=True
d = 5

filename = 'hilbert_convergence.p'

if generate_data:
    T_shape = 41 + np.arange(d) # e.g., [41, 42, 43, 44, 45]
    T = make_hilbert_tensor(T_shape)
    apply_T = lambda xx, k: dense_tensor_action(T, xx, k)
    rr = 2+np.arange(18)
    errs = np.zeros(len(rr))
    errs_optimal = np.zeros(len(rr))
    for k in range(len(rr)):
        r = rr[k]
        CC = tensor_train_from_tensor_action(apply_T, T_shape, max_rank=r, tol=1e-20, verbose=True)

        T2 = build_dense_tensor_from_tensor_train(CC)
        tt_err = np.linalg.norm(T2 - T) / np.linalg.norm(T)
        errs[k] = tt_err

        CC_optimal = make_tensor_train_with_conventional_method(T, tol=1e-20, max_rank=r)

        T_optimal = build_dense_tensor_from_tensor_train(CC_optimal)

        tt_optimal_err = np.linalg.norm(T_optimal - T) / np.linalg.norm(T)
        errs_optimal[k] = tt_optimal_err

        print('r=', r, ', tt_err=', tt_err, ', tt_optimal_err=', tt_optimal_err)

    if save_data:
        data = (T_shape, rr, errs, errs_optimal)
        pickle.dump(data, open(filename, 'wb'))
else:
    (T_shape, rr, errs, errs_optimal) = pickle.load(open(filename, 'rb'))

if make_plot:
    import matplotlib.pyplot as plt

    plt.figure()
    if d == 5:
        tt_cross_data = sio.loadmat('hilbert_dmrg_cross_data2.mat') # from nick_hilbert_tensor_train_cross.m, using Oseledets TT-cross matlab code
        errs_cross = tt_cross_data['errs'].reshape(-1)
        rr_cross = tt_cross_data['rr'].reshape(-1)
        plt.semilogy(rr_cross, errs_cross,linestyle='dashed', color='k')

    plt.semilogy(rr.reshape(-1), errs.reshape(-1), color='k')
    plt.semilogy(rr.reshape(-1), errs_optimal.reshape(-1),linestyle='dotted', color='k')
    plt.title('Hilbert tensor: approximation error vs. rank',fontsize=14)
    plt.xlabel('Tensor train rank, $r$',fontsize=12)
    plt.ylabel(r'$\frac{||T - \widetilde{T}||}{||T||}$', rotation=0, fontsize=16, labelpad=30)
    plt.xlim([2,19])
    if d == 5:
        plt.legend(['TT-cross', 'TT-RSVD (our method)', 'TT-SVD (optimal)'])
    else:
        plt.legend(['TT-RSVD (our method)', 'TT-SVD (optimal)'])

if make_plot and save_plot:
    plt.savefig("hilbert_test1.pdf",bbox_inches='tight',dpi=100)


from ipywidgets import interact, interactive, fixed, interact_manual
from ipywidgets import FloatSlider, Dropdown
import ipywidgets as widgets

import pandas as pd

from sklearn.datasets import make_regression
from sklearn.metrics import mean_squared_error

import matplotlib.pyplot as plt

import numpy as np

from sklearn.utils import check_random_state

def plot_simple_regression(b0=0, b1=1, xlim=(-5, 5), ylim=(-5, 5)):
    x = np.linspace(-10, 10, 1000)
    y = b0 + b1 * x

    plt.xlim(xlim)
    plt.ylim(ylim)
    plt.plot(x, y)
    plt.plot([0, 0], ylim, 'g-',
             xlim, [0, 0], 'g-', linewidth=0.4)

def simple_linear_regression_manual_demo_1():
    interact(plot_simple_regression,
         b0=FloatSlider(min=-10, max=10, step=0.01, value=0),
         b1=FloatSlider(min=-10, max=10, step=0.01, value=1),
         xlim=fixed((-5, 5)),
         ylim=fixed((-5, 5)));

def plot_simple_regression_with_dataset(x, y, b0=0, b1=1, xlim=(-5, 5), ylim=(-5, 5)):
    plot_simple_regression(b0, b1, xlim, ylim)
    plt.scatter(x, y)

    y_hat = b0 + b1 * x

    return "Mean Squared Error (MSE): {}".format(mean_squared_error(y, y_hat))

def simple_linear_regression_demo_2():
    x, y = make_regression(n_features=1, n_samples=100, noise=30.5, random_state=10, bias=200)
    x = x[:, 0]
    y /= 100
    y *= 2.0

    interact(plot_simple_regression_with_dataset,
             b0=FloatSlider(min=-10, max=10, step=0.01, value=-1),
             b1=FloatSlider(min=-10, max=10, step=0.01, value=-1),
             x=fixed(x),
             y=fixed(y),
             xlim=fixed((-5, 5)),
             ylim=fixed((-3, 8)));

def learning_rate_impact(learning_rate=0.1):
    f = lambda x: x ** 2
    df_dx = lambda x: 2 * x
    x = -300

    epochs = 100

    data = []

    for epoch in range(epochs):
        x = x - learning_rate * df_dx(x)
        data.append({
            'epoch': epoch, 'x': x,
            'f(x)': f(x), 'df_dx': df_dx(x)})

    data = pd.DataFrame(data)

    plt.plot(data['epoch'], data['f(x)'])
    plt.ylabel('f(x)')
    plt.xlabel('epochs')
    plt.title('learning rate: {}'.format(learning_rate))

def gradient_descent_learning_rate_impact_demo():
    interact(learning_rate_impact,
             learning_rate=FloatSlider(
                 min=0.001, max=1.1,
                 step=0.001, value=0.001))

import numpy as np

import matplotlib.pyplot as plt

def get_computed_function(x, name='convex-1'):
    if name == 'convex-1':
        return {
            'y': x ** 2,
            'dy': 2 * x
        }
    if name == 'convex-2':
        return {
            'y': x ** 2 + 3 * x +2,
            'dy': 2 * x + 3
        }
    if name == 'non-convex-1':
        return {
            'y': (x ** 2) + abs(15 * x) * np.cos(x),
            'dy': 2 * x + np.cos(x) * (15 * x / abs(x)) - abs(15 * x) * np.sin(x)
        }
    if name == 'non-convex-2':
        return {
            'y': 3 * np.cos(x) + abs(x),
            'dy': -3 * np.sin(x) + x / abs(x)
        }
    if name == 'non-convex-3':
        w1 = 5.1
        w2 = 10.1
        # TODO: still has problems
        return {
            'dy': 2 * x + w1 * w2 * np.cos(w2 * x) + 2 * (x ** 2) * np.cos(x) * np.sin(x) + 2 * x * (np.sin(x) ** 2) + w1 * np.sin(w1 * x),
            'y': x ** 2 + (x * np.sin(x)) ** 2 + w1 * np.sin(w2 * x) - np.cos(w1 * x)
        }

def run_sgd_step(o, learning_rate=0.1,
                 name='convex-2',
                 range_def=[-10.0, 10.0, 10000]):
    x_min = min(range_def[0], o['curr_x'])
    x_max = max(range_def[1], o['curr_x'])
    n_steps = range_def[2]
    x = np.linspace(x_min, x_max, n_steps)
    y = get_computed_function(x, name=name)
    y = y['y']

    curr_y = get_computed_function(np.array([o['curr_x']]), name=name)
    d_curr_y = curr_y['dy']
    curr_y = curr_y['y']

    o['curr_x'] = o['curr_x'] - learning_rate * d_curr_y
    curr_y = get_computed_function(np.array(o['curr_x']), name=name)['y']
    o['curr_x'] = o['curr_x'][0]

    plt.plot([o['curr_x']], [curr_y], 'o')
    plt.plot(x, y)

    return o

def non_convex_gradient_descent_demo():
    o = {'curr_x': -6.0}

    interact_manual(run_sgd_step,
                    learning_rate=FloatSlider(min=0.01, max=2.0, step=0.01, value=0.01),
                    o=fixed(o),
                    name=fixed('non-convex-1'),
                    range_def=fixed([-20, 20, 100000]));

def run_sgd_for_simple_lr(x, y, params, learning_rate):
    run_linear_regression_sgd_epoch(x, y, params, learning_rate)

    x_ = np.linspace(-4, 4)
    b0 = params['b0']
    b1 = params['b1']
    y_hat = b0 + b1 * x_

    plt.ylim([-4, 8])
    plt.xlim([-6, 6])
    plt.plot(x_, y_hat)
    plt.scatter(x, y, c='orange')

def run_linear_regression_sgd_epoch(x, y, params, learning_rate):
    data = np.concatenate((np.array([x]).T, np.array([y]).T), axis=1)

    np.random.shuffle(data)

    for m in range(x.shape[0]):
        x = data[:, 0]
        y = data[:, 1]

        b0 = params['b0']
        b1 = params['b1']

        x_ = x[m]
        y_ = y[m]

        y_hat = b0 + b1 * x_

        d_mse_d_b1 = - 2 * (y_ - y_hat) * x_

        d_mse_d_b0 = - 2 * (y_ - y_hat)

        b0 = b0 - learning_rate * d_mse_d_b0
        b1 = b1 - learning_rate * d_mse_d_b1

    params['b0'] = b0
    params['b1'] = b1

    return params

def run_multiple_sgd_iter_for_simple_lr(x, y, params, learning_rate, n_iter, random_state):
    data = pd.concat(
        (x.to_frame(), y.to_frame()),
        axis=1)
    data.columns = ['x', 'y']

    data.sample(n=data.shape[0], random_state=random_state)

    for i in range(int(n_iter)):
        run_linear_regression_sgd_epoch(x, y, params, learning_rate)

        x_ = np.linspace(-4, 4)
        b0 = params['b0']
        b1 = params['b1']
        y_hat = b0 + b1 * x_

        params['path'].append({
            'b0': b0,
            'b1': b1
        })

    x_ = np.linspace(-4, 4)
    b0 = params['b0']
    b1 = params['b1']
    y_hat = b0 + b1 * x_

    f, (ax1, ax2) = plt.subplots(1, 2, sharey=False)
    f.set_figheight(5)
    f.set_figwidth(15)

    plt.ylim([-4, 8])
    plt.xlim([-6, 6])
    ax1.plot(x_, y_hat)
    ax1.scatter(x, y, c='orange')

    path = params['path']

    x = []
    y = []

    for p in path:
        x.append(p['b0'])
        y.append(p['b1'])

    ax2.plot(x, y, 'r')

def run_multiple_bgd_for_simple_lr(x, y, params, learning_rate, n_iter):
    for i in range(int(n_iter)):
        y_hat = params['b0'] + params['b1'] * x

        y_dif = y - y_hat
        total_b0_grad = -(2 * y_dif).mean()
        total_b1_grad = -((2 * y_dif) * x).mean()

        params['b0'] = params['b0'] - learning_rate * total_b0_grad
        params['b1'] = params['b1'] - learning_rate * total_b1_grad

        x_ = np.linspace(-4, 4)
        b0 = params['b0']
        b1 = params['b1']
        y_hat = b0 + b1 * x_

        params['path'].append({
            'b0': b0,
            'b1': b1
        })

    x_ = np.linspace(-4, 4)
    b0 = params['b0']
    b1 = params['b1']
    y_hat = b0 + b1 * x_

    f, (ax1, ax2) = plt.subplots(1, 2, sharey=False)
    f.set_figheight(5)
    f.set_figwidth(15)

    plt.ylim([-4, 8])
    plt.xlim([-6, 6])
    ax1.plot(x_, y_hat)
    ax1.scatter(x, y, c='orange')

    path = params['path']

    x = []
    y = []

    for p in path:
        x.append(p['b0'])
        y.append(p['b1'])

    ax2.plot(x, y, 'r')

def sgd_simple_lr_dataset_demo():
    random_state = check_random_state(10)

    x, y = make_regression(n_features=1, n_samples=100, noise=30.5,
                           random_state=random_state, bias=200)
    x = pd.Series(x[:, 0])
    y /= 100
    y *= 2.0
    y = pd.Series(y)

    params = {
        'b0': -1,
        'b1': -5,
        'path': []
    }

    interact_manual(run_multiple_sgd_iter_for_simple_lr,
                    x=fixed(x), y=fixed(y),
                    random_state=fixed(random_state),
                    params=fixed(params),
                    n_iter=FloatSlider(
                        min=1, max=100, step=1, value=1),
                    learning_rate=FloatSlider(
                        min=0.01, max=2.0, step=0.01, value=0.01))

def bgd_simple_lr_dataset_demo():
    x, y = make_regression(n_features=1, n_samples=100, noise=30.5, random_state=10, bias=200)
    x = x[:, 0]
    y /= 100
    y *= 2.0

    params = {
        'b0': -1,
        'b1': -5,
        'path': []
    }

    interact_manual(run_multiple_bgd_for_simple_lr,
                    x=fixed(x), y=fixed(y),
                    params=fixed(params),
                    n_iter=FloatSlider(
                        min=1, max=100, step=1, value=1),
                    learning_rate=FloatSlider(
                        min=0.01, max=100.0, step=0.01, value=0.01))


import numpy as np

def smallest_rectangle_enclosing(observations):
    x_min = np.min(observations[:,0], 0)
    x_max = np.max(observations[:,0], 0)
    y_min = np.min(observations[:,1], 0)
    y_max = np.max(observations[:,1], 0)
    x_span = x_max - x_min
    y_span = y_max - y_min
    return x_min, y_min, x_span, y_span

# Returns an unnormalised prior on the hypotheses that is
# proportional to the inverse product of the hypothesis x- and y-scale
def uninformative_prior(hypotheses):
    x_span_hyp = hypotheses[:,0]
    y_span_hyp = hypotheses[:,1]
    return 1 / x_span_hyp*y_span_hyp

def likelihood(hypotheses, observations):
    n = len(observations)
    x_span_hyp = hypotheses[:,0]
    y_span_hyp = hypotheses[:,1]
    _, _, x_span, y_span = smallest_rectangle_enclosing(observations)

    # Truth values indicating whether each hypothesis supports the obbservations (hypothesis scale must
    # cover the obbservations range)
    indications = np.logical_and(x_span_hyp > x_span, y_span_hyp > y_span)

    # Likelihood is proportional to 1/scale in each direction for each obbservations point,
    # or to zero if the hypothesis doesn't support the obbservations.
    return indications / np.power(x_span_hyp*y_span_hyp, n)

def posterior(likelihood, prior):
    unnormalised = likelihood * prior
    return unnormalised / np.sum(unnormalised)

def diffs(points, min_, span):
    # is 0 whenever the point is
    # within the span of the observation, otherwise it's the distance to the
    # nearest neighbour along that dimension.
    max_ = min_ + span
    return (points < min_) * abs(points - min_) + (points > max_) * abs(max_ - points)

def proba_from_diffs(x_diffs, y_diffs, width, height, n_observations):
    p_denom = (1 + (x_diffs/width)) * (1 + (y_diffs/height))
    p = np.power(1/p_denom, n_observations-1)
    r = p / np.sum(p)
    return r

def draw_from_posterior(hypotheses, posterior, size):
    samples_index = np.random.choice(len(posterior), size, p=posterior)

    # Reorder the samples from least to most probable, to help later with
    # drawing order so that darker, higher probability samples are drawn on top of
    # lighter, lower probability samples.
    samples_prob = posterior[samples_index]
    samples_index = samples_index[np.argsort(samples_prob)]

    samples_posterior = posterior[samples_index]
    samples_width, samples_height = hypotheses[samples_index, 0], hypotheses[samples_index, 1]

    return  samples_width, samples_height, samples_posterior


"""
Ajay Kc
013213328
EE381
Project 4 Part 3

The problem simulates the lifespan of a carton with 24 batteries and plots the histogram
for the simulated results.
"""
import numpy as np
import matplotlib.pyplot as plt
import math as math
mean = 45
standard_deviation = 45

def getRVMean(n):
    return n*mean

def getRVSd(n):
    return standard_deviation*math.sqrt(n)

def simulateExpRV():
    expRV = np.random.exponential(45,100)
    return expRV

def simulateSumExpEV():
    carton = []
    sumRV = []

    for i in range (0,24):
        carton.append(simulateExpRV())

    sumRV = [sum(x) for x in zip(*carton)]

    return sumRV

def plotFunctions(RV):
    nbins=30; # Number of bins
    nbatteries = 24
    a=20
    b=70
    edgecolor = 'w';    #Color seperating bars in the bargraph
    #
    #Create bins and histogram
    bins = [float(x) for x in np.linspace(nbatteries*a, nbatteries*b, nbins+1)]
    h1, bin_edges = np.histogram(RV, bins, density = True)
    #Define points on the horizontal axis
    be1 = bin_edges[0:np.size(bin_edges)-1]
    be2 = bin_edges[1:np.size(bin_edges)]
    b1 = (be1+be2)/2
    barwidth = b1[1]-b1[0] #Width of bars in the bargraph

    figureOne = plt.figure(1)
    xlabel = "Life span of 24 batteries"
    plt.xlabel(xlabel, fontsize = 20)
    plt.ylabel("PDF", fontsize = 20)
    plt.title("PDF of life span of 24 batteries and comparison with Gaussian",fontsize=20)
    plt.bar(b1,h1,width = barwidth, edgecolor=edgecolor, color = 'b')

    normalDist = []
    for i in range(0, len(b1)):
        normalDist.append((1 / (getRVSd(24) * math.sqrt(2 * math.pi))) * math.exp(
            -((b1[i] - getRVMean(24)) ** 2) / (2 * getRVSd(24) ** 2)))

    plt.plot(b1, normalDist, color='r')
    plt.show()
    plt.close()

    H1 = np.cumsum(h1)*barwidth
    xlabel = "Life span of 24 batteries"
    plt.xlabel(xlabel, fontsize=20)
    plt.ylabel("CDF", fontsize=20)
    plt.title("CDF of life span of 24 batteries", fontsize=20)

    plt.bar(b1,H1,width = barwidth, edgecolor=edgecolor)
    plt.show()
    plt.close()

mergedList = []
for i in range(0,10000):
    mergedList += simulateSumExpEV()

plotFunctions(mergedList)


import numpy as np
import os

import matplotlib as mpl
import matplotlib.pyplot as plt

from sklearn.datasets import fetch_openml
from sklearn.model_selection import train_test_split
from sklearn.decomposition import PCA
from sklearn.decomposition import IncrementalPCA

# Define the directory for saving the plotting results
PROJECT_ROOT_DIR = '.'
CHAPTER_ID = 'dim_reduction'
IMAGES_PATH = os.path.join(PROJECT_ROOT_DIR, 'images', CHAPTER_ID)
os.makedirs(IMAGES_PATH, exist_ok=True)

# Function of saving the plotting results
def save_fig(fig_id, tight_layout=True, fig_extension='png', resolution=300):
    path = os.path.join(IMAGES_PATH, fig_id + '.' + fig_extension)
    print('Save Image ', fig_id)
    if tight_layout:
        plt.tight_layout()
    plt.savefig(path, format=fig_extension, dpi=resolution)

# MNIST dataset display function
def plot_digits(instances, images_per_row=5, **options):
    size = 28
    images_per_row = min(len(instances), images_per_row)
    images = [instance.reshape(size,size) for instance in instances]
    n_rows = (len(instances) - 1) // images_per_row + 1
    row_images = []
    n_empty = n_rows * images_per_row - len(instances)
    images.append(np.zeros((size, size * n_empty)))
    for row in range(n_rows):
        rimages = images[row * images_per_row : (row + 1) * images_per_row]
        row_images.append(np.concatenate(rimages, axis=1))
    image = np.concatenate(row_images, axis=0)
    plt.imshow(image, cmap = mpl.cm.binary, **options)
    plt.axis("off")

####################################################################################################################################################
### Prepare MNIST dataset ##########################################################################################################################
####################################################################################################################################################
mnist = fetch_openml('mnist_784', version=1)
mnist.target = mnist.target.astype(np.uint8)

X = mnist['data']       # Load data from MNIST dataset
y = mnist['target']     # Load target values from MNIST dataset

X_train, X_test, y_train, y_test = train_test_split(X, y)   # Split the dataset between training and test

####################################################################################################################################################
### PCA (Principle Component Analysis) #############################################################################################################
####################################################################################################################################################
pca = PCA()             # PCA object for producing principle components for the dataset
pca.fit(X_train)        # Produce Re-Organized dataset (sklearn API includes standardization)
cumsum = np.cumsum(pca.explained_variance_ratio_)   # Cumulative sum of PC variance
d = np.argmax(cumsum >= 0.95) + 1                   # The number of PCs for explaining 95% of the Re-Organized dataset

print(d)    # Print the number of PCs for explaining 95% of the Re-Organized dataset

plt.figure(figsize=(6,4))
plt.plot(cumsum, linewidth=3)               # Plot the cumulative sum of PC variance
plt.axis([0, 400, 0, 1])
plt.xlabel("Dimensions")
plt.ylabel("Explained Variance")

# Indicate the point of explaining 95% of the Re-Organized dataset
plt.plot([d, d], [0, 0.95], "k:")
plt.plot([0, d], [0.95, 0.95], "k:")
plt.plot(d, 0.95, "ko")
plt.annotate("Elbow", xy=(65, 0.85), xytext=(70, 0.7),
             arrowprops=dict(arrowstyle="->"), fontsize=16)     # Indicate the point of explaining 95% of the Re-Organized dataset

plt.grid(True)
save_fig("explained_variance_plot")
plt.show()

pca = PCA(n_components=0.95)                    # PCA object for producing principle components that explain 95% of the dataset
X_reduced = pca.fit_transform(X_train)          # Produce Re-Organized dataset (sklearn API includes standardization)

print(np.sum(pca.explained_variance_ratio_))    # Print the variance ratio of current principle components

pca = PCA(n_components=154)                     # PCA object for producing 154 principle components
X_reduced = pca.fit_transform(X_train)          # Produce Re-Organized dataset (sklearn API includes standardization)
X_recovered = pca.inverse_transform(X_reduced)  # Reproject Re-Organized dataset back to original feature space

X_reduced_pca = X_reduced   # Save PCA-based Re-Organized dataset

# Comparison between original image dataset and PCA image dataset
plt.figure(figsize=(7, 4))
plt.subplot(121)
plot_digits(X_train[::2100])                # Show training dataset of MNIST
plt.title("Original", fontsize=16)
plt.subplot(122)
plot_digits(X_recovered[::2100])            # Show PCA-reprojected training dataset
plt.title("Compressed", fontsize=16)

save_fig("mnist_compression_plot")
plt.show()

####################################################################################################################################################
### IPCA (Incremental Principle Component Analysis) ################################################################################################
####################################################################################################################################################
n_batches = 100

inc_pca = IncrementalPCA(n_components=154)

for X_batch in np.array_split(X_train, n_batches):
    print('.', end='')
    inc_pca.partial_fit(X_batch)
print()

X_reduced_inc_pca = inc_pca.transform(X_train)

X_recovered_inc_pca = inc_pca.inverse_transform(X_reduced_inc_pca)

# Comparison between original image dataset and IPCA image dataset
plt.figure(figsize=(7, 4))
plt.subplot(121)
plot_digits(X_train[::2100])
plt.subplot(122)
plot_digits(X_recovered_inc_pca[::2100])
plt.tight_layout()
plt.show()

####################################################################################################################################################
### Comparison between PCA and IPCA ################################################################################################################
####################################################################################################################################################

print(np.allclose(pca.mean_, inc_pca.mean_))

print(np.allclose(X_reduced_pca, X_reduced_inc_pca))


# Programming assignment 0
# Prereqs: numpy, scipy, tensorflow, scikit-learn, and keras
import keras
import numpy as np
import scipy.stats as st
import sklearn as sk
import sys
import tensorflow as tf

# Your A# is going to be your major input to your calculations.
# Please be careful about the digits. Here's your guide for digit indices:
# A12345678 being an example A#, 8 is the last digit, 7 is the second to last digit,
# 6 is the third to the last digit, etc.

anumber = 'A20351527'

# Please implement what is needed at the TODO sections,
# do not modify the other parts of the code.

result_list = list()
result_list.append(sys.version)
result_list.append(keras.__version__)

#TODO: 1. Using the scipy.stats.norm.pdf function, calculate the probability density value of
# "the last digit of your A#", where the mean (i.e., loc) is 5, and standard deviation (i.e., scale) is 15.
# Store the result in a variable called value1.
# Do not change the following line. Obviously, your code needs to preceed the following line :).
value1 = st.norm.pdf(int(anumber[-1]), 5, 15)
result_list.append(value1)

#TODO: 2. Set the seed of Numpy using np.random.seed() function, and use "the second to the last digit of your A#" as the seed.
#         Then sample a value from the uniform distribution of [0, 1) (use numpy.random.rand()).
#		  The result should be assigned to value2.
np.random.seed(int(anumber[-2]))
value2 = np.random.rand()
result_list.append(value2)

#TODO: 3. Using the tf.random_normal() function, sample a random value from the normal distribution
#		  with mean=-1 and standard deviaion=4, and use "the third digit to the last of your A#" as the seed.
#         The result should be assigned to value3.
normal_rv = tf.random_normal([1,], mean=-1, stddev=4, seed=int(anumber[-3]))
with tf.Session() as sess:
    value3 = sess.run(normal_rv)[0]
result_list.append(value3)

#TODO: 4. Using sklearn.utils.shuffle(), shuffle the array of [0, 1,...,11]. Set the seed to "the fourth to
#         the last digit of your A#".
#		  The result should be assigned to value4.
array = np.arange(12)
value4 = sk.utils.shuffle(array, random_state=int(anumber[-4]))
result_list.append(value4)

# Once you run the code, it will generate a "result.txt" file. Do not modify the following code.
with open("result.txt", "w") as f:
	for v in result_list:
		f.write(str(v))
		f.write("\n")


from __future__ import annotations
import numpy as np

EPSILON = 10e-17

def vector_from_points(u: np.array, v: np.array) -> np.array:
    """
    Return the vector 'uv', from points 'u' to 'v'.

    Args:
        u (np.array): Point 'u'.
        v (np.array): Point 'v'.

    Returns:
        np.array: vector

    """

    return v - u

# 2D plane
class Plane:
    """
    2D Plane class.

    """

    def __init__(self, a: float, b: float, c: float, d: float):
        """ax + by + cz + d = 0"""
        self.a, self.b, self.c, self.d = a, b, c, d

    def point_on_plane(self, point: np.array) -> bool:
        """
        Is the given point on this plane ?

        If the distance to th eplane is less than EPSILON, the point is
        considered to be on the plane.

        Args:
            point (np.array): Point to check.

        Returns:
            bool: The point is one the plane.

        """

        return self.normal_dist(point) < EPSILON

    def normal_dist(self, point: np.array) -> float:
        """
        Return the normal distance of the 'point' to the plane.

        Args:
            point (np.array): Point to check.

        Returns:
            float: Normal distance to the plane.

        """

        return abs(self.a * point[0] + self.b * point[1] + self.c * point[2] + self.d)

    def dist_with_point(self, point: np.array) -> float:
        """
        Return the distance of the 'point' to the plane.

        Args:
            point (np.array): Point to check.

        Returns:
            float: Distance to the plane.

        """

        return self.normal_dist(point) / self.base()

    def base(self):
        """
        Return the base of the plane.

        Returns:
            float: The base of the plane.

        """

        return np.sqrt(self.a ** 2 + self.b ** 2 + self.c ** 2)

    @staticmethod
    def from_vectors(u: np.array, v: np.array, point: np.array = (0, 0, 0)) -> Plane:
        """
        Returns the Plane defined with the two given vectors, starting from the 'point'.

        Args:
            u     (np.array): Vector u.
            v     (np.array): Vector v.
            point (np.array): Starting point.

        Returns:
            Plane: Plane defined by the triplet (point, u(vect), v(vect)).

        """

        normal = np.cross(u, v)
        a, b, c = normal
        d = -(a * point[0] + b * point[1] + c * point[2])
        return Plane(a, b, c, d)

    @staticmethod
    def from_points(P: np.array, Q: np.array, R: np.array) -> Plane:
        """
        Returns the Plane defined by those 3 points.

        Returns the Plane defined by (P, PQ(vect), PR(vect))

        Args:
            P (np.array): First point.
            Q (np.array): Second point.
            R (np.array): Third point.

        Returns:
            Plane: Plane defined by those 3 points.

        """

        PQ = vector.vector(P, Q)
        PR = vector.vector(P, R)
        return Plane.from_vectors(PQ, PR, P)


import sympy as sym

# Computing with Dirichlet conditions: -u''=2 and sines
x, L = sym.symbols('x L')
e_Galerkin = x*(L-x) - 8*L**2*sym.pi**(-3)*sym.sin(sym.pi*x/L)
e_colloc = x*(L-x) - 2*L**2*sym.pi**(-2)*sym.sin(sym.pi*x/L)

# Verify max error for x=L/2
dedx_Galerkin = sym.diff(e_Galerkin, x)
print((dedx_Galerkin.subs(x, L/2)))
dedx_colloc = sym.diff(e_colloc, x)
print((dedx_colloc.subs(x, L/2)))

# Compute max error: x=L/2, evaluate numerical, and simplify
print(('Max error Galerkin/least.sq.:', \
      sym.simplify(e_Galerkin.subs(x, L/2).evalf(n=3))))
print(('Max error colloc.:', \
      sym.simplify(e_colloc.subs(x, L/2).evalf(n=3))))
import sys
#sys.exit(0)

# Computing with Neumann and Dirichlet conditions: -u''=2
x, C, D = sym.symbols('x C D')
i, j = sym.symbols('i j', integer=True)

integrand = (i+1)*(j+1)*(1-x)**(i+j)
A_ij = sym.integrate(integrand, (x, 0, 1))
A_ij = sym.simplify(A_ij)
print(A_ij)
psi_i = (1-x)**(i+1)
integrand = 2*psi_i - D*(i+1)*(1-x)**i
b_i = sym.integrate(integrand, (x, 0, 1)) - C*psi_i.subs(x, 0)
b_i = sym.factor(sym.simplify(b_i))
print(b_i)
print((sym.expand(2 - (2+i)*(D+C))))

# Solving model2 problem with f(x) and fe1D.py
from u_xx_f_sympy import model2, x, C, D, L
m = 2
u = model2(x**m, L, C, D)
print(u)
#u_exact = lambda x: D + C*(x-L) + (1./6)*(L**3 - x**3)
u_exact = sym.lambdify([x, C, D, L], u)

import numpy as np
from fe1D import finite_element1D_naive, mesh_uniform
# Override C, D and L with numeric values
C = 5
D = 2
L = 4

d = 1

vertices, cells, dof_map = mesh_uniform(
    N_e=2, d=d, Omega=[0,L], symbolic=False)
vertices[1] = 3
essbc = {}
essbc[dof_map[-1][-1]] = D

c, A, b, timing = finite_element1D_naive(
    vertices, cells, dof_map,
    essbc,
    ilhs=lambda e, phi, r, s, X, x, h:
    phi[1][r](X, h)*phi[1][s](X, h),
    irhs=lambda e, phi, r, X, x, h:
    x**m*phi[0][r](X),
    blhs=lambda e, phi, r, s, X, x, h: 0,
    brhs=lambda e, phi, r, X, x, h:
    -C*phi[0][r](-1) if e == 0 else 0,
    intrule='GaussLegendre',
    verbose=False,
    )

# Visualize
from fe1D import u_glob
x, u, nodes = u_glob(c, cells, vertices, dof_map)
u_e = u_exact(x, C, D, L)
print((u_exact(nodes, C, D, L) - c))  # difference at the nodes
import matplotlib.pyplot as plt
plt.plot(x, u, 'b-', x, u_e, 'r--')
plt.legend(['finite elements, d=%d' %d, 'exact'], loc='upper left')
plt.savefig('tmp.png'); plt.savefig('tmp.pdf')
plt.show()


import numpy as np
from math import log

# sigmoid activation as per example
def sigmoid(x):
    return 1.0 / (1.0+np.exp(-x))

def sigmoid_activation(x):
    return sigmoid(x)

# inverted sigmoid activation
def inv_sigmoid(x):
    return -1.0 * np.log((1.0-x)/x) if x > 0.0 else 0.0

def inv_sigmoid_activation(x):
    return inv_sigmoid(x)

# corresponding derivative
def sigmoid_prime(x):
    return np.multiply(sigmoid_activation(x), (1-sigmoid_activation(x)))

# loss function
def dot_loss(p, b):
    e = p - b
    esq = e.dot(e.T)
    return np.sum(np.array(esq)), e

# vector of partial derivatives for the output activations
def cost_derivative(out_act, y):
    return out_act - y

# softmax
def softmax(x):
    return np.exp(x) / np.sum(np.exp(x))

def softmax_activation(x):
    return softmax(x)

# relu
def relu(self, x):
    return np.maximum(0, x)

def relu_prime(self, x):
    return 1. * (x > 0)

# Sample generator
def next_batch(x, y, batchsize):
    for i in np.arange(0, x.shape[0], batchsize):
        yield (np.asarray(x)[i:i + batchsize], np.asarray(y)[i:i + batchsize])

# Stats for signal and background for a given cut
def scanPoint(cutVal, sig, bkg):
    totSig = len(sig)
    totBKG = len(bkg)
    sig_pass = [v for v in sig if v > cutVal]
    bkg_rej = [v for v in bkg if v < cutVal]
    bkg_pass = [v for v in bkg if v > cutVal]
    eff_sig = float(len(sig_pass))/float(totSig)
    rej_bkg = float(len(bkg_rej))/float(totBKG)
    return eff_sig, rej_bkg, len(sig_pass), len(bkg_pass)

def swap_as_needed(mode, shape1, shape2):
    """
    If in 'valid' mode, returns whether or not the input arrays need to be
    swapped depending on whether `shape1` is at least as large as `shape2` in
    every dimension.
    Otherwise False is immediately returned.
    """
    if mode == 'valid':
        ok1, ok2 = True, True
        for d1, d2 in zip(shape1, shape2):
            if not d1 >= d2:
                ok1 = False
            if not d2 >= d1:
                ok2 = False
        if not (ok1 or ok2):
            raise ValueError("For 'valid' mode, one must be at least "
                             "as large as the other in every dimension")
        return not ok1
    return False

def pad_as_needed(inpt, fltr_shape, mode = 'fill', fillval = 0):
    mode = 'constant' if mode == 'fill' else mode
    inpt_dim = np.ndim(inpt)
    pad_width = [(0,0) for idx in range(inpt_dim)]
    shps = np.subtract(fltr_shape, inpt.shape)
    for idx in range(np.ndim(inpt)):
        pad_width[idx] = (0, shps[idx] if shps[idx] >= 0 else 0)
    p_inpt = None
    if mode == 'constant':
        p_inpt = np.pad(inpt, pad_width, mode, constant_values = (fillval, fillval))
    else:
        p_inpt = np.pad(inpt, pad_width, mode)
    return p_inpt

def transform_as_needed(inpt, fltr, mode = 'full', pad_mode = 'fill', fillval = 0):
    if mode not in ['full', 'valid', 'same']:
        raise ValueError('Acceptable mode flags are \'full\', \'valid\', \'same\' only')
    if pad_mode not in ['fill', 'wrap', 'symmetric']:
        raise ValueError('Acceptable mode flags are \'fill\', \'wrap\', \'symmetric\' only')
    if swap_as_needed(mode, inpt.shape, fltr.shape):
        new_fltr, new_inpt = inpt, fltr  # swap input and filter
    else:
        new_fltr, new_inpt = fltr, inpt
    return pad_as_needed(inpt, new_fltr.shape, pad_mode, fillval), new_fltr

def _conv2d(fltr, subM, strides = (1, 1)):
    if np.ndim(strides) > 1:
        raise ValueError('Valid strides are single integer or tuple/list of dimension 1')
    if np.ndim(strides) == 0:
        return np.einsum('ij,ijkl->kl', fltr, subM)[::strides, ::strides, ...]
    else:
        return np.einsum('ij,ijkl->kl', fltr, subM)[::strides[0], ::strides[1], ...]

def _subM(inpt, fltr_shape):
    subshp = fltr_shape + tuple(np.subtract(inpt.shape, fltr_shape) + 1)  # order of summation important
    strd = np.lib.stride_tricks.as_strided
    subM = strd(inpt, shape = subshp, strides = inpt.strides * 2)
    return subM

def conv2d(inpt, fltr, mode = 'full', pad_mode = 'fill', fillval = 0, strides = (1, 1)):
    _inpt = np.asarray(inpt)
    _fltr = np.flip(np.asarray(fltr))  # flip kernel as per definition
    if np.ndim(_inpt) != 2 or np.ndim(_fltr) != 2:
        raise ValueError('Single convolution input (single channel) and filter must be 2-D arrays')
    _inpt, _fltr = transform_as_needed(_inpt, _fltr, mode, pad_mode, fillval)
    subM = _subM(_inpt, _fltr.shape)
    return _conv2d(_fltr, subM, strides)

def get_class(class_name):
    parts = str(class_name).split('.')
    module_name = ".".join(parts[:-1])
    module = __import__(module_name)
    if parts == str(class_name):
        return module
    for comp in parts[1:]:
        module = getattr(module, comp)
    return module


# authors:
# Jan Pavovský : 618792cf-25ec-11e8-9de3-00505601122b
# Jaroslav Knotek :

#!/usr/bin/env python3
import numpy as np

if __name__ == "__main__":
    # Load data distribution, each data point on a line

    dataPointList = {}
    modelList={}

    with open("numpy_entropy_data.txt", "r") as data:
        for line in data:
            line = line.rstrip("\n")
            # TODO: process the line, aggregating using Python data structures
            if(line in dataPointList):
                dataPointList[line] += 1
            else:
                dataPointList[line] = 1
                modelList[line] = 0.

    # TODO: Create a NumPy array containing the data distribution. The
    # NumPy array should contain only data, not any mapping. If required,
    # the NumPy array might be created after loading the model distribution.

    # Load model distribution, each line `word \t probability`.
    with open("numpy_entropy_model.txt", "r") as model:
        for line in model:
            line = line.rstrip("\n")
            # TODO: process the line, aggregating using Python data structures
            tokens = line.split("\t")
            if(tokens[0] in modelList):
                modelList[tokens[0]] = float(tokens[1])

    data = np.array(list(dataPointList.values()))
    dist = data / np.sum(data)

    model = np.array(list(modelList.values()))

    # TODO: Create a NumPy array containing the model distribution.

    # TODO: Compute and print the entropy H(data distribution). You should not use
    # manual for/while cycles, but instead use the fact that most NumPy methods
    # operate on all elements (for example `*` is vector element-wise multiplication).

    entropy=-(np.sum(np.log(dist) * dist))

    print("{:.2f}".format(entropy))

    cross_entropy=-(np.sum(np.log(model) * dist))

    print("{:.2f}".format(cross_entropy))

    kl= cross_entropy - entropy

    print("{:.2f}".format(kl))

    # TODO: Compute and print cross-entropy H(data distribution, model distribution)
    # and KL-divergence D_KL(data distribution, model_distribution)


""" Example showing how to combine several NURBS curves into a single NURBS curve
    The NURBS curve must be of the same order to merge them
    Merging curves of different degree would require degree elevation (not implemented yet)

"""

# -------------------------------------------------------------------------------------------------------------------- #
# Importing packages
# -------------------------------------------------------------------------------------------------------------------- #
import numpy as np
import nurbspy as nrb
import matplotlib.pyplot as plt

# -------------------------------------------------------------------------------------------------------------------- #
# Create the first NURBS curve
# -------------------------------------------------------------------------------------------------------------------- #
# Define the array of control points
P = np.zeros((2,8))
P[:, 0] = [0.00, 0.00]
P[:, 1] = [0.10, 0.50]
P[:, 2] = [0.20, -0.50]
P[:, 3] = [0.30, 0.00]
P[:, 4] = [0.40, 0.10]
P[:, 5] = [0.50, 0.20]
P[:, 6] = [0.60, 0.30]
P[:, 7] = [0.75, 0.00]

# Define the array of control weights
W = np.asarray([1, 1, 1, 1, 2, 2, 2, 2])

# Highest index of the control points (counting from zero)
n = np.shape(P)[1] - 1

# Define the order of the basis polynomials
p = 3

# Define the knot vector (clamped spline)
# p+1 zeros, n-p equispaced points between 0 and 1, and p+1 ones.  In total r+1 points where r=n+p+1
U = np.concatenate((np.zeros(p), np.linspace(0, 1, n - p + 2), np.ones(p)))

# Create the B-Spline curve
nurbs1 = nrb.NurbsCurve(control_points=P, weights=W, degree=p, knots=U)

# -------------------------------------------------------------------------------------------------------------------- #
# Create the second NURBS curve
# -------------------------------------------------------------------------------------------------------------------- #
# Define the array of control points
P = np.zeros((2,4))
P[:, 0] = [0.75, 0.00]
P[:, 1] = [1.00, 0.50]
P[:, 2] = [1.25, -0.50]
P[:, 3] = [1.50, 0.00]

# Define the array of control weights
W = np.asarray([5, 2, 2, 4])

# Highest index of the control points (counting from zero)
n = np.shape(P)[1] - 1

# Define the order of the basis polynomials
p = 3

# Define the knot vector (clamped spline)
# p+1 zeros, n-p equispaced points between 0 and 1, and p+1 ones.  In total r+1 points where r=n+p+1
U = np.concatenate((np.zeros(p), np.linspace(0, 1, n - p + 2), np.ones(p)))

# Create the B-Spline curve
nurbs2 = nrb.NurbsCurve(control_points=P, weights=W, degree=p, knots=U)

# -------------------------------------------------------------------------------------------------------------------- #
# Create the third NURBS curve
# -------------------------------------------------------------------------------------------------------------------- #
# Define the array of control points
P = np.zeros((2,5))
P[:, 0] = [1.50, 0.00]
P[:, 1] = [2.00, 0.50]
P[:, 2] = [1.50, 0.75]
P[:, 3] = [1.00, 0.60]
P[:, 4] = [0.50, 0.30]

# Define the array of control weights
W = np.asarray([1, 1, 1, 1, 1])

# Highest index of the control points (counting from zero)
n = np.shape(P)[1] - 1

# Define the order of the basis polynomials
p = 3

# Define the knot vector (clamped spline)
# p+1 zeros, n-p equispaced points between 0 and 1, and p+1 ones.  In total r+1 points where r=n+p+1
U = np.concatenate((np.zeros(p), np.linspace(0, 1, n - p + 2), np.ones(p)))

# Create the B-Spline curve
nurbs3 = nrb.NurbsCurve(control_points=P, weights=W, degree=p, knots=U)

# -------------------------------------------------------------------------------------------------------------------- #
# Merge the NURBS curves
# -------------------------------------------------------------------------------------------------------------------- #
nurbsMerged = (nurbs1.attach_nurbs(nurbs2)).attach_nurbs(nurbs3)

# -------------------------------------------------------------------------------------------------------------------- #
# Plot the NURBS curves
# -------------------------------------------------------------------------------------------------------------------- #
fig, ax = nurbsMerged.plot(curve=False, control_points=False)
nurbs1.plot_curve(fig, ax, color='green', linewidth=2)
nurbs2.plot_curve(fig, ax, color='red',   linewidth=2)
nurbs3.plot_curve(fig, ax, color='blue',  linewidth=2)
nurbsMerged.plot_curve(fig, ax, color='w', linewidth=1, linestyle=':')
plt.show()


# 0501-lin-inter.py
# Linear interpolation
# Sparisoma Viridi | https://github.com/dudung
# 20220221 Create this example.

# import package
import numpy as np

# define data points
x = [1, 4, 7, 10]
y = [11, 18, 7, 5]

# create coefficients c0 and c1 with zero values
c0 = [0, 0, 0]
c1 = [0, 0, 0]

# calculate c0 and c1
N = len(c0)
for i in range(N):
  c1[i] = (y[i+1] - y[i]) / (x[i+1] - x[i])
  c0[i] = y[i] - c1[i] * x[i]

# define linear interpolation function f(x)
def f(xx):
    i = int(np.floor((xx - x[0])/(x[1] - x[0])))
    if i > N - 1:
        i = i - 1
    y = c0[i] + c1[i] * xx
    return y

# use the function
for xx in range(1, 11):
  yy = f(xx)
  print(xx, yy)


#---------------------------------------------------------------------
# File Name   : LinearRegression.py
# Author      : Kunal K.
# Description : Implementing Linear Regression
# Date:       : 11 Nov. 2020
# Version     : V1.0
# Ref No      : DS_Code_P_K07
#---------------------------------------------------------------------

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

# reading a csv file using pandas library
wcat=pd.read_csv("wc-at.csv")
wcat.columns

plt.hist(wcat.Waist)
plt.boxplot(wcat.Waist,0,"rs",0)

plt.hist(wcat.AT)
plt.boxplot(wcat.AT)

plt.plot(wcat.Waist,wcat.AT,"bo");plt.xlabel("Waist");plt.ylabel("AT")

wcat.AT.corr(wcat.Waist) # # correlation value between X and Y
np.corrcoef(wcat.AT,wcat.Waist)

# For preparing linear regression model we need to import the statsmodels.formula.api
import statsmodels.formula.api as smf
model=smf.ols("AT~Waist",data=wcat).fit()

# For getting coefficients of the varibles used in equation
model.params

# P-values for the variables and R-squared value for prepared model
model.summary()

model.conf_int(0.05) # 95% confidence interval

pred = model.predict(wcat.iloc[:,0]) # Predicted values of AT using the model

# Visualization of regresion line over the scatter plot of Waist and AT
# For visualization we need to import matplotlib.pyplot
import matplotlib.pylab as plt
plt.scatter(x=wcat['Waist'],y=wcat['AT'],color='red');plt.plot(wcat['Waist'],pred,color='black');plt.xlabel('WAIST');plt.ylabel('TISSUE')

pred.corr(wcat.AT) # 0.81

# Transforming variables for accuracy
model2 = smf.ols('AT~np.log(Waist)',data=wcat).fit()
model2.params
model2.summary()
print(model2.conf_int(0.01)) # 99% confidence level
pred2 = model2.predict(pd.DataFrame(wcat['Waist']))
pred2.corr(wcat.AT)
# pred2 = model2.predict(wcat.iloc[:,0])
pred2
plt.scatter(x=wcat['Waist'],y=wcat['AT'],color='green');plt.plot(wcat['Waist'],pred2,color='blue');plt.xlabel('WAIST');plt.ylabel('TISSUE')

# Exponential transformation
model3 = smf.ols('np.log(AT)~Waist',data=wcat).fit()
model3.params
model3.summary()
print(model3.conf_int(0.01)) # 99% confidence level
pred_log = model3.predict(pd.DataFrame(wcat['Waist']))
pred_log
pred3=np.exp(pred_log)  # as we have used log(AT) in preparing model so we need to convert it back
pred3
pred3.corr(wcat.AT)
plt.scatter(x=wcat['Waist'],y=wcat['AT'],color='green');plt.plot(wcat.Waist,np.exp(pred_log),color='blue');plt.xlabel('WAIST');plt.ylabel('TISSUE')
resid_3 = pred3-wcat.AT
# so we will consider the model having highest R-Squared value which is the log transformation - model3
# getting residuals of the entire data set
student_resid = model3.resid_pearson
student_resid
plt.plot(model3.resid_pearson,'o');plt.axhline(y=0,color='green');plt.xlabel("Observation Number");plt.ylabel("Standardized Residual")

# Predicted vs actual values
plt.scatter(x=pred3,y=wcat.AT);plt.xlabel("Predicted");plt.ylabel("Actual")

# Quadratic model
wcat["Waist_Sq"] = wcat.Waist*wcat.Waist
model_quad = smf.ols("AT~Waist+Waist_Sq",data=wcat).fit()
model_quad.params
model_quad.summary()
pred_quad = model_quad.predict(wcat.Waist)

model_quad.conf_int(0.05) #
plt.scatter(wcat.Waist,wcat.AT,c="b");plt.plot(wcat.Waist,pred_quad,"r")

plt.scatter(np.arange(109),model_quad.resid_pearson);plt.axhline(y=0,color='red');plt.xlabel("Observation Number");plt.ylabel("Standardized Residual")

plt.hist(model_quad.resid_pearson) # histogram for residual values

############################### Implementing the Linear Regression model from sklearn library

from sklearn.linear_model import LinearRegression
import numpy as np
plt.scatter(wcat.Waist,wcat.AT)
model1 = LinearRegression()
model1.fit(wcat.Waist.values.reshape(-1,1),wcat.AT)
pred1 = model1.predict(wcat.Waist.values.reshape(-1,1))
# Adjusted R-Squared value
model1.score(wcat.Waist.values.reshape(-1,1),wcat.AT)# 0.6700
rmse1 = np.sqrt(np.mean((pred1-wcat.AT)**2)) # 32.760
model1.coef_
model1.intercept_

#### Residuals Vs Fitted values
import matplotlib.pyplot as plt
plt.scatter(pred1,(pred1-wcat.AT),c="r")
plt.hlines(y=0,xmin=0,xmax=300)
# checking normal distribution for residual
plt.hist(pred1-wcat.AT)

### Fitting Quadratic Regression
wcat["Waist_sqrd"] = wcat.Waist*wcat.Waist
model2 = LinearRegression()
model2.fit(X = wcat.iloc[:,[0,2]],y=wcat.AT)
pred2 = model2.predict(wcat.iloc[:,[0,2]])
# Adjusted R-Squared value
model2.score(wcat.iloc[:,[0,2]],wcat.AT)# 0.67791
rmse2 = np.sqrt(np.mean((pred2-wcat.AT)**2)) # 32.366
model2.coef_
model2.intercept_
#### Residuals Vs Fitted values
import matplotlib.pyplot as plt
plt.scatter(pred2,(pred2-wcat.AT),c="r")
plt.hlines(y=0,xmin=0,xmax=200)
# Checking normal distribution
plt.hist(pred2-wcat.AT)
import pylab
import scipy.stats as st
st.probplot(pred2-wcat.AT,dist="norm",plot=pylab)

# Let us prepare a model by applying transformation on dependent variable
wcat["AT_sqrt"] = np.sqrt(wcat.AT)

model3 = LinearRegression()
model3.fit(X = wcat.iloc[:,[0,2]],y=wcat.AT_sqrt)
pred3 = model3.predict(wcat.iloc[:,[0,2]])
# Adjusted R-Squared value
model3.score(wcat.iloc[:,[0,2]],wcat.AT_sqrt)# 0.74051
rmse3 = np.sqrt(np.mean(((pred3)**2-wcat.AT)**2)) # 32.0507
model3.coef_
model3.intercept_
#### Residuals Vs Fitted values
import matplotlib.pyplot as plt
plt.scatter((pred3)**2,((pred3)**2-wcat.AT),c="r")
plt.hlines(y=0,xmin=0,xmax=300)
# checking normal distribution for residuals
plt.hist((pred3)**2-wcat.AT)
st.probplot((pred3)**2-wcat.AT,dist="norm",plot=pylab)

# Let us prepare a model by applying transformation on dependent variable without transformation on input variables
model4 = LinearRegression()
model4.fit(X = wcat.Waist.values.reshape(-1,1),y=wcat.AT_sqrt)
pred4 = model4.predict(wcat.Waist.values.reshape(-1,1))
# Adjusted R-Squared value
model4.score(wcat.Waist.values.reshape(-1,1),wcat.AT_sqrt)# 0.7096
rmse4 = np.sqrt(np.mean(((pred4)**2-wcat.AT)**2)) # 34.165
model4.coef_
model4.intercept_
#### Residuals Vs Fitted values
import matplotlib.pyplot as plt
plt.scatter((pred4)**2,((pred4)**2-wcat.AT),c="r")
plt.hlines(y=0,xmin=0,xmax=300)

st.probplot((pred4)**2-wcat.AT,dist="norm",plot=pylab)

# Checking normal distribution for residuals
plt.hist((pred4)**2-wcat.AT)

import numpy,import scipy,import statsmodels


import numpy as np

def _L1Reg(ThetaW,L1,m):
	L = np.size(ThetaW)
	Reg = 0.0
	for i in range(0,L-1):
		T = ThetaW[i]
		Reg += L1/(2.0*m) * np.sum(np.abs(T))
	return Reg

def _L2Reg(ThetaW,L2,m):
	L = np.size(ThetaW)
	Reg = 0.0
	for i in range(0,L-1):
		T = ThetaW[i]
		Reg += L2/(2.0*m) * np.sum(T**2.0)
	return Reg


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Dec  2 15:37:10 2020

Copyright 2020 by Hadrien Montanelli.
"""
# %% Imports.

# Standard library imports:
import matplotlib.pyplot as plt
import numpy as np
import time

# Chebpy imports:
from chebpy.cheb import chebpts, diffmat, spconvert, vals2coeffs

# %% First-order differentiation on [-1, 1].

# Function:
w = 100
f = lambda x: np.cos(w*x)
dfex = lambda x: -w*np.sin(w*x)

# Grid:
n = 4*w
dom = [-1, 1]
x = chebpts(n, dom)

# Compute coeffs of f:
F = vals2coeffs(f(x))

# Differentiation matrix in coefficient space:
start = time.time()
D = diffmat(n, 1, dom)
end = time.time()
print(f'Time   (setup): {end-start:.5f}s')
plt.figure()
plt.spy(D)

# Differentiate:
start = time.time()
DF = D @ F
end = time.time()
print(f'Time (product): {end-start:.5f}s')

# Exact coefficients
S0 = spconvert(n, 0)
DFex = S0 @ vals2coeffs(dfex(x))

# Error:
error = np.max(np.abs(DF - DFex))/np.max(np.abs(DFex))
print(f'Error  (L-inf): {error:.2e}')

# %% Second-order differentiation on [0, 2].

# Function:
w = 100
f = lambda x: np.cos(w*x)
d2fex = lambda x: -w**2*np.cos(w*x)

# Grid:
n = 4*w
dom = [0, 2]
x = chebpts(n, dom)

# Compute coeffs of f:
F = vals2coeffs(f(x))

# Differentiation matrix in coefficient space:
start = time.time()
D2 = diffmat(n, 2, dom)
end = time.time()
print(f'Time   (setup): {end-start:.5f}s')
plt.figure()
plt.spy(D2)

# Differentiate:
start = time.time()
D2F = D2 @ F
end = time.time()
print(f'Time (product): {end-start:.5f}s')

# Exact coefficients
S0 = spconvert(n, 0)
S1 = spconvert(n, 1)
D2Fex = S1 @ S0 @ vals2coeffs(d2fex(x))

# Error:
error = np.max(np.abs(D2F - D2Fex))/np.max(np.abs(D2Fex))
print(f'Error  (L-inf): {error:.2e}')


# coding: utf-8
"""
Created on Mon May 17 00:00:00 2017

@author: DIP
"""

# # Import necessary dependencies and settings

# In[1]:

from sklearn.preprocessing import StandardScaler, MinMaxScaler, RobustScaler
import numpy as np
import pandas as pd
np.set_printoptions(suppress=True)

# # Load sample data of video views

# In[2]:

views = pd.DataFrame([1295., 25., 19000., 5., 1., 300.], columns=['views'])
views

# # Standard Scaler $\frac{x_i - \mu}{\sigma}$

# In[3]:

ss = StandardScaler()
views['zscore'] = ss.fit_transform(views[['views']])
views

# In[4]:

vw = np.array(views['views'])
(vw[0] - np.mean(vw)) / np.std(vw)

# # Min-Max Scaler $\frac{x_i - min(x)}{max(x) - min(x)}$

# In[5]:

mms = MinMaxScaler()
views['minmax'] = mms.fit_transform(views[['views']])
views

# In[6]:

(vw[0] - np.min(vw)) / (np.max(vw) - np.min(vw))

# # Robust Scaler $\frac{x_i - median(x)}{IQR_{(1,3)}(x)}$

# In[7]:

rs = RobustScaler()
views['robust'] = rs.fit_transform(views[['views']])
views

# In[8]:

quartiles = np.percentile(vw, (25., 75.))
iqr = quartiles[1] - quartiles[0]
(vw[0] - np.median(vw)) / iqr


import numpy as np
from matplotlib import pyplot as plt

def Newtons_method(f, x0, Df, iters=15, tol=.002):
    '''Use Newton's method to approximate a zero of a function.

    INPUTS:
    f     - A function handle. Should represent a function from
            R to R.
    x0    - Initial guess. Should be a float.
    Df    - A function handle. Should represent the derivative
            of `f`.
    iters - Maximum number of iterations before the function
            returns. Defaults to 15.
    tol   - The function returns when the difference between
            successive approximations is less than `tol`.

    RETURN:
    A tuple (x, converged, numiters) with
    x           - the approximation to a zero of `f`
    converged   - a Boolean telling whether Newton's method
                converged
    numiters    - the number of iterations the method computed
    '''
    xold = float(x0)
    n = 0
    converged = False
    while n <= iters:
        xnew = xold - f(xold)/Df(xold)
        if np.abs(xnew-xold) < tol:
            converged = True
            break
        else:
            xold = xnew
            n += 1
            print xold
    return (xnew, converged, n)

def plot_basins(f, Df, roots, xmin, xmax, ymin, ymax, numpoints=100, iters=15, colormap='brg'):
    '''Plot the basins of attraction of f.

    INPUTS:
    f       - A function handle. Should represent a function
            from C to C.
    Df      - A function handle. Should be the derivative of f.
    roots   - An array of the zeros of f.
    xmin, xmax, ymin, ymax - Scalars that define the domain
            for the plot.
    numpoints - A scalar that determines the resolution of
            the plot. Defaults to 100.
    iters   - Number of times to iterate Newton's method.
            Defaults to 15.
    colormap - A colormap to use in the plot. Defaults to 'brg'.
    '''
    xreal = np.linspace(xmin, xmax, numpoints)
    ximag = np.linspace(ymin, ymax, numpoints)
    Xreal, Ximag = np.meshgrid(xreal, ximag)
    xold = Xreal+1j*Ximag
    n = 0
    while n <= iters:
        xnew = xold - f(xold)/Df(xold)
        xold = xnew
        n += 1

    converged_to = np.empty_like(xnew)
    for i in xrange(xnew.shape[0]):
        for j in xrange(xnew.shape[1]):
            root = np.abs(roots-xnew[i,j]).argmin()
            converged_to[i,j] = root

    plt.pcolormesh(Xreal, Ximag, converged_to, cmap=colormap)


import numpy as np
from scipy import signal
from timeit import default_timer as timer

def conv2d_direct(x, w):
    w = np.flip(np.flip(w, 0), 1)
    rows = x.shape[0]
    cols = x.shape[1]
    kh = w.shape[0]
    kw = w.shape[1]
    rst = np.zeros((rows-kh+1, cols-kw+1))
    for i in range(rst.shape[0]):
        for j in range(rst.shape[1]):
            tmp = 0.
            for ki in range(kh):
                for kj in range(kw):
                    tmp += x[i+ki][j+kj] * w[ki][kj]
            rst[i][j] = tmp
    return rst

def conv2d_fft(x, w):
    # return signal.fftconvolve(x, w, mode='valid')
    size = np.array(x.shape) + np.array(w.shape) - 1
    fsize = 2 ** np.ceil(np.log2(size)).astype(int)
    fslice = tuple([slice(kn-1, int(sz)-kn+1) for sz, kn in zip(size, w.shape)])
    x_fft = np.fft.fft2(x , fsize)
    w_fft = np.fft.fft2(w , fsize)
    rst = np.fft.ifft2(x_fft * w_fft)
    rst = rst[fslice].real
    return rst

def im2col(x, stride=1):
    # https://stackoverflow.com/a/30110497/3829845
    rows = x.shape[0]
    cols = x.shape[1]
    kh = w.shape[0]
    kw = w.shape[1]
    s0, s1 = x.strides
    nrows = rows-kh+1
    ncols = cols-kw+1
    shape = kh, kw, nrows, ncols
    slides = s0, s1, s0, s1
    L = kh*kw

    x_unfold = np.lib.stride_tricks.as_strided(x, shape=shape, strides=slides)
    return x_unfold.reshape(L, -1)[:,::stride]

def conv2d_gemm(x, w, stride=1):
    w = np.flip(np.flip(w, 0), 1)
    rows = x.shape[0]
    cols = x.shape[1]
    kh = w.shape[0]
    kw = w.shape[1]
    L = kh*kw

    x_unfold = im2col(x)
    y_unfold = np.matmul(x_unfold.transpose(), w.reshape((L, 1)))
    return y_unfold.reshape(rows-kh+1, cols-kw+1)

x = np.random.randn(512, 512)
w = np.random.randn(5, 5)
# x = np.ones((12, 12))
# w = np.ones((5, 5))
# x = np.arange(16).reshape((4,4))
# w = np.arange(9).reshape((3,3))

start = timer()
rst0 = signal.convolve2d(x, w, mode='valid')
end = timer()
print('Elapsed time (reference): {}'.format(end - start))

# print(rst0.shape)
# print(rst0)

start = timer()
rst1 = conv2d_direct(x, w)
end = timer()
print('Elapsed time (direct): {}'.format(end - start))

# print(rst1.shape)
# print(rst1)
error1 = np.max(np.abs(rst1 - rst0))
print('Error: {}'.format(error1))

start = timer()
rst2 = conv2d_fft(x, w)
end = timer()
print('Elapsed time (FFT): {}'.format(end - start))

# print(rst2.shape)
# print(rst2)
error2 = np.max(np.abs(rst2 - rst0))
print('Error: {}'.format(error2))

start = timer()
rst3 = conv2d_gemm(x, w)
end = timer()
print('Elapsed time (im2col): {}'.format(end - start))

# print(rst3.shape)
# print(rst3)
error3 = np.max(np.abs(rst3 - rst0))
print('Error: {}'.format(error3))

import torch

inp = torch.randn(1, 1, 512, 512)
w = torch.randn(1, 1, 5, 5)
start = timer()
inp_unf = torch.nn.functional.unfold(inp, (5, 5))
# print(inp_unf.shape)
out_unf = inp_unf.transpose(1, 2).matmul(w.view(w.size(0), -1).t()).transpose(1, 2)
# print(out_unf.shape)
# out = torch.nn.functional.fold(out_unf, (508, 508), (1, 1))
out = out_unf.view(1, 1, 508, 508)
end = timer()
print('Elapsed time (nn.Unfold): {}'.format(end - start))
error4 = (torch.nn.functional.conv2d(inp, w) - out).abs().max()
print('Error: {}'.format(error4))


# -*- coding: utf-8 -*-
"""
Created on Thu Sep  9 11:36:44 2021

@author: HP
"""

# Learning how DCT actually works

import matplotlib.pyplot as plt
import numpy as np
import scipy.fft as spfft

original_ts = np.array([0, 0.707, 1, 0.707, 0, -0.707, -1, -0.707])
L = len(original_ts)
plt.plot(original_ts, "p")
plt.title("Original Time Series of Lenght L = {}".format(L))

# Deriving the DCT co-effecients manually now
def get_Xk(Xs,k):
    '''
    calculate the Fourier coefficient X_n of
    Discrete Fourier Transform (DFT)
    '''
    L  = len(Xs)
    ns = np.arange(0,L,1)
    terms = 2*Xs*np.cos((np.pi*k*(1/2+ns))/L)
    terms[0]  *= np.sqrt(1/(4*L))
    terms[1:] *= np.sqrt(1/(2*L))
    xn = np.sum(terms)
    return(xn)

xs =[]
for n in range(L):
    x = get_Xk(original_ts,n)
    xs.append(x)
    print("DCT coefficient: x_{}={:+3.2f}".format(n,x))

# Our 7 Point signal is now in DCT Domain

# Getting back our original time series signal

def get_xn(xs,n):
    L = len(xs)
    ks = np.arange(1,L,1)
    out = 1/2*xs[0]
    out += np.sum(xs[1:]*np.cos(np.pi/L*ks*(n+1/2)))
    return(out*2/L)

def get_xn(Xs,n):
    '''
    calculate the Fourier coefficient X_n of
    Discrete Fourier Transform (DFT)
    '''
    L  = len(Xs)
    ks = np.arange(0,L,1)
    terms = Xs*np.cos((np.pi*ks*(1/2+n))/L)*2
    terms[0]  *= np.sqrt(1/(4*L))
    terms[1:] *= np.sqrt(1/(2*L))
    xn = np.sum(terms)
    return(xn)

for n in range(L):
    Xn = get_xn(xs,n)
    print("Reproduced original series {:+5.3f}".format(Xn))

# Doing using just functions

original_time = np.array([0, 0.707, 1, 0.707, 0, -0.707, -1, -0.707])
dct_domain = spfft.dct(original_time, type = 2, norm = "ortho")
idct_domain = spfft.idct(dct_domain, norm = "ortho")
for n in range(len(original_time)):
    print("DCT coefficient using function: x_{}={:+3.2f}".format(n,dct_domain[n]))
    print("IDCT Coeffecient using function: x_{} = {:+3.3f}".format(n, idct_domain[n]))


# code loosely based on https://www.geeksforgeeks.org/partition-set-k-subsets-equal-sum/
# with a lot of changes by @EinGartenzwerg
import numpy as np

def partition_helper(elements, taken,
                     subsetsize, parts, size, curIdx, limitIdx, subsets):
    if np.sum(subsets[curIdx]) == subsetsize:

        # if size - 1 subsets are possible, then the last subset is also possible.
        if curIdx == parts - 2:
            for idx, elem in enumerate(taken):
                if not elem:
                    subsets[parts - 1].append(elements[idx])
            return subsets

        return partition_helper(elements, taken,
                                subsetsize, parts, size, curIdx + 1, size - 1, subsets)

    # start from limitIdx and include
    # elements into current partition
    for i in range(limitIdx, -1, -1):

        if taken[i]:
            continue

        # free space in the partition
        if (np.sum(subsets[curIdx]) + elements[i]) <= subsetsize:

            # Backtracking: Put in
            taken[i] = True
            subsets[curIdx].append(elements[i])

            if partition_helper(elements, taken, subsetsize, parts, size, curIdx, i - 1, subsets):
                return subsets

            # Backtracking: if not solution - take out
            # @Sebastian: Go over standard Backtracking schema
            taken[i] = False
            subsets[curIdx].remove(elements[i])
    return False

# returns true if partitioning possible, else False
def partition(elements, parts, size):

    # array is partition
    if size == 1:
        return elements

    # check if partitioning is possible: not more partitions than elements, elements distributable to partitions
    summe = np.sum(elements)
    if parts < size | summe % size != 0:
        return False

    subsets = [[] for i in range(size)]
    print(subsets)
    # mark all elements as not taken
    taken = [False] * parts

    # init: last element
    taken[parts - 1] = True
    subsets[0].append(elements[parts - 1])
    print(subsets)

    return partition_helper(elements, taken,
                            summe // size, size, parts, 0, parts - 1, subsets)

if __name__ == '__main__':

    test_arr = [4, 5, 96, 90, 5, 100]
    parts = len(test_arr)
    example_size = 3
    res = partition(test_arr, parts, example_size)

    # @Sebastian: explain, why this condition works (no boolean)
    if res:
        print("Partitioning finished:")
        print(res)
    else:
        print("Partitioning not possible.")

    # @Sebastian: for minimal partition:
    # for i in range(parts):
    #     res2 = partition(test_arr, parts, i)
    #     if res2:
    #         print("Partitioning finished:")
    #         print(res2)
    #     else:
    #         print("Partitioning not possible.")


import numpy as np

def convert_fixed_point_to_integer(fixed_point_float: float, n_bits: int) -> int:
    return int(round(fixed_point_float * 2**n_bits))

def convert_to_fixed_point(float_value: float, n_bits: int) -> float:
    f = (1 << n_bits)

    return np.round(float_value * f) * (1.0 / f)

def quantize_data(train_data: np.ndarray, test_data: np.ndarray, number_of_bits: int,
                  flag_save_details_to_file: bool = False, path: str = './'):
    train_data_quantized = np.array([convert_to_fixed_point(x, number_of_bits) for x in train_data])
    test_data_quantized = np.array([convert_to_fixed_point(x, number_of_bits) for x in test_data])

    if flag_save_details_to_file:
        with open(path + 'quantization_comparision.txt', 'w') as file_quantization:
            print(f'Train data size before quantization: {len(train_data)}', file=file_quantization)
            print(f'First element before quantization:\n' +
                  np.array2string(train_data[0], formatter={'float': lambda x: '%.3f' % x}),
                  file=file_quantization)
            print(f'Size after quantization: {len(train_data_quantized)}', file=file_quantization)
            print(f'First element after quantization:\n' +
                  np.array2string(train_data_quantized[0], formatter={'float': lambda x: '%.3f' % x}),
                  file=file_quantization)

    return train_data_quantized, test_data_quantized

def test_convert_to_fixed_point():
    assert convert_to_fixed_point(1 / 3, 2) == 0.25
    assert convert_to_fixed_point(1 / 3, 3) == 0.375

if __name__ == "__main__":
    value = 13 / 16
    print(value)

    for i in range(10, -1, -1):
        value_as_fixed_point = convert_to_fixed_point(value, i)
        print("Number of bits used: " + str(i) + " value: " + str(value_as_fixed_point))
        print("% error: {0:.2f}".format(abs(value - value_as_fixed_point) / value * 100))


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

class point:
    x, z = 0, 0

    def __init__(self, x: float, z: float):
        self.x, self.z = x, z

    def __add__(self, other):
        return point(self.x + other.x, self.z + other.z)

    def __sub__(self, other):
        return point(self.x - other.x, self.z - other.z)

    def __len__(self):
        return 2

    def __str__(self):
        return str(self.x) + "," + str(self.z)

    def dis(self):
        return math.sqrt(self.x ** 2 + self.z ** 2)

class example:
    rho = 1.0

    def __init__(self, rho: float):
        self.rho = rho

    def F(self, p: point):
        return (p.x - 1) ** 2 + (p.z - 2) ** 2

    def subject_to(self, p: point):
        return 2 * p.x + 3 * p.z - 5

    def L(self, p: point, y_t: float):
        return self.F(p) + y_t * self.subject_to(p) + 0.5 * self.rho * (self.subject_to(p) ** 2)

def advance_retreat_method(loss_function: example, lambda_: float, start: point, direction: list, step=0,
                           delta=0.1) -> tuple:
    alpha0, point0 = step, start

    alpha1 = alpha0 + delta
    point1 = point0 + point(direction[0] * delta, direction[1] * delta)
    if loss_function.L(point0, lambda_) < loss_function.L(point1, lambda_):
        while True:
            delta *= 2
            alpha2 = alpha0 - delta
            point2 = point0 - point(direction[0] * delta, direction[1] * delta)
            if loss_function.L(point2, lambda_) < loss_function.L(point0, lambda_):
                alpha1, alpha0 = alpha0, alpha2
                point1, point0 = point0, point2
            else:
                return alpha2, alpha1
    else:
        while True:
            delta *= 2
            alpha2 = alpha1 + delta
            point2 = point1 + point(direction[0] * delta, direction[1] * delta)
            if loss_function.L(point2, lambda_) < loss_function.L(point1, lambda_):
                alpha0, alpha1 = alpha1, alpha2
                point0, point1 = point1, point2
            else:
                return alpha0, alpha2

def golden_search(loss_function: example, lambda_: float, start: point, direction: list, epsilon=0.1) -> float:
    a, b = advance_retreat_method(loss_function, lambda_, start, direction)

    # find the minimum
    golden_num = (math.sqrt(5) - 1) / 2
    p, q = a + (1 - golden_num) * (b - a), a + golden_num * (b - a)
    while abs(a - b) > epsilon:
        f_p = loss_function.L(start + point(direction[0] * p, direction[1] * p), lambda_)
        f_q = loss_function.L(start + point(direction[0] * q, direction[1] * q), lambda_)
        if f_p < f_q:
            b, q = q, p
            p = a + (1 - golden_num) * (b - a)
        else:
            a, p = p, q
            q = a + golden_num * (b - a)

    return (a + b) / 2

def drawResult(loss_function: example, points: list, label: str, epsilon: float, other_label=''):
    plt.figure()
    plt.title(
        label + '(rho=' + str(loss_function.rho) + other_label + ',epsilon=' + str(epsilon) + ',iteration=' + str(
            len(points)) + ')')

    # draw the function and condition
    X = np.arange(-2, 4.5 + 0.05, 0.05)
    Y = np.arange(-2, 3 + 0.05, 0.05)
    Y2 = (5 - 2 * X) / 3
    X, Y = np.meshgrid(X, Y)
    Z1 = loss_function.F(point(X, Y))
    contour2 = plt.contour(X, Y, Z1, colors='k')
    plt.clabel(contour2, fontsize=8, colors='k')

    # draw the result
    x, z = [], []
    for p in points:
        x.append(p.x)
        z.append(p.z)
    plt.plot(x, z, 'b*-')
    contour1 = plt.contour(X, Y, Z1, [loss_function.F(points[-1])], colors='blue')
    plt.clabel(contour1, inline=True, fontsize=8, colors='blue')

    # draw the start point
    plt.scatter(points[0].x, points[0].z, color='blue')
    plt.text(points[0].x, points[0].z, 'start(%.3g,%.3g,%.3g)' % (points[0].x, points[0].z, loss_function.F(points[0])),
             color='blue', verticalalignment='top')
    # draw the end point
    plt.scatter(points[-1].x, points[-1].z, color='blue')
    plt.text(points[-1].x, points[-1].z,
             'end(%.3g,%.3g,%.3g)' % (points[-1].x, points[-1].z, loss_function.F(points[-1])), color='blue',
             verticalalignment='bottom')
    plt.show()


"""
A perfect number is a number for which the sum of its proper divisors is exactly equal to the number. For example, the sum of the proper divisors of 28 would be 1 + 2 + 4 + 7 + 14 = 28, which means that 28 is a perfect number.

A number n is called deficient if the sum of its proper divisors is less than n and it is called abundant if this sum exceeds n.

As 12 is the smallest abundant number, 1 + 2 + 3 + 4 + 6 = 16, the smallest number that can be written as the sum of two abundant numbers is 24. By mathematical analysis, it can be shown that all integers greater than 28123 can be written as the sum of two abundant numbers. However, this upper limit cannot be reduced any further by analysis even though it is known that the greatest number that cannot be expressed as the sum of two abundant numbers is less than this limit.

Find the sum of all the positive integers which cannot be written as the sum of two abundant numbers.

Solution comment:
If b(n) = d(n) + n
    b(n) = b(p1 * p2 * .... * pn) = b(p1) * b(p2) * ... * b(pn)
with
    b(p**a) = sum( p**i for i in range(0, a+1)  )
"""
from numpy import prod

def primes_dict(n):
    primfac = {}
    d = 2
    while d*d <= n:
        while n % d == 0:
            if d in primfac:
                primfac[d] += 1
            else:
                primfac[d] = 1
            n /= d
        d += 1
    if n > 1:
        primfac[n] = 1
    return primfac

def d(n):
    if n <= 1:
        return 0
    primefac = primes_dict(n)
    per_prime = prod([sum(( p**i for i in xrange(primefac[p]+1))) for p in primefac ])
    return per_prime - n

# find abundant numbers less than 28123
abundant = [n for n in xrange(28123) if d(n) > n]

# make a set for faster 'in' testing
# this is absolutely necessary
# as list lookup is O(n),
# compared to set lookup which is O(1)
abundant_set = set(abundant)

# store all numbers that is not the sum of two abundants
# use that if n = a1 + a2, then a2 = n - a1
non_sum_of_abundant = []
for n in xrange(1, 28124):
    is_sum_of_abundant = False
    for a in abundant:
        if n - a in abundant_set:
            is_sum_of_abundant = True
            break
        elif a >= n:
            break
    if not is_sum_of_abundant:
        non_sum_of_abundant.append(n)

print 'Sum of all intergers that cannot be written as the sum of two abundant numbers:',
print sum(non_sum_of_abundant)


import numpy as np
import numpy
import matplotlib.pyplot as plt
from time import time
def autocorr1(x,lags):
    '''numpy.corrcoef, partial'''

    corr=[1. if l==0 else numpy.corrcoef(x[l:],x[:-l])[0][1] for l in lags]
    return numpy.array(corr)

def autocorr2(x,lags):
    '''manualy compute, non partial'''

    mean=numpy.mean(x)
    var=numpy.var(x)
    xp=x-mean
    corr=[1. if l==0 else numpy.sum(xp[l:]*xp[:-l])/len(x)/var for l in lags]

    return numpy.array(corr)

def autocorr3(x,lags):
    '''fft, pad 0s, non partial'''

    n=len(x)
    # pad 0s to 2n-1
    ext_size=2*n-1
    # nearest power of 2
    fsize=2**numpy.ceil(numpy.log2(ext_size)).astype('int')

    xp=x-numpy.mean(x)
    var=numpy.var(x)

    # do fft and ifft
    cf=numpy.fft.fft(xp,fsize)
    sf=cf.conjugate()*cf
    corr=numpy.fft.ifft(sf).real
    corr=corr/var/n

    return corr[:len(lags)]

def autocorr4(x,lags):
    '''fft, don't pad 0s, non partial'''
    mean=x.mean()
    var=numpy.var(x)
    xp=x-mean

    cf=numpy.fft.fft(xp)
    sf=cf.conjugate()*cf
    corr=numpy.fft.ifft(sf).real/var/len(x)

    return corr[:len(lags)]

def autocorr5(x,lags):
    '''numpy.correlate, non partial'''
    mean=x.mean()
    var=numpy.var(x)
    xp=x-mean
    corr=numpy.correlate(xp,xp,'full')[len(x)-1:]/var/len(x)

    return corr[:len(lags)]

def autocorr6(x, K):
    freqs = np.fft.rfft(x)
    return np.fft.irfft(freqs * np.conj(freqs))[:len(K)]/np.var(x) / len(x)

def autocorr7(x, K):
    result = np.correlate(x, x, mode='full')
    return result[len(x)-1:len(x)-1+len(K)] / np.var(x) / len(x)

if __name__=='__main__':

    y = np.random.rand(200) - 0.5

    lags=range(50)
    fig,ax=plt.subplots()

    for funcii, labelii in zip([autocorr1, autocorr2, autocorr3, autocorr4,
        autocorr5, autocorr6, autocorr7], ['np.corrcoef, partial', 'manual, non-partial',
            'fft, pad 0s, non-partial', 'fft, no padding, non-partial',
            'np.correlate, non-partial', 'trying FFT', 'np full corr']):
        start = time()
        cii=funcii(y,lags)
        duration = time() - start
        print(labelii + f" {duration}sec")
        print(cii)

        ax.plot(lags,cii,label=labelii)

    ax.set_xlabel('lag')
    ax.set_ylabel('correlation coefficient')
    ax.legend()
    plt.show()


'''
Construct a can with the maximum volume from a solid piece of material.
'''

import math
from sympy import Derivative, symbols, solve
from collections import namedtuple

Dimension = namedtuple( 'Dimension', [ 'width', 'height', 'volume'] )

def can_volume( area ):

	r,h = symbols( 'r,h' )
	# v = πr²h
	surf_area = 2*math.pi*r**2 + 2*math.pi*r*h
	# Solve surf_area for h, reduce to single variable.
	Ah = solve( surf_area - area, h )[ 0 ]

	V = math.pi * r**2 * h
	V1 = V.subs( h, Ah )

	# Derivative of volume with respect to the radius.
	dV = Derivative( V1, r ).doit()

	canidates = solve( dV )

	# Eliminate impossible Values
	for c in canidates:
		if( c <= 0 ):
			canidates.remove( c )

	h0 = 0

	if( len( canidates ) != 1 ):
		print( 'Invalid number of solutions.' )
	else:
		r0 = canidates[ 0 ].evalf()
		h0 = Ah.subs( { r: r0 } )

	return Dimension( width = r0, height = h0, volume = cyl_volume( r0, h0 ) )

def cyl_volume( r, h ):
	return math.pi * r**2 * h

if __name__ == '__main__':

	try:
		area = float( input( 'Enter the area of the material piece: ') )
	except ValueError:
		print( 'Error parsing values' )
	else:
		dim = can_volume( area )
		print( 'Maximum can volume: {0}'.format( dim.volume ) )
		print( 'with dimentions: {0} x {1}'.format( dim.width, dim.height ) )


import numpy as np
import matplotlib.pyplot as plt

Tc=304.2
Th=60+273.15
#Vc=.094
Pc=73.83
#Qh=2856.4
#^kW, also does this underaccount, because it's not pulling all heat above 60°C
CompressRatio=2
R=.08314
a=(27/64)*R**2*Tc**2/Pc
b=(1/8)*R*Tc/Pc
Vc = (3/8)*R*Tc/Pc
#find Volumes
V1=Vc*2/(CompressRatio+1)
V2=2*V1

#Builds Volume array
V=np.linspace(V1,V2, num=1000)

#Build isotherms
Phot= R*Th/(V-b)- a/(V**2)
Pcold= R*Tc/(V-b)- a/(V**2)

#Find Carnot Efficiency
effcarnot= 1-(Tc/Th)
print('efficiency is {}'.format(effcarnot))
print('=============================')
print('graph:')
#Build Temperature array
T=np.linspace(Tc,Th, num=1000)

#builds Graph

cvr = 0.655*(8.314/44.01)
def adia(V,b,Tc,cvr,Th):
    return (V-b)*(Tc/Th)**cvr+b

T2b = np.linspace(Tc,Th,1000)
VB = [V2]
previous_vb = V2
for i in range(0,len(T2b)-1):
    previous_Tc = T2b[i]
    current_Tc = T2b[i+1]
    current_vb = adia(previous_vb,b,previous_Tc,cvr,current_Tc)
    VB.append(current_vb)
    previous_vb = current_vb

T1a = np.linspace(Th,Tc,1000)
VA = [V1]
previous_va = V1
for i in range(0,len(T1a)-1):
    previous_Tc = T1a[i]
    current_Tc = T1a[i+1]
    current_va = adia(previous_va,b,previous_Tc,cvr,current_Tc)
    VA.append(current_va)
    previous_va = current_va

P1a= [R*j/(i-b)- a/(i**2) for i,j in zip(VA,T1a)]
P2b= [R*j/(i-b)- a/(i**2) for i,j in zip(VB,T2b)]

plt.plot(np.linspace(V1,VB[-1],1000), Phot,label=r'$T_H$')
plt.plot(np.linspace(VA[-1],V2,1000), Pcold,label=r'$T_C$')
plt.plot(VA,P1a,label='Adiabatic compression')
plt.plot(VB,P2b,label='Adiabatic expension')
plt.legend()
plt.xlabel('Volume/Liters')
plt.ylabel('Pressure/Bar')
plt.title('Carnot Engine at 60°C')
plt.show()

print('=============================')
for i,j in zip(['V1','VA','V2','VB'],[V1,VA[-1],V2,VB[-1]]):
    print('{} is {}'.format(i, j))

print('=============================')
integral = 0
int1 = 0
int2 = 0
for i in range(0,len(VA)-1):
    Phot= R*Th/(VA[i]-b)- a/(VA[i]**2)
    Phot2= R*Th/(VA[i+1]-b)- a/(VA[i+1]**2)
    int1 += (Phot - P1a[i])*(VA[i+1]-VA[i])
    int2 += (Phot2 - P1a[i])*(VA[i+1]-VA[i])

integral += (int1+int2)/2
int1 = 0
int2 = 0
V = np.linspace(VA[-1],VB[-1],1000)
for i in range(0,len(V)-1):
    Phot= R*Th/(V[i]-b)- a/(V[i]**2)
    Phot2= R*Th/(V[i+1]-b)- a/(V[i+1]**2)
    Pcold= R*Tc/(V[i]-b)- a/(V[i]**2)
    Pcold2= R*Tc/(V[i+1]-b)- a/(V[i+1]**2)
    int1 += (Phot - Pcold)*(V[i+1]-V[i])
    int2 += (Phot2 - Pcold2)*(V[i+1]-V[i])
integral += (int1+int2)/2

int1 = 0
int2 = 0
VB=VB[::-1]
P2b=P2b[::-1]
for i in range(0,len(VB)-1):
    Pcold= R*Tc/(VB[i]-b)- a/(VB[i]**2)
    Pcold2= R*Tc/(VB[i+1]-b)- a/(VB[i+1]**2)
    int1 += (P2b[i] - Pcold)*(VB[i+1]-VB[i])
    int2 += (P2b[i] - Pcold2)*(VB[i+1]-VB[i])
integral += (int1+int2)/2
print('Numerical solve work is {}'.format(integral))
print('=============================')
Qhana = R*Th*np.log((VB[0]-b)/(V1-b))
print('Analytical solve QH is {}'.format(Qhana))
print('Analytical solve Work is {}'.format(Qhana*effcarnot))


# Generates figure 6.2

from math import exp
import matplotlib.pyplot as plt
import numpy as np
from scipy.special import lambertw

def parametric_omega(gamma, other_omega):
    if gamma == 0:
        return 0
    if other_omega < gamma:
        return -gamma * lambertw(-other_omega * exp(-other_omega / gamma) / gamma, k=-1).real
    return -gamma * lambertw(-other_omega * exp(-other_omega / gamma) / gamma).real

if __name__ == "__main__":
    xs = np.linspace(0, 3.0, 500)

    plt.rc('text', usetex=True)
    plt.rc('font', family='serif')
    plt.plot(xs, [(2 - x) / (2 - 1) for x in xs], label=r"Possible $\Omega$ values for $K=2$")
    plt.plot(xs, [(3 - x) / (3 - 1) for x in xs], label=r"Possible $\Omega$ values for $K=3$")
    plt.plot(xs, [parametric_omega(1.0, x) for x in xs], label=r"$\gamma=1.0$", linestyle="dashed")
    plt.plot(xs, [parametric_omega(1.0926, x) for x in xs], label=r"$\gamma=1.0926$", linestyle="dashed")
    plt.xlim([0.0, 3.0])
    plt.ylim([0.0, 2.0])
    plt.xlabel(r"$\omega_{in}$", fontsize=14)
    plt.ylabel(r"$\omega_{out}$", fontsize=14)
    plt.title(r"Maximum Expected $\gamma$ Estimates with $K=2,3$ and $N \to \infty$", fontsize=14)
    plt.legend()
    plt.savefig("maximum_gamma_estimates_in_omega_space.pdf")


# -*- coding: utf-8 -*-
"""
Created on Tue Dec 14 12:30:17 2021

@author: Oscar
"""

" Tutorial 10 Question 2: Spherical Tank"
import sympy as sp
import numpy as np
import math as m
import matplotlib.pyplot as plt

#%% Question 1: Flow rate through the orifice

#Flow rate Q = CAsqrt(2gH) (m^3/s)
    # Q is a rate of change, thus Q = dV/dt volume over time
    # Vol. sphere is 4/3 pi*r^3, Area of a circle is pi*r^2
    # Radius of the water level wrt to time can be found using pythagorean

# Define Parameters
# Grav. Accel
g = 9.81 #m/s^2
# Coefficient
C = 0.55
# Orifice Diameter
ori_d = 0.03 # 3cm
# Area of the orifice
A = (ori_d/2)**2 * m.pi
# Tank Diameter
tank_d = 3 #m
R = tank_d/2

def model(H, t):
    Volume = -(C*A*m.sqrt(2*g*H))
    Area = (2*R*H*m.pi - H**2 * m.pi)
    Height = Volume/Area
    return Height

# Employing Euler's method

# Initial Conditions
t0 = 0
h0 = 2.75

# total solution interval
x_final = 10000
# step size
h = 0.1

# number of steps
n_step = m.ceil(x_final/h)

# Definition of arrays to store solution
y_eul = np.zeros(n_step+1)
x_eul = np.zeros(n_step+1)

# Initialize first element of arrays
# with initial condition
y_eul[0] = h0
x_eul[0] = t0

# Populate the x array
for i in range(n_step):
    x_eul[i+1] = x_eul[i] + h
# Apply Euler method n_step times
for i in range(n_step):
    # compute the slope
    slope = model(y_eul[i],x_eul[i])
    # use the Euler method
    y_eul[i+1] = y_eul[i] + h * slope
    if y_eul[i+1] < 0:
        break
    print( x_eul[i+1], y_eul[i+1])

# plot results
plt.plot(x_eul, y_eul , 'b.-',)
plt.xlabel('time')
plt.ylabel('H(t)')
plt.show()


"""
Description: script to demonstrate estimation of a function using a
 			 Fourier series
Author: Tarkan Bilge
Date: 06/02/2021"""

# =============================================================================
# Import
# =============================================================================

import scipy
import numpy as np
import matplotlib.pyplot as plt
from scipy import signal

# =============================================================================
# Functions
#==============================================================================

def fourier_series(f, interval, N):
	"""
	Calculates the Fourier series to approximate a function f.

	Parameters
	----------
	f : function
		Arbitrary function to be estimated by Fourier series.
	interval : list of float
		The start and end points of the interval of analysis.
	N : int
		Number of harmonics to estimate the function f with.

	Returns
	-------
	F : function
		The Fourier series approximation of f with N harmonics.
	"""

	P = interval[1] - interval[0]
	coefficient_list = []

	# The cooefficient sum should be zero if N = 0, but still a function of t
	coefficient_sum = lambda t: 0 * t

	# The coefficient for n = 0 is written separately to simplify the sum
	a0 = (2.0/P) * scipy.integrate.quad(f, interval[0], interval[1])[0]

	if N > 0:
		for n in range(1, N + 1):
			cos_term = lambda t, n=n: np.cos((2.0 * np.pi * n * t)/P)
			sin_term = lambda t, n=n: np.sin((2.0 * np.pi * n * t)/P)
			f_cos = lambda t, n=n : f(t) * cos_term(t)
			f_sin = lambda t, n=n : f(t) * sin_term(t)

			an = (2.0/P) * scipy.integrate.quad(f_cos, interval[0], interval[1])[0]
			bn = (2.0/P) * scipy.integrate.quad(f_sin, interval[0], interval[1])[0]
			coefficient = lambda t, n=n, an=an, bn=bn: (an * np.cos((2.0 * np.pi * n * t)/P)) + (bn * np.sin((2.0 * np.pi * n * t)/P))
			coefficient_list.append(coefficient)

		coefficient_sum = lambda t: sum([x(t) for x in coefficient_list])

	F = lambda t: a0/2.0 + coefficient_sum(t)
	return(F)

# =============================================================================
# Main
# =============================================================================

if __name__ == '__main__':

	# User input: input function
	f = lambda t: signal.sawtooth(2 * np.pi * t)

	# User input : Fourier series parameters
	N = 3
	interval = [0.0, 1.0]

	# Calculate fourier series estimate
	F = fourier_series(f, interval=interval, N=N)

	# Plotting
	t = np.linspace(0, 2, 1000)
	plt.plot(t, f(t))
	plt.plot(t, F(t))

	# Plot settings
	plt.ylim(-1.5, 1.5)
	plt.title(f"Fourier series estimation of a function; N = {N} over interval {interval}")
	plt.legend(['f(x)', 'F(x)'])
	plt.xlabel("x")
	plt.ylabel("y")

	plt.show()


import numpy as np
aArray = np.array([1,2,3])
print(aArray)
bArray = np.array([(1,2,3),(4,5,6)])
print(bArray)
# np.arange(start, stop, step)
c = np.arange(1,5,0.5)
print(c)
# return random floats between 0,1.0
d = np.random.random((2,2))
print(d)
# np.linspace(start, stop, nums, )
e = np.linspace(1,2,10,endpoint=False)
print(e)

# np.ones(shape, dtype=, order='') an ndarray with axis 0 = 2, axis 1 = 3 filled with one
f = np.ones([2,3])
print(f)

# np.zeros(shape, dtype=, order='') an ndarray with axis 0 = 2, axis 1 = 2, filled with zeros
g = np.zeros((2,2))
print(g)

# np.fromfunction(function, shape, dtype=, order='') an ndarray with function:(lambda i,j:(i+1)*(j+1)) and shape(9,9)
h = np.fromfunction(lambda i,j:(i+1)*(j+1),(9,9))
print(h)

# creating a 4x4 ndarray with filled with 1-16(1,17)
i = np.arange(1,17).reshape(4,4)
print(i)

j = np.array([1,3,7])
k = np.array([3,5,8])
print(np.vstack((j,k)))
print(np.hstack((j,k)))

l = np.array([(5,5,5),(5,5,5)])
m = np.array([(2,2,2),(2,2,2)])
print(l*m)
print(l+m)

n = np.array([1,2,3])
o = np.array([[1,2,3],[4,5,6]])
print(n+o)


import numpy as np
from scipy.linalg import hadamard

def gaussian_random_sketch(m, n, mean=0, variance=1):
    """
    m: Sketch size,
    n: Number of columns of the input matrix,
    mean: mean of gaussian distribution
    variance: variance of gaussian distribution

    returns: An m x n matrix sample from the Gaussian Distribution
    """
    return np.random.normal(loc=mean, scale=variance, size=(m, n))

def subsampled_randomized_hadamard_transforms(m, n):
    """
    m: Sketch size,
    n: Number of rows in the input matrix,

    returns: An m x n matrix subsampled randomized Hadamard transform
    """

    # if n is None:
    #     # Select n such that it is the smallest power of 2 that is larger than m
    #     p = int(round(np.log2(m), 0) + 1)
    #     n = 2 ** p
    #
    # Create the n x n Walsh-Hadamard matrix:
    H = hadamard(n)

    # Calculate diagonal - uniformly randomly 1 or -1
    d = np.random.uniform(0, 1, size=(n,))
    d = np.where(d > 0.5, 1, -1)

    # Use dot product to calculate HD
    HD = (H * d)

    # Calculate row sampling matrix
    # I_n = np.eye(n)
    # R = I_n[np.random.choice(n, m, replace=False), :]

    # Put everything together with 1 matrix multiplication
    # S = (1 / (m ** 0.5)) * np.matmul(R, HD)
    S = (1 / (m ** 0.5)) * HD[np.random.choice(n, m, replace=True), :]
    # H = hadamard(n)
    # b = np.random.binomial(1, m / n, size=(n,))
    # d = np.random.uniform(0, 1, size=(n,))
    # d = np.where(d > 0.5, 1, -1)
    # S = np.random.permutation(((b * H) * d).T)
    # S = S[np.where(S.any(axis=1))[0], :]

    return S

def sparse_johnson_lindenstrauss_transform(m, n, s):
    """
    m: Sketch size,
    n: Number of rows in the input matrix,
    s: Number of elements in each column to be non-zero.

    returns: An m x n matrix Sparse Johnson Lindenstrauss Transforms
    """

    # Calculate 1/sqrt{s} once
    a = 1 / (s ** 0.5)

    # Initialize s to be an m x n matrix filled with zeros
    S = np.zeros((m, n))

    # For each column, uniformly randomly select s rows that will be non-zero. Uniformly randomly assign it to be +/- 1/sqrt{s}
    sparse_array = np.random.uniform(0, 1, size=(s, n))
    sparse_array = np.where(sparse_array > 0.5, a, -1 * a)
    S[np.random.choice(m, size=(s, n)), np.arange(n)] = sparse_array

    return S


import numpy as np
import sklearn.preprocessing

#x_prop = (x - d_min) / (d_max - d_min)
#x' = x_prop * (r_max - r_min) + r_min

arr = np.array([[1, 100, 2390], [2, 234, 5432], [0, 323, 5555]]) #feature_range=(x, y)

default_scaler = sklearn.preprocessing.MinMaxScaler()
print(default_scaler.fit_transform(arr))
# [[0.5        0.         0.        ]
#  [1.         0.60089686 0.96113744]
#  [0.         1.         1.        ]]

default_scaler = sklearn.preprocessing.MinMaxScaler()
default_scaler.fit(arr)
#print(default_scaler.transform(arr)) the same as line 10
arr2 = np.array([[1, 100, 2390], [2, 100, 1999], [1, 223, 5555]])

print(default_scaler.transform(arr2))
# [[ 0.5         0.          0.        ]
#  [ 1.          0.         -0.1235387 ]
#  [ 0.5         0.55156951  1.        ]]


import numpy as np
class Loss:

    def calculate(self, output, y):

        sample_losses = self.forward(output, y)
        data_loss     = np.mean(sample_losses)
        return(data_loss)

class Loss_CategoricalCrossEntropy(Loss):
                        #y_pred is not the predicted y, it is its
                        #probability!!
        def forward(self, y_pred, y_true):
            samples = len(y_pred)
            #removing vals close to zero and one bco log and accuracy
            y_pred_clipped = np.clip(y_pred, 1e-7, 1 - 1e-7)

            #now, depending on how classes are coded, we need to get the probs
            if len(y_true.shape) == 1:#classes are encoded as [[1],[2],[2],[4]]
                correct_confidences = y_pred_clipped[range(samples), y_true]
            elif len(y_true.shape) == 2:#classes are encoded as
                                    #[[1,0,0], [0,1,0], [0,1,0]]
                correct_confidences = np.sum(y_pred_clipped*y_true, axis = 1)

            negative_log_likelihoods = -np.log(correct_confidences)
            return(negative_log_likelihoods)

        def backward(self, dvalues, y_true):
            Nsamples = len(dvalues)
            Nlabels  = len(dvalues[0])
            #turning labels into one-hot i. e. [[1,0,0], [0,1,0], [0,1,0]], if
            #they are not
            if len(y_true.shape) == 1:
            #"eye" turns it into a diag matrix, then indexing via the label
            #itself
                y_true = np.eye(Nlabels)[y_true]
            #normalized gradient
            self.dinputs = -y_true/dvalues/Nsamples
            #this is the local derivative


import random
import math
import numpy

def chisquarevariate(k):
	"""Generates a variate from chi square distrubuton with paramater k"""

	s = 0
	for i in range(k):
		s += math.pow(random.normalvariate(0, 1), 2)

	return s

def estimate(k, n):
	"""Estimate expected value and variance over n runs"""
	variates = []
	for i in range(n):
		variates.append(chisquarevariate(k))

	return (numpy.mean(variates), numpy.var(variates))

def conf(L):
	"""Compute a 95 percent confidence interval"""
	lower = numpy.mean(L) - 1.96 * numpy.std(L)/math.sqrt(len(L))
	upper = numpy.mean(L) + 1.96 * numpy.std(L)/math.sqrt(len(L))

	return (lower, upper)

if __name__ == "__main__":
	k = 9
	n = 10000
	m = 50

	random.seed(123)

	for i in range(1, k):

		Lvar = []
		Lmean = []
		for j in range(m):
			res = estimate(i, n)

			Lmean.append(res[0])
			Lvar.append(res[1])

		confMean = conf(Lmean)
		confVar = conf(Lvar)

		print "K = ", i
		print "  > Conf Mean: ", confMean
		print "  > Conf Var: ", confVar
		print "\n"


import numpy as np
import scipy.stats as sps
import matplotlib.pyplot as plt
import seaborn as sns
from marchenko_pastur import *
from embedding import *

def mutual_information(x, y, bins=30):
    c_xy = np.histogram2d(x, y, bins)[0]
    g, p, dof, expected = sps.chi2_contingency(c_xy, lambda_="log-likelihood")
    mi = 0.5 * g / c_xy.sum()
    return mi

def mutual_information_matrix(X,bins=30):
    p,n = X.shape
    mi_matrix = np.zeros((p,p))
    for i in range(p):
        for j in range(p):
            mi_matrix[i,j] = mutual_information(X[i,:],X[j,:],bins=bins)
    return mi_matrix

def plot_mi_matrix(X,ax,bins=30):
    mi_matrix = mutual_information_matrix(X,bins=bins)
    sns.heatmap(mi_matrix,ax=ax,cmap='inferno')
    ax.set_title('Mutual Information Heatmap')

def covariance_matrix(X,transform=True):
    if transform:
        X_ = transform_to_zero_mean_and_unit_std(X)
    else:
        X_ = X.copy()

    C = np.dot(X_,X_.T) / X.shape[1]
    return C

def plot_cov_matrix(X,axis,transform=True):
    C = covariance_matrix(X,transform=transform)
    sns.heatmap(C,ax=axis,cmap='inferno')
    axis.set_title('Covariance Heatmap')

def overview(X,skip=[]):
    fig,ax = plt.subplots(2,2)
    if 'marchenko-pastur' not in skip:
        marchenko_pastur_comparison(X,ax[0,0])
    if 'skree' not in skip:
        _,S = PCA(X)
        skree_plot(S,ax[0,1])
    if 'covariance' not in skip:
        plot_cov_matrix(X,ax[1,0])
    if 'mutual-information' not in skip:
        plot_mi_matrix(X,ax[1,1])
    plt.show()


import numpy as np

def sigmoid(x):
    """ sigmoid = 1 / (1 + exp(-x))"""
    return 1 / (1 + np.exp(-x))

class Sigmoid:
    def __init__(self):
        self.y = None

    def forward(self, x):
        self.y = 1 / (1 + np.exp(-x))
        return self.y

    def backward(self, delta_output):
        return delta_output * self.y * (1 - self.y)

if __name__ == '__main__':
    sigmoiding = Sigmoid()
    sig_fw = sigmoiding.forward(0)
    print(sig_fw)
    sig_bw = sigmoiding.backward(1)
    print(sig_bw)


# -*- coding: utf-8 -*-
"""
Created on Tue Oct 26 16:46:16 2021

@author: Oliver
"""

# Define the core Trapezoid rule function defining the function, a,b
# and the number of strips N used. T is the integral in [a,b].
import numpy as np
import matplotlib.pyplot as plt

def trapz(f,a,b,N):
    x = np.linspace(a,b,N+1) # N+1 points make N subintervals
    y = f(x)
    y_right = y[1:] # right endpoints
    y_left = y[:1] # left endpoints
    dx = (b-a)/N
    T = (dx/2)* np.sum(y_right + y_left)
    return T

# Define the function to be integrated

def f(x):
    return np.exp(-x**2)

a = 1
b = 10
n = 2000000
# N =50

print(trapz(f,a,b,n))

# graphing the trapezoidal rule
# defining x and y and plotting the curve
x = np.linspace(-1.5,1.5,100)
y = np.exp(x**2)
plt.plot(x,y)

# these commands fill a defined region of the graph to form a trapezoid area. then it calculates
#the area,A, shown within the trapezoid geometrically. this A is the approximation fo the integral oif
#the function
x0 = 0
x1 = 1
y0 = np.exp(x0**2)
y1 = np.exp(x1**2)
plt.fill_between([x0,x1],[y0,y1])
plt.show()
A = 0.5*(y1+y0)*(x1 - x0)
print("trapezoidal area", A)

Trapexoidal rule numerical integration.py


import math
from src.taxodist import td_calc
from src.taxodist import td_utils as utils
from treelib import Tree
import warnings
from scipy.optimize import linear_sum_assignment

def getJaccardSetSim(concepts_1: set, concepts_2: set):
    """ Returns Jaccard Set Similarity for the given concept sets """

    intersection = len(concepts_1.intersection(concepts_2))
    union = concepts_1.union(concepts_2)
    if union != 0:
        return float(intersection) / union
    else:
        warnings.warn("Union was zero")
        return 0

def getDiceSetSim(concepts_1: set, concepts_2: set):
    """ Returns Dice Set Similarity for the given concept sets """
    intersection = len(concepts_1.intersection(concepts_2))
    return (2*intersection)/(len(concepts_2)+len(concepts_1))

def getCosineSetSim(concepts_1: set, concepts_2: set):
    """ Returns Cosine Set Similarity for the given concept sets """
    intersection = len(concepts_1.intersection(concepts_2))
    return intersection/(math.sqrt(len(concepts_2)*len(concepts_1)))

def getOverlapSetSim(concepts_1: set, concepts_2: set):
    """ Returns Overlap Set Similarity for the given concept sets """
    intersection = len(concepts_1.intersection(concepts_2))
    return intersection/min(len(concepts_1),len(concepts_2))

def getMeanCSSetSim(concepts_1: set, concepts_2: set,tree: Tree, cs_mode:str,ic_mode: str = 'sanchez'):
    ''' Returns Set Similarity based on SS#7 from Jia et al. '''
    sum = 0
    depth = tree.depth()
    for concept_1 in concepts_1:
        for concept_2 in concepts_2:
            sum += utils.getCS(concept_1,concept_2,tree,depth,ic_mode,cs_mode)
    return sum/(len(concepts_1)*len(concepts_2))

def getHierachicalDistSetSim(concepts_1: set, concepts_2: set,tree: Tree, cs_mode:str,ic_mode: str = 'sanchez'):
    """ Returns hierarchical distance for the given concept sets based on https://doi.org/10.1016/j.jbi.2016.07.021"""

    if concepts_1 == concepts_2:
        return 0.0

    difference_1 = concepts_1.difference(concepts_2)
    difference_2 = concepts_2.difference(concepts_1)
    union = concepts_1.union(concepts_2)
    depth = tree.depth()

    first_summand = sum([1 - utils.getCS(concept_difference_1,concept_2,tree,depth,ic_mode,cs_mode) for concept_2 in concepts_2 for concept_difference_1 in difference_1])

    second_summand = sum([1 - utils.getCS(concept_difference_2,concept_1,tree,depth,ic_mode,cs_mode) for concept_1 in concepts_1 for concept_difference_2 in difference_2])

    return ( first_summand/len(difference_2) + second_summand/len(difference_1) )/len(union)

def getMaxWeightedBipartiteMatchingSim(concepts_1, concepts_2, tree, ic_mode, cs_mode):
    ''' Weighted undirected bipartite Graph with weight function CS(a,b).
        Matching = subset of edges with max weights aka highest similarity for the two given concept-sets. \n
        Returns max-sum of the CS-weighted edges. '''

    # get pairwise-similarity matrix for max bipartite matching
    cs_matrix = utils.getCSMatrix(concepts_1, concepts_2, tree, ic_mode, cs_mode)

    # calculate max similarity using hungarian algorithm
    row_ind, col_ind = linear_sum_assignment(cost_matrix=cs_matrix,maximize=True)

    return cs_matrix[row_ind, col_ind].sum()


#Milne's Corrector Predictor Method
import numpy as np

pynp1 = 0 #predictor
yn  = 1.504119
ynm1 =   1.2773913
ynm2 = 1.1168872
ynm3 =1

xnp1 = 0.4
xn  = 0.3
xnm1 =  0.2
xnm2 = 0.1
xnm3 =0

n = 2

h = 0.1
#order = 4 always

def dy(x,y):
    dyvalue = x*y + y**2
    return dyvalue

i = 0
while i<=n:
    #predictor:

    pynp1 = ynm3 + ((4*h)/3)*(2*dy(xnm2,ynm2)-dy(xnm1,ynm1)+2*dy(xn,yn))

    #corrector:

    cynp1 = ynm1 + (h/3)*(dy(xnm1,ynm1)+4*dy(xn,yn)+dy(xnp1,pynp1))

    #print:

    print("____________"+str(i)+"____________")
    print("xn = "+ str(xnp1))
    print("predictor pyn+1 = "+ str(pynp1))
    print("corrector cyn+1 = "+ str(cynp1))
    print("\n")

    #update:
    ynm3 = ynm2
    ynm2 = ynm1
    ynm1 = yn
    yn = cynp1 #not sure about this. for n >1 should we put the corrected value or the predicted for further iterations

    xnp1+=h
    xnm2+=h
    xnm1+=h
    xn+=h

    i+=1