# coding: utf-8

# In[1]:

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

# In[2]:

# Linear line
# x_vals = np.linspace(start=0, stop=5, num=50)
# y_vals = 2 * x_vals + 1
# input_shape = 1

# Line with noise
sigma = 5
x_vals = np.linspace(start=0, stop=5, num=50)
y_vals = 2 * x_vals + 1 + sigma* np.random.randn(50)
input_shape = 1

# In[3]:

plt.plot(x_vals, y_vals, 'r')
plt.show()

# In[4]:

def visualize_line(w_val):
    x_grid = np.linspace(start=0, stop=5, num=50)
    y_guessed = w_val[0] * x_grid + w_val[1]

    plt.plot(x_grid, y_guessed, 'b')
    plt.plot(x_vals, y_vals, 'r')

    plt.ylim((np.min(y_vals),np.max(y_vals)))
    plt.xlim((0,5))

    plt.show()

# In[5]:

x_tf = tf.placeholder(tf.float64, [])
y_tf = tf.placeholder(tf.float64, [])

w = np.zeros([2])
w_tf = tf.Variable(initial_value=w, dtype=tf.float64)

# In[6]:

yhat_tf =  tf.reduce_sum(w_tf[0] * x_tf) + w_tf[1]
loss = 1/2. * (y_tf - yhat_tf) ** 2

# In[7]:

lr = 0.001
optimization = tf.train.GradientDescentOptimizer(learning_rate=lr).minimize(loss)

# In[8]:

sess = tf.Session()
init_op = tf.global_variables_initializer()
sess.run(init_op)

# In[9]:

epochs = 15
for ee in range(epochs):
    epoch_loss = 0.
    for ii in range(x_vals.shape[0]):
        x_i = x_vals[ii]
        y_i = y_vals[ii]

        run_dict = {'optimization': optimization, 'loss':loss}
        feed_dict = {x_tf:x_i, y_tf:y_i}
        out_dict = sess.run(run_dict, feed_dict=feed_dict)
        epoch_loss += out_dict['loss']

        # w_trained = sess.run(w_tf)
        # print('Current loss: %.5f' %  out_dict['loss'])
        # visualize_line(w_trained)

    w_trained = sess.run(w_tf)
    print('Epoch loss: %.5f' % epoch_loss)
    visualize_line(w_trained)

# In[10]:

print('w: %.2f, b: %.2f' % (w_trained[0], w_trained[1]))


"""
Simple implementation of Fisher Discriminant Analysis
Demo with 2D toy data

Author: Duong Nguyen @TokyoTech
Contact: nguyen@sg.cs.titech.ac.jp
"""

import numpy as np
import matplotlib.pyplot as plt
from scipy.linalg import eig # for generalized eigensystem solver
from mpl_toolkits.mplot3d import Axes3D # for 3d plot

#------------------------------------------#
#    Load data from file, plotting code    #
#------------------------------------------#
def loadData(filename, label):
    """ Load data from file.
        Assign given label to each samples.

        Returns:
        ----------------------
        X: n x d matrix of n samples
        Y: n x 1 label vector
        n_samples: number of samples
        dim: data dimension
    """
    X = []
    with open(filename, 'r') as fin:
        for line in fin:
            row = map(float, line.strip().split(','))
            X.append(row)

    n_samples = len(X)
    dim = len(X[0])
    Y = [label] * n_samples
    X = np.asarray(X, dtype='float64')
    Y = np.asarray(Y, dtype='int16')
    return X, Y, n_samples, dim

def plot_2d_xx(infile1, infile2, outfile=None, show=True):
    """ Plot 2d data. Just for testing."""
    X1, Y1, n1, d1 = loadData(infile1, 0)
    X2, Y2, n2, d2 = loadData(infile2, 1)
    d1 = X1.shape[1]
    d2 = X2.shape[1]
    assert d1 == d2, "Dimension not match!"
    assert d1 == 2, "2D!"

    plt.plot(X1[:,0], X1[:,1], 'rx', label='Class 1')
    plt.plot(X2[:,0], X2[:,1], 'go', label='Class 2')
    plt.legend(loc='best', prop={'size':20})

    if outfile: # save to file
        plt.savefig(outfile)
    if show: # show figure
        plt.show()

#----------------#
#    FDA code    #
#----------------#
def FDA(X, Y, n_class, m):
    """ Fisher Discriminant Analysis.
        Params:
        -------------
        X: n x d matrix of samples
        Y: n x 1 label vector
        n_class: number of classes
        m: reduced dimensionality

        Returns:
        ---------------
        B_FDA: m x d matrix (FDA embedding matrix)
    """
    n, d = X.shape

    nc = [] # number of samples from each class
    muc = [] # list of class sample means
    for i in range(n_class):
        nc.append(len(Y[Y==i]))
        muc.append(np.mean(X[Y==i], 0))

    mu_X = np.mean(X, 0) # sample mean of the whole data

    # Compute Sb
    Sb = np.zeros((d,d), dtype='float64')

    for i in range(n_class):
        Sb += nc[i] * np.dot(np.reshape(muc[i]-mu_X, (d,1)), np.reshape(muc[i]-mu_X, (1,d)))

    # compute Sw
    Sw = np.zeros((d,d), dtype='float64')
    for i in range(n_class):
        Sw += np.dot((X[Y==i]-muc[i]).T, (X[Y==i]-muc[i]))

    eigvals, V = eig(Sb, Sw)
    sorted_indices = np.argsort(eigvals)[::-1]
    V = V[:, sorted_indices] # sort in decreasing order of eigenvalues
    return V[:, 0:m] # return the m largest component

def testFDA(outfile='fda-2d-L3.png', show=True, debug=False):
    """ Test FDA."""
    X1, Y1, n1, d1 = loadData('2d-L3-c1.txt', 0)
    X2, Y2, n2, d2 = loadData('2d-L3-c2.txt', 1)

    assert d1 == d2, "Dimensions must match!"

    X = np.vstack((X1, X2))
    Y = np.hstack((Y1, Y2))
    fda_dir = FDA(X, Y, n_class=2, m=1)

    if debug: # print fda_dir in debug mode
        print fda_dir

    x_mean = np.mean(X, 0)

    plt.plot(X1[:,0], X1[:,1], 'rx', markersize=10, mew='2', label='Class 1')
    plt.plot(X2[:,0], X2[:,1], 'bo', markersize=10, mew='2', mfc='w', mec='b', label='Class 2')

    plt.plot([x_mean[0] + k*fda_dir[0] for k in np.linspace(-9,9)],
                [x_mean[1] + k*fda_dir[1] for k in np.linspace(-9,9)],
                'k-', lw=4, label='FDA')

    plt.legend(loc='best', prop={'size':20})
    plt.axis('equal')
    plt.savefig(outfile)
    if show:
        plt.show()

if __name__ == '__main__':
    testFDA()


r"""
Solve Poisson equation in 1D with homogeneous Neumann bcs

    \nabla^2 u = f

Use Shen's Neumann basis

The equation to solve is

     (\nabla^2 u, v) = (f, v)

"""
import sys
import os
import sympy as sp
import numpy as np
from shenfun import inner, div, grad, TestFunction, TrialFunction, FunctionSpace, \
    Array, Function, legendre, chebyshev, extract_bc_matrices, la, SpectralMatrix, dx

# Collect basis from either Chebyshev or Legendre submodules
assert len(sys.argv) == 3, "Call with two command-line arguments"
assert sys.argv[-1].lower() in ('legendre', 'chebyshev')
assert isinstance(int(sys.argv[-2]), int)
family = sys.argv[-1].lower()
Solver = chebyshev.la.Helmholtz if family == 'chebyshev' else la.SolverGeneric1ND

# Use sympy to compute a rhs, given an analytical solution
x = sp.symbols("x", real=True)
alpha = 0
ue = sp.cos(2*sp.pi*x)
#ue = sp.cos(5*sp.pi*(x+0.1)/2)
fe = -ue.diff(x, 2)+alpha*ue

# Size of discretization
N = int(sys.argv[-2])

bc = {'left': ('N', ue.diff(x, 1).subs(x, -1)), 'right': ('N', ue.diff(x, 1).subs(x, 1))}
SD = FunctionSpace(N, family=family, bc=bc, basis='ShenNeumann')
u = TrialFunction(SD)
v = TestFunction(SD)

# Get f on quad points
fj = Array(SD, buffer=fe)

# Compute right hand side of Poisson equation
f_hat = inner(v, fj)

# Get left hand side of Poisson equation
A0 = inner(v, div(grad(u)))
B0 = inner(v, u)

# Solve
u_hat = Function(SD).set_boundary_dofs()
M = -A0
if alpha != 0:
    M += alpha*B0

# The coefficient matrix is singular if alpha=0. In that case add constraint
constraint = ((0, dx(Array(SD, buffer=ue), weighted=True)/dx(Array(SD, val=1), weighted=True)),) if alpha == 0 else ()

if alpha != 0:
    # Use Helmholtz solver
    sol = Solver(A0, B0, -1, alpha)
    u_hat = sol(f_hat, u_hat, constraints=constraint)
else:
    u_hat = M.solve(f_hat, u_hat, constraints=constraint)

# Transform to real space
uj = u_hat.backward()

# Compare with analytical solution
ua = Array(SD, buffer=ue)
print(abs(uj-ua).max())
assert np.allclose(uj, ua)

if 'pytest' not in os.environ:
    import matplotlib.pyplot as plt
    plt.figure()
    X = SD.mesh()
    plt.plot(X, uj)

    plt.figure()
    plt.plot(X, ua)

    plt.figure()
    plt.plot(X, ua-uj)
    plt.title('Error')
    #plt.show()


import numpy as np

def generate_regression_data(degree, N, amount_of_noise=1.0):
    """
    Generates data to test one-dimensional regression models.

    Args:
        degree (int): degree of polynomial that relates the output x and y
        N (int): number of points to generate
        amount_of_noise (float): amount of random noise to add to the relationship between x and y.

    Returns:
        x (np.ndarray): explanatory variable of size N, ranges between -1 and 1.
        y (np.ndarray): response variable of size N, which responds to x as polynomial of degree 'degree'.
    """

    # Generate explanatory variable x of floats chosen are random between -1 and 1
    x = np.zeros((N,), dtype=float)
    iteration = 0
    for i in x:
        x[iteration] = np.random.uniform(-1.0, 1.0)
        iteration += 1

    # Generate polynomial float coefficients chosen uniformally at random between -10 and 10
    exps = np.arange(degree+1)
    coeff = np.zeros((degree+1,), dtype=float)
    j = 0
    for i in coeff:
        coeff[j] = np.random.uniform(-10.0, 10.0)
        j += 1

    # Generate response variable y that contains f(x)
    y = np.zeros(len(x))
    f = 0
    for i in x:
        y[f] = sum(coeff[a]*x[f]**exps[a] for a in range(len(coeff)))
        f += 1

    # Add Gaussian noise n to y with mean = 0.0 and standard deviation
    std_y = np.std(y)
    noise = np.random.normal(loc=0.0, scale=amount_of_noise*std_y, size=y.shape)
    y_noise = y + noise

    return x, y_noise


import numpy as np

def triangular_superior(A, b):
    """Resolve um sistema linear com matriz de coeficientes \
triangular superior.

    Parâmetros:
        [A] (numpy.array): Matriz triangular superior (coeficientes).
        [b] (numpy.array): Vetor das constantes.

    Retorno:
        Vetor com a solução (numpy.array)
"""

    n = len(A)
    x = np.zeros(n)

    x[n - 1] = b[n - 1] / A[n - 1, n - 1]

    for k in range(n - 2, -1, -1):
        s = 0
        for j in range(k + 1, n):
            s += A[k, j] * x[j]
            x[k] = (b[k] - s) / A[k, k]

    print(f"A solução do sistema é o vetor: {x}")
    return x

if __name__ == "__main__":
    A = np.array([[2, 1, 3], [0, 1, -1], [0, 0, 2]])
    b = np.array([11, 1, 4])
    triangular_superior(A, b)


import numpy as np

### Functions for you to fill in ###

# pragma: coderesponse template

def polynomial_kernel(X, Y, c, p):
    """
        Compute the polynomial kernel between two matrices X and Y::
            K(x, y) = (<x, y> + c)^p
        for each pair of rows x in X and y in Y.

        Args:
            X - (n, d) NumPy array (n datapoints each with d features)
            Y - (m, d) NumPy array (m datapoints each with d features)
            c - a coefficient to trade off high-order and low-order terms (scalar)
            p - the degree of the polynomial kernel

        Returns:
            kernel_matrix - (n, m) Numpy array containing the kernel matrix
    """
    kernel_matrix = (X.dot(Y.T) + c)**p

    return kernel_matrix
# pragma: coderesponse end

# pragma: coderesponse template

def rbf_kernel(X, Y, gamma):
    """
        Compute the Gaussian RBF kernel between two matrices X and Y::
            K(x, y) = exp(-gamma ||x-y||^2)
        for each pair of rows x in X and y in Y.

        Args:
            X - (n, d) NumPy array (n datapoints each with d features)
            Y - (m, d) NumPy array (m datapoints each with d features)
            gamma - the gamma parameter of gaussian function (scalar)

        Returns:
            kernel_matrix - (n, m) Numpy array containing the kernel matrix
    """
    n, d = X.shape
    m = Y.shape[0]

    # Naive version with for loops
#    kernel_matrix = np.zeros((n,m))
#
##### Single for loop ####
#    for i in range(n):
#        d = X[i,:] - Y  # Using numpy broadcasting to get differences
#        b = np.sum(d**2, axis=1)
#        kernel_matrix[i,:] = np.exp(-gamma*b)
#### End: single-loop version ####

#### Vectorized version (runs slower than the single loop version) ####
#    kernel_matrix = np.linalg.norm((X[:,None] - Y), ord=2, axis=2)**2
#    kernel_matrix = (np.sum(X**2, axis=1)[:,None] + np.sum(Y**2, axis=1)) - 2*(X @ Y.T)
    kernel_matrix = X**2 @ np.ones((d,m)) + np.ones((n,d)) @ Y.T**2 - 2*(X @ Y.T)
    kernel_matrix = np.exp(-gamma*kernel_matrix)
#### End: vectorized version ####

    return kernel_matrix
# pragma: coderesponse end


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

def online_p4():
    d_vc = 50
    delta = 0.05
    N = 5
    def m_H(n):
        return n ** d_vc

    a_bound = math.sqrt((8/N) * math.log((4*m_H(2*N))/delta))
    b_bound = math.sqrt(2 * math.log(2*N*m_H(N))/N) + math.sqrt((2/N) * math.log(1/delta)) + 1/N
    c_bound = math.sqrt((1/N) * math.log(6 * m_H(2*N) / delta) + 1/(N**2)) + 1/N
    d_bound = math.sqrt((1/(2*N - 4)) * (math.log(4/delta) + 2*d_vc*math.log(N)) + (1/(N-2))**2) + 1/(N-2)
    e_bound = math.sqrt((16/N) * math.log(2 * m_H(N) / math.sqrt(delta)))

    print("a: ", a_bound)
    print("b: ", b_bound)
    print("c: ", c_bound)
    print("d: ", d_bound)
    print("e: ", e_bound)

def get_data(path):
    data_all = np.genfromtxt(path)
    data_x = data_all[:, :-1]
    data_y = data_all[:, -1]
    return data_x, data_y

def error(pred, gt):
    return np.sum(pred != gt) / len(gt)

def decision_stump(data_x, data_y):
    """
    x, y are both in shape (data_num, )
    Return (theta, s= +/-1)
    """
    data_len = len(data_x)
    sort_arg = np.argsort(data_x)
    data_x = data_x[sort_arg]
    data_y = data_y[sort_arg]
    thetas = [(data_x[i] + data_x[i+1]) / 2 for i in range(data_len-1)]
    thetas.append(data_x[0] - 1)
    stump = (None, None)
    error_min = 1
    for theta in thetas:
        pred = np.ones(data_len) * (-1)
        pred[data_x > theta] = 1
        err = error(pred, data_y)
        if  err < error_min:
            error_min = err
            stump = (theta, 1)
        pred = np.ones(data_len) * (-1)
        pred[data_x < theta] = 1
        err = error(pred, data_y)
        if  err < error_min:
            error_min = err
            stump = (theta, -1)
    return stump

def online_p19_p20():
    train_x, train_y = get_data("train.dat")
    test_x , test_y  = get_data("test.dat")
    train_len, test_len = len(train_y), len(test_y)

    dim = None
    stump = None
    E_in = 1
    for d in range(train_x.shape[1]):
        ds = decision_stump(train_x[:, d], train_y)
        pred = np.ones(train_len) * (ds[1])
        pred[train_x[:, d] < ds[0]] *= (-1)
        err = error(pred, train_y)
        if err < E_in:
            E_in = err
            dim = d
            stump = ds

    test_pred = np.ones(test_len) * stump[1]
    test_pred[test_x[:, dim] < stump[0]] *= (-1)
    E_out = error(test_pred, test_y)

    print("E in:  {}".format(E_in))
    print("E_out: {}".format(E_out))

def E_out(s, theta):
    return 0.5 + 0.3 * s * (min(abs(theta), 1) - 1)

def plot_hist(data_size, fig_name):
    error_distance = []
    error_in  = []
    error_out = []
    for _ in range(1000):
        x = np.random.rand(data_size) * 2 - 1
        y = np.ones(data_size)
        y[x < 0] = -1
        noise_idx = np.random.choice(data_size, int(0.2 * data_size), replace= False)
        y[noise_idx] *= -1

        theta, s = decision_stump(x, y)
        pred = np.ones(data_size) * s
        pred[x < theta] *= (-1)
        e_in  = error(pred, y)
        e_out = E_out(s, theta)
        e_diff = e_in - e_out
        error_distance.append(e_diff)
        error_in.append(e_in)
        error_out.append(e_out)

    print("E_in: {}".format(np.mean(error_in)))
    print("E_out: {}".format(np.mean(error_out)))
    plt.title("E_in: {:.3f} E_out: {:.3f}".format(np.mean(error_in), np.mean(error_out)))
    plt.hist(error_distance)
    plt.savefig(fig_name)
    plt.close()

def hw_p7_p8():
    plot_hist(20, "imgs/p7.png")
    plot_hist(2000, "imgs/p8.png")

def test():
    x, y = get_data("test.dat")
    print(x.shape)
    print(y.shape)

if __name__ == "__main__":
    hw_p7_p8()


# -*- coding:utf-8 -*-

import os

import numpy as np
import tensorflow as tf

os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'

#
# voector
#

vector = np.random.randint(1, 10, (2, 3)).astype(np.float32)
vector_1 = vector[0]
vector_2 = vector[1]
print(vector_1, vector_2)

# length
# https://www.tensorflow.org/api_docs/python/tf/norm
length_11 = tf.norm(vector_1)
print(length_11)
length_21 = tf.norm(vector_2)
print(length_21)

# sqrt(sum(square(x)))
length_12 = np.sqrt(np.sum(np.square(vector_1)))
print(length_12)

length_22 = np.sqrt(np.sum(np.square(vector_2)))
print(length_22)

#
# cosine sim by dot
#

# a.b/|a||b|
output_1 = tf.matmul([vector_1], [vector_2], transpose_b=True) / (length_11 * length_21)
print(output_1)

#
# cosine sim by normalize and dot
#

# normalize vector_1
normal_11 = vector_1 / length_11
print(normal_11)
print(tf.norm(normal_11))

# normalize vector_1
# https://www.tensorflow.org/api_docs/python/tf/math/l2_normalize
normal_12 = tf.math.l2_normalize(vector_1)
print(normal_12)
print(tf.norm(normal_12))

# normalize vector_2
normal_21 = vector_2 / length_21
print(normal_21)
print(tf.norm(normal_21))

# normalize vector_2
normal_22 = tf.math.l2_normalize(vector_2)
print(normal_22)
print(tf.norm(normal_22))

output_2 = tf.matmul([normal_11], [normal_21], transpose_b=True)
print(output_2)


import numpy as np
'''感知机逻辑门实现'''

def AND(x1, x2):
    '''与门'''
    x = np.array([x1, x2])
    w = np.array([0.5, 0.5])
    b = -0.7
    tmp = np.sum(w*x) + b
    if tmp <= 0:
        return 0
    else:
        return 1

def NAND(x1, x2):
    '''与非门'''
    x = np.array([x1, x2])
    w = np.array([-0.5, -0.5])
    b = 0.7
    tmp = np.sum(w*x) + b
    if tmp <= 0:
        return 0
    else:
        return 1

def OR(x1, x2):
    '''或门'''
    x = np.array([x1, x2])
    w = np.array([0.5, 0.5])
    b = -0.2
    tmp = np.sum(w*x) + b
    if tmp <= 0:
        return 0
    else:
        return 1

def XOR(x1, x2):
    '''异或门'''
    s1 = NAND(x1, x2)
    s2 = OR(x1, x2)
    y = AND(s1, s2)
    return y

def step_function(x):
    '''阶跃函数'''
    return np.array(x > 0, dtype = np.int)

def sigmoid(x):
    '''针对二元分类问题的激活函数'''
    return 1/(1 + np.exp(-x))

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

def identity_function(x):
    '''恒等函数'''
    return x

def softmax(a):
    '''针对多元分类问题的激活函数'''
    c = np.max(a)
    exp_a = np.exp(a - c)    #溢出策略
    sum_exp = np.sum(exp_a)
    y = exp_a / sum_exp

    return y

def mean_square_error(y, t):
    '''均方误差'''
    return 0.5 * np.sum((y - t) ** 2)

def cross_entropy_error(y, t):
    '''交叉熵误差'''
    delta = 1e-7
    return -np.sum(t * np.log(y + delta))

def cross_entropy_error_onehot(y, t):
    if y.ndim == 1:
        t = t.reshape(1, t.size)
        y = y.reshape(1, y.size)

    batch_size = y.shape[0]
    return -np.sum(t * np.log(y + 1e-7)) / batch_size

def cross_entropy_error_not_onehot(y, t):
    if y.adim == 1:
        t = t.reshape(1, t.size)
        y = y.reshape(1, y.size)

    batch_size = y.shape[0]
    return -np.sum(np.log(y[np.arange(batch_size,), t] + 1e-7)) / batch_size

def numerical_diff(f, x):
    '''数值微分函数'''
    h = 1e-4
    return (f(x+h) - f(x-h)) / (2 * h)


"""
This code implements a perceptron algorithm (PLA).
First, we visualise the dataset which contains 2 features. We can see that the dataset can be clearly separated by drawing a straight line between them. The goal is to write an algorithm that finds that line and classifies all of these data points correctly.

The output file (e.g. 'output1_f.csv') contains the values of w1, w2 and b which define the 'threshold' line. The last row will be the most accurate one. Each time it goes through each of the examples in 'input1.csv', it adds a new line to the output file containing a comma-separated list of the weights w_1, w_2, and b (bias) in that order.

Upon convergence, the program stops, and the final values of w_1, w_2, and b are printed to the output file (output1.csv). This defines the decision boundary that your PLA has computed for the given dataset.

Note: When implementing your PLA, in case of tie (sum of w_jx_ij = 0), please follow the lecture note and classify the datapoint as -1.

Ensure this file can be executed as:
$ python3 problem1.py input1.csv output1.csv

The code includes plotting functions. However those are disabled when executing the code from the command line in the format specified immediately above.

"""

# builtin modules
import os
import psutil
import requests
import sys

# 3rd party modules
import pandas as pd
import numpy as np
import plotly.graph_objects as go

class problem1:

    def get_data(source_file, names_in:list = ['feature1','feature2','labels']):

        # Define input and output filepaths
        input_path = os.path.join(os.getcwd(),'datasets','in', source_file)

        # Read input data
        df = pd.read_csv(input_path, names=names_in)

        return df

    def perceptron_classify(df, n:int = 200, names_in:list = ['feature1','feature2','labels']):
        """
        1. set b = w = 0
        2. for N iterations, or until weights do not change
            (a) for each training example xᵏ with label yᵏ
                i. if yᵏ — f(xᵏ) = 0, continue
                ii. else, update wᵢ, △wᵢ = (yᵏ — f(xᵏ)) xᵢ
        """

        # transform the dataframe to an array
        data = np.asmatrix(df, dtype = 'float64')

        # get the first two columns as pairs of values
        features = data[:, :-1]
        # get the last column
        labels = data[:, -1]

        # assign zero weight as a starting point to features and labels
        w = np.zeros(shape=(1, features.shape[1]+1)) #e.g. array([0., 0., 0.])
        w_ = np.empty(shape=[0,3]) # declare w_ as an empty matrix of same shape as w

        for iteration in range(0,n):
            for x, label in zip(features, labels):
                x = np.insert(x, 0, 1) # add a column of 1s to represent w0
                f = np.dot(w, x.transpose()) # a scalar
                if f * label <= 0:
                    w += (x * label.item(0,0)).tolist() # because label comes from being a matrix (matrix([[1.]])) and needs to be converted to scalar
                else:
                    iteration = n

            w_ = np.vstack((w_, w))

        return (w_, w_[-1])

    def plot_results(df, weights, names_in:list = ['feature1','feature2','labels']):
        """
        Plot the Perceptron classifier, from the following inputs:
        - source_file: csv file with the input samples
        - weights: from perceptron_classify function
        - names_in: a list of the names of the columns (headers) in the input df
        returns:
        - a plot of the figure in the default browser, and
        - a PNG version of the plot to the "images" project directory
        """
        # Create the figure for plotting the initial data
        fig = go.Figure(data=go.Scatter(x=df[names_in[0]],
                                        y=df[names_in[1]],
                                        mode='markers',
                                        marker=dict(
                                        color=df[names_in[2]],
                                        colorscale='Viridis',
                                        line_width=1,
                                        size = 16),
                                        text=df[names_in[2]], # hover text goes here
                                        showlegend=False))  # turn off legend only for this item

        # Create the 1D array for X values from the first feature; this is just to be able to plot a line
        # within the space defined by the two features explored
        X = np.linspace(0, max(df[names_in[0]].max(),df[names_in[1]].max()))
        # Vector Y will calculated from the weights, w1, w2, the bias, b, and the value of X in its 1D linear space
        Y = []

        for b, w1, w2 in [weights]: #(matrix.tolist()[0] for matrix in weights):
            for x in X:
                if w2 == 0:
                    y = 0.0
                else:
                    y = (-(b / w2) / (b / w1))* x + (-b / w2) # per the equation of a line, e.g. C = Ax + By
                Y.append(y)

        # Add the threshold line to the plot
        fig.add_trace(go.Scatter(x=X, y=Y,
                                    mode= 'lines',
                                    name = 'Threshold'))

        # Give the figure a title
        fig.update_layout(title='Perceptron Algorithm | Problem 1')

        # Show the figure, by default will open a browser window
        fig.show()

        # export plot to png file to images directory
        # create an images directory if not already present
        if not os.path.exists("images"):
            os.mkdir("images")
        ## write the png file with the plot/figure
        return fig.write_image("images/fig1.png")

    def write_csv(filename, weights):
        # write the outputs csv file
        filepath = os.path.join(os.getcwd(),'datasets','out', filename)
        dataframe = pd.DataFrame(data=weights, columns=('b','w1','w2'))
        # reorder the columns in the dataframe in accordance with assignment
        order = [1,2,0] # setting column's order, 'b' goes as first column followed by weights
        dataframe = dataframe[[dataframe.columns[i] for i in order]]
        dataframe.to_csv(filepath)
        return print("New Outputs file saved to: <<", filename, ">>", sep='', end='\n')

    def main():

        in_data = 'input1.csv'
        out_data = 'output1.csv'

        df = get_data(in_data)
        (w_, w) = perceptron_classify(df)
        plot_results(df, w)
        write_csv(out_data, w_)

    if __name__ == '__main__':

        main()


import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from scipy.stats import multivariate_normal
import matplotlib
import time
import random
import math

Z1=[]
Z2=[]

#------------generate 1000 values for Z1 and Z2 to get ~N(0,1)------------------------#
def Marsaglia_and_Bray():
    count_acc=0
    while(1):
        u1=random.uniform(0,1)
        u2=random.uniform(0,1)
        u1=2*u1-1
        u2=2*u2-1
        x=u1**2+u2**2
        if(x>1):
            continue
        else:
            count_acc=count_acc+1
            y=math.sqrt(-2*math.log(x)/x)
            z1=u1*y
            z2=u2*y
            Z1.append(z1)
            Z2.append(z2)
            if(count_acc==1000):
                break
#--------------------------------------------------------------------------------------#

#-------------------find the matrix A from sigma1, sigma2 and rho----------------------#
def return_A(sigma1, sigma2, rho):
    A=[]
    A.append(sigma1) #A11
    A.append(0) #A12
    A.append(rho*sigma2) #A21
    A.append(sigma2*(math.sqrt(1-rho**2))) #A22
    return A

#--------------------------------------------------------------------------------------#

#--------------------------- PDF for multivariate normal-------------------------------#
def return_multivariate_normal_pdf(x,det,inv,mean):
    d=2
    diff=x-mean
    denom=(((2*math.pi)**(1/2))*(det**(1/2)))
    power_quan=-0.5*np.matmul(diff.T,np.matmul(inv,diff))
    num=math.exp(power_quan)
    res=num/denom
    return res
#--------------------------------------------------------------------------------------#

#--------------------------- PDF for univariate normal-------------------------------#
def return_univariate_normal_pdf(x,mean,var):
    power_term = -(np.square(x-mean))/(2*var)
    num=np.exp(power_term)
    denom = np.sqrt(2*np.pi*var)
    res=num/denom
    return res
#--------------------------------------------------------------------------------------#

a_values=[-0.5,0,0.5,1] # allowed values of a as per q1.1

# -----------------------values obtained from the Covariance Matrix E-----------------#
MU=[5,8]
SIGMA1=1
SIGMA2=2
#-------------------------------------------------------------------------------------#

Marsaglia_and_Bray() # calling the function to generate 1000 N(0,1) values and store in Z1 and Z2

for i in range (len(a_values)):
    a=a_values[i]
    RHO=2*a/(SIGMA1*SIGMA2) #2a=rho*sigma1*sigma2
    A11,A12,A21,A22=return_A(SIGMA1,SIGMA2,RHO)
    COV_matrix=np.array([[1,2*a],[2*a,4]]) #making this an np array for later use (of transpose, inverse etc..)

    X1=[]
    X2=[]
    #--------------q1.1 done. In X1[], X2[] we have the generated values of X----------#
    for j in range (len(Z1)):
        X1.append(MU[0]+A11*Z1[j])
    for j in range (len(Z2)):
        X2.append(MU[1]+A21*Z1[j]+A22*Z2[j])
    #----------------------------------------------------------------------------------#

    #drawing the histogram corresponding to the different values of a.
    fig = plt.figure(figsize= (35, 50), frameon= True)

    hist, xedges, yedges = np.histogram2d(X1, X2, bins = (15, 15))
    xpos, ypos = np.meshgrid(xedges[:-1]+0.05, yedges[:-1]+0.05 , indexing = 'ij')
    xpos = xpos.ravel()
    ypos = ypos.ravel()
    zpos = 0
    dx=dy=0.4
    dz = hist.ravel()

    #making a 4*1 plot and adding the first subplot at position 1 ---------q1.2 done---------#
    plot_1 = fig.add_subplot(321, projection='3d')
    plot_1.set_title('3D Histogram for Simulated X')
    plot_1.set_xlabel(r'$X_1$')
    plot_1.set_ylabel(r'$X_2$')
    plot_1.set_zlabel('Frequency')
    plot_1.bar3d(xpos, ypos, zpos, dx, dy, dz,  shade = True, zsort = 'max', cmap = 'inferno')

    #plotting the actual density for the above cases
    x1_range=np.linspace(2,10,200) #x1 has a range from 2 to 10 (plot1)
    x2_range=np.linspace(2,20,200) #x2 has a range from 2 to 20 (plot1)

    AX1, AX2 = np.meshgrid(x1_range, x2_range)
    AX = np.empty(AX1.shape + (2,))
    AX[:, :, 0] = AX1
    AX[:, :, 1] = AX2

    Z=[]
    detereminant_E=np.linalg.det(COV_matrix)
    if(detereminant_E==0):
        print('The determinant for COV matrix is 0 and PDF does not exist in case of a=1.0')
    else:
        inverse_E=np.linalg.inv(COV_matrix)
        for r in range(200):
            M=[]
            for s in range(200):
                x=np.array([AX[r,s,0],AX[r,s,1]])
                result=return_multivariate_normal_pdf(x,detereminant_E,inverse_E,np.array(MU))
                M.append(result)
            Z.append(M)
        Z=np.array(Z)
        Z=Z*200*2*(xedges[1]-xedges[0])*(yedges[1]-yedges[0])
        plot_2= fig.add_subplot(322, projection ='3d')
        plot_2.plot_surface(AX1, AX2, Z, cmap ='inferno', label = 'Actual')
        plot_2.set_title('Actual Density surface')
        plot_2.set_xlabel(r'$X_1$')
        plot_2.set_ylabel(r'$X_2$')
        plot_2.set_zlabel('PDF')

        #plotting the actual and generated densities in a common graph
        plot_3= fig.add_subplot(323, projection='3d')
        plot_3.bar3d(xpos, ypos, zpos, dx, dy, dz,  shade = True, zsort = 'max', cmap = 'inferno', alpha=0.3)
        plot_3.plot_surface(AX1, AX2, Z, cmap ='inferno', alpha=0.7)
        plot_3.set_title('Simulated histogram for X vs Actual surface')
        plot_3.set_xlabel(r'$X_1$')
        plot_3.set_ylabel(r'$X_2$')
        plot_3.set_zlabel('Frequency / PDF')

#     plotting for the marginal 1 dimensional cases!
    figpos1=325
    figpos2=326
    if(a==1):
        figpos1=323
        figpos2=324

    # plotting for X1-------------------------------------------------------------------------------
    plot_4 = fig.add_subplot(figpos1)
    counts, bins, _=plot_4.hist(X1, bins = 20, label = 'Simulated',rwidth=0.9)
    xaxis= np.arange(bins[0]-0.5, bins[-1]+0.5, 0.2)
    yaxis= return_univariate_normal_pdf(xaxis, MU[0], SIGMA1**2) * (bins[1] - bins[0]) * len(X1)
    plot_4.plot(xaxis, yaxis, label='Actual')
    plot_4.set_title('X1 marginal distribution with \u03BC = {} and {} = {}'.format(round(np.mean(X1),4), r"$\sigma^{2}$", round(np.std(X1)**2,4)))
    plot_4.set_xlabel('Values')
    plot_4.set_ylabel('Frequency')
    plot_4.legend()

    # plotting for X2-------------------------------------------------------------------------------
    plot_5 = fig.add_subplot(figpos2)
    counts, bins, _ = plot_5.hist(X2, bins = 20, label = 'Simulated',rwidth=0.9)
    xaxis = np.arange(bins[0]-0.5, bins[-1]+0.5, 0.2)
    yaxis = return_univariate_normal_pdf(xaxis, MU[1], SIGMA2**2) * (bins[1] - bins[0]) * len(X2)
    plot_5.plot(xaxis, yaxis, label = 'Actual')
    plot_5.set_title('X2 marginal distribution with \u03BC = {} and {} = {}'.format(round(np.mean(X2),4), r"$\sigma^{2}$", round(np.std(X2)**2),4))
    plot_5.set_xlabel('Values')
    plot_5.set_ylabel('Frequency')
    plot_5.legend()

    mu_array='['+str(np.mean(X1))+','+str(np.mean(X2))+']'
    print("Plots for a = {}".format(a))
    plt.show()
    #we have used a special character \u03BC for showing the greek alpha bet mu

Semester 5/MA 323 (Monte Carlo)/Lab Submissions/Lab 6/180123062_ABSatyaprakashq1.py


# -*- coding: utf-8 -*-
import numpy as np
import math

__all__ = ["haversine",
        	"manhattan",
        	"euclidean",
        	"minkowski",
        	"cosine_similarity",
        	"hamming",
			"mahalanobis"]

def _validate_vector(vector, dtype=None):
    vector = np.asarray(vector, dtype=dtype).squeeze()
    vector = np.atleast_1d(vector)
    if vector.ndim > 1:
        raise ValueError("Input vector should be 1-D.")
    return vector

def _validate_var_type(value, dtype=None):
    if isinstance(value, dtype):
        return value
    else:
        raise ValueError("Input value not of type: " + str(dtype))

def _validate_weights(w, dtype=np.double):
    w = _validate_vector(w, dtype=dtype)
    if np.any(w < 0):
        raise ValueError("Input weights should be all non-negative")
    return w

def hamming(vector1, vector2) :
    if type(vector1) == type(vector2) == int:
        return bin(vector1 ^ vector2).count('1')
    elif type(vector1) == type(vector2) == str:
        if len(vector1) != len(vector2):
            raise ValueError("Undefined for sequences of unequal length.")
        return sum(el1 != el2 for el1, el2 in zip(vector1, vector2))
    else:
        return "Hi"

def haversine(coord1, coord2, R = 6372800):
    '''
    Important to note is that we have to take the radians of the longitude and latitude values.
    R  corresponds to Earths mean radius in meters (6372800)
    '''
    lat1, lon1 = _validate_vector(coord1, dtype=np.double)
    lat2, lon2 = _validate_vector(coord2, dtype=np.double)

    phi1, phi2 = math.radians(lat1), math.radians(lat2)
    dphi       = math.radians(lat2 - lat1)
    dlambda    = math.radians(lon2 - lon1)

    a = math.sin(dphi/2)**2 + \
        math.cos(phi1)*math.cos(phi2)*math.sin(dlambda/2)**2

    return 2*R*math.atan2(math.sqrt(a), math.sqrt(1 - a))

def manhattan(vector_1, vector_2):
    '''
    ## Input
    manhattan([1,2.3213213,3],[4,5.321,6.123])
    ## Output
    -9.1226787
    '''
    vector_1 = _validate_vector(vector_1, dtype=np.double)
    vector_2 = _validate_vector(vector_2, dtype=np.double)
    return minkowski(vector_1, vector_2, p=1)

def euclidean(vector_1, vector_2):
    '''
    ## Input
    euclidean([1,2.3213213,3],[4,5.321,6.123])
    ## Output
    5.267940897849338
    '''
    vector_1 = _validate_vector(vector_1, dtype=np.double)
    vector_2 = _validate_vector(vector_2, dtype=np.double)
    return minkowski(vector_1, vector_2, p=2)

def minkowski(vector_1, vector_2, p=1):
    vector_1 = _validate_vector(vector_1, dtype=np.double)
    vector_2 = _validate_vector(vector_2, dtype=np.double)
    distance = 0.0
    for i in range(len(vector_1)):
            distance += (vector_1[i] - vector_2[i])**p
    return (distance)**(1.0/p)

def cosine_similarity(vector_1, vector_2):
    vector_1 = _validate_vector(vector_1, dtype=np.double)
    vector_2 = _validate_vector(vector_2, dtype=np.double)
    num = np.dot(vector_1, vector_2)
    den = (np.sqrt(np.dot(vector_1, vector_1)) * np.sqrt(np.dot(vector_2, vector_2)))
    return num / den

def mahalanobis(u,v,VI):
    u = _validate_vector(u)
    v = _validate_vector(v)
    VI = np.atleast_2d(VI)
    delta = u - v
    m = np.dot(np.dot(delta, VI), delta)
    return np.sqrt(m)


from math import sqrt
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from statsmodels.tsa.stattools import adfuller

def compute_correlation(x,y,r2=False,auto=False):

    '''Take two array-like series to calculate the correlation
    x: numpy.array or pandas.DataFrame: x value for correlation
    y: numpy.array or pandas.DataFrame: y value for correlation

    r2: Boolean (optional): return r-squared value instead of r'''

    '''Need to remove the mean for autocorrelation?'''

    df = pd.DataFrame({'x':x,'y':y})

    if auto:

        df['x'] = df['x'] - df['x'].mean()
        df['y'] = df['y'] - df['y'].mean()

    df.dropna(inplace=True)

    n = len(df)

    df['x2'] = np.square(df['x'])
    df['y2'] = np.square(df['y'])
    df['xy'] = df['x'] * df['y']
    sum_x = df['x'].sum()
    sum_y = df['y'].sum()
    sum_xy = df['xy'].sum()
    sum_x2 = df['x2'].sum()
    sum_y2 = df['y2'].sum()

    corr = (n*(sum_xy) - (sum_x*sum_y)) / (sqrt(((n*(sum_x2) - (sum_x**2)) *((n*(sum_y2) - (sum_y**2))))))

    #corr_test = np.cov(df['x'].values,df['y'].values)[0,1]

    return df, corr

def acf_compute(x,y):

    if isinstance(x,pd.DataFrame) or isinstance(x,pd.Series):

        x = x.dropna().values

    if isinstance(y,pd.DataFrame) or isinstance(y,pd.Series):

        y = y.dropna().values

    nx = len(x)
    ny = len(y)

    x = x[nx-ny:]

    top = np.mean(np.dot((x-np.mean(x)), (y-np.mean(y))))

    bot = np.sum(np.square((x-np.mean(x))))

    acf_r = top/bot

    return acf_r

def autocorrelate(x,shift=1,conf_int=False,lags=None,df=False):

    if isinstance(x,pd.DataFrame) or isinstance(x,pd.Series):

        x = x.values

    n = len(x)

    if lags is None:

        lags = n

    else:

        lags = lags

    r_array = np.empty(lags)
    conf_lower = np.empty(lags)
    conf_upper = np.empty(lags)

    for i in range(lags):

        r_array[i] = acf_compute(x[i:],x[:len(x)-i])
        conf_lower[i] = -1.96 / np.sqrt(len(x)-i)
        conf_upper[i] = 1.96 / np.sqrt(len(x)-i)

    if df:

        r_array = pd.DataFrame(data=r_array)

    if conf_int:

        return r_array, conf_upper, conf_lower

    return r_array

def plot_auto_corr(x,title=None,lags=None):

    auto_corr, conf_upper, conf_lower = autocorrelate(x,conf_int=True,lags=lags)

    plt.plot(auto_corr,linestyle='none',marker='o',color='red')

    for i, x in enumerate(auto_corr):
        plt.vlines(x=i,ymin=min(0,x),ymax=max(0,x))

    plt.fill_between([i for i in range(len(auto_corr))],conf_lower,conf_upper,color='green',alpha=0.2)

    if title is None:
        title = 'Autocorrelation (Lags = {})'.format(len(auto_corr))

    else:

        title = title + ' (Lags = {})'.format(len(auto_corr))
    plt.title(title,fontsize=16)
    plt.show()

def test_stationarity(df, print_results=True, **kwargs):

    '''Use stattools adfuller function with a more DataFrame-friendly format

    df = pandas.DataFrame or pandas.Series: required, used for testing stationarity

    **kwargs = dict, used to feed adfuller arguments'''

    raw_results = adfuller(df,**kwargs)

    df_rows = {fk: fv for fv, fk in zip(raw_results[:4],list(['Test Statistic','P-Value','Lags Used','Observations Taken']))}

    df_rows.update({sk: sv for sk, sv in raw_results[4:-1][0].items()})

    dickey_test_results = pd.DataFrame(index=df_rows.keys(),data=list(df_rows.values()),columns=['Metric'])

    if print_results:
        print('Results of the Augmented Dickey-Fuller Test: \n\n', dickey_test_results.head(10))

    return dickey_test_results


"""
Ajay Kc
013213328
EE 381
Project 1 Part 3

The program checks the probability of getting 4 of a kind card
"""

import numpy as np

def fourOfAKind():

    #drawnCards = np.random.randint(1,53,5)
    drawnCards = np.random.permutation(52)[0:5]
    cardFaces = {}
    for i in drawnCards:
        if (i % 13 in cardFaces):
            cardFaces[i % 13] += 1
        else:
            cardFaces[i % 13] = 1

    for k, v in cardFaces.items():
        if v == 4:
            return 'Success'

    return 'Failure'

successCount = 0
for i in range(0, 100000):
    if fourOfAKind() == 'Success':
        successCount += 1

probability = successCount / 100000
print('The probability of getting a 4-of-a-kind when 5 cards are drawn %s' % (probability))


#Array Mathematics
import numpy

n, m = input().split()
a = [numpy.array(list(map(int,input().split())), int)]
b = [numpy.array(list(map(int,input().split())), int)]

print(numpy.add(a,b))
print(numpy.subtract(a,b))
print(numpy.multiply(a,b))
print(numpy.array(numpy.divide(a,b), int))
print(numpy.mod(a,b))
print(numpy.power(a,b))

#Arrays

def arrays(arr):
    # complete this function
    # use numpy.array
    return numpy.array(arr, float)[::-1]

#Shape and Reshape

import numpy

arr = numpy.array(list(map(int,input().split())))
print(numpy.reshape(arr,(3,3)))

#Transpose and Flatten

import numpy

n, m = input().split()

arr = numpy.array([input().split() for _ in range(int(n))], int)

print(numpy.transpose(arr))
print(arr.flatten())

#Concatenate

import numpy

n, m, p = list(map(int,input().split()))

arr1 = numpy.array([input().split() for _ in range(n)], int)
arr2 = numpy.array([input().split() for _ in range(m)], int)
print(numpy.concatenate((arr1, arr2), axis = 0))

#Zeros and Ones

import numpy

shape = list(map(int,input().split()))

print(numpy.zeros(shape, dtype=int))
print(numpy.ones(shape, dtype=int))

#Eye and Identity

import numpy
numpy.set_printoptions(legacy='1.13')

n, m = list(map(int,input().split()))

print(numpy.eye(n,m))

#Floor, Ceil and Rint

import numpy

numpy.set_printoptions(legacy='1.13')

arr = list(map(float,input().split()))

aux = numpy.floor(arr)
print(aux)
aux = numpy.ceil(arr)
print(aux)
aux = numpy.rint(arr)
print(aux)

#Sum and Prod
import numpy

n,m = list(map(int,input().split()))

arr = []
for _ in range(n):
    arr.append(list(map(int,input().split())))

print(numpy.prod(numpy.sum(arr, axis = 0)))

#Min and Max

import numpy

n, m = list(map(int,input().split()))

arr = []
for _ in range(n):
    arr.append(list(map(int,input().split())))
print(numpy.max(numpy.min(arr, axis=1)))

#Mean, Var, and Std
import numpy
n, m = list(map(int,input().split()))

arr = []
for _ in range(n):
    arr.append(list(map(int,input().split())))

print(numpy.mean(arr, axis=1))
print(numpy.var(arr, axis=0))
print(numpy.around(numpy.std(arr),decimals=11) ) #found numpy.araund in Discussions section

#Dot and Cross

import numpy

n = int(input())

A = []
for _ in range(n):
    A.append(list(map(int, input().split())))

B = []
for _ in range(n):
    B.append(list(map(int, input().split())))

print(numpy.dot(A,B))

#Inner and Outer

import numpy

arr1 = list(map(int,input().split()))
arr2 = list(map(int,input().split()))

print(numpy.inner(arr1, arr2))
print(numpy.outer(arr1, arr2))

#Polynomials
import numpy

arr = list(map(float, input().split()))
n = float(input())

print(numpy.polyval(arr, n))

#Linear Algebra

import numpy

n = int(input())

mat = []
for _ in range(n):
    mat.append(list(map(float,input().split())))
print(numpy.around(numpy.linalg.det(mat), decimals=2))


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
learning and gate with logistic regression

"""
import numpy as np
from tqdm import tqdm, trange

import matplotlib.pyplot as plt

def initizalize_with_zeros(dim):
    w = np.zeros(shape=(dim,1))
    b = 0
    return w, b

def sigmoid(z):
    return 1 / (1 + np.exp(-1 * z))

def cross_entropy_loss_function(m, A, Y):
    c = (-1/m)*np.sum(Y*np.log(A)+(1-Y)*(np.log(1-A)))
    return c

def propagate(w,b,X,Y):
    m = X.shape[1]
    z = (np.dot(w.T, X) + b)

    #compute activation
    A = sigmoid(z)

    #compute cross-entropy-loss
    cost = cross_entropy_loss_function(m, A, Y)

    #backward propagation
    dw = (1/m)*np.dot(X, (A-Y).T)
    db = (1/m)* np.sum(A - Y)
    grads = {"dw" : dw, "db" : db}

    return grads, cost

"""
# Optimization
The goal is to learn ww and bb by minimizing the cost function J.
For a parameter θ, the update rule is θ=θ−α dθ=θ−α dθ,
where α is the learning rate.
"""

def optimize(w, b, X, Y, num_iterations, learning_rate):
    #cost cache
    costs = []

    for i in trange(num_iterations):
        grads, cost = propagate(w, b, X, Y)

        # Retrieve derivatives from grads
        dw = grads["dw"]
        db = grads["db"]

        #update rule
        w = w - (learning_rate * dw)
        b = b - (learning_rate * db)

        if i % 100 == 0:
            costs.append(cost)

    params = {"w":w, "b":b}
    grads = {"dw":dw, "db":db}

    return params, grads, costs

def predict(w, b, X):
    m = X.shape[1]
    Y_prediction = np.zeros((1,m))

    A = sigmoid(np.dot(w.T, X) + b)

    for i in range(A.shape[1]):
        Y_prediction[0, i] = 1 if A[0,i] > 0.5 else 0

    return Y_prediction

if __name__ == '__main__':
    w, b, X, Y = np.random.uniform(size=2), np.random.uniform(size=1), np.array([[0.,1.,0.,1],[0.,0.,1.,1]]), np.array([[0,0,0,1]])
    params, grads, costs = optimize(w, b, X, Y, num_iterations= 10000, learning_rate = 0.01)

    X_test = np.array([np.random.uniform(-1,2,2) for x in range(10)])
    preds = predict(params["w"], params["b"], X_test.T)
    print(preds)

    model_costs = np.squeeze(costs)

    plt.plot(model_costs)
    plt.ylabel('training cost')
    plt.xlabel('iterations (per hundreds)')
    plt.title("Learning rate = 0.01")
    plt.show()


# Problem: https://projecteuler.net/problem=358

from sage.all import *

"""
    . According to https://en.wikipedia.org/wiki/Cyclic_number,
        <quote>
            Conversely, if the digital period of 1/p (where p is prime) is p − 1, then the digits represent a cyclic number.
        </quote> (1)
    and,
        <quote>
            From the relation to unit fractions, it can be shown that cyclic numbers are of the form of the Fermat quotient
                (b^(p-1)-1)/p
            where b is the number base (10 for decimal), and p is a prime that does not divide b. (Primes p that give cyclic numbers in base b are called full reptend primes or long primes in base b).
        </quote> (2)

    . Note that, a prime p is a full reptend prime when
        Mod(10, p).multiplicative_order() is p-1 (which means the cycle length is p-1). (3)

    . Let the cyclic number we want to find be 'alpha'.

    . From (1), we can say that, the cyclic number we want to find is in the form of
        alpha = (1/p) * (10**(p-1))

    . Since the left most digits of the cyclic number is 00000000137, then
        0.00000000137 < 1/p < 0.00000000138
        Therefore, floor(1/0.00000000137) > p > floor(1/0.00000000138)
    -> we have a lowerbound and an upperbound for p. (4)

    . We have that the rightmost digits of alpha is 56789.
      From (2), we have that (10^(p-1)-1)/p = alpha.
                       -> 10^(p-1)          = alpha * p + 1
                       -> 10^(p-1) mod 10^5 = (alpha * p + 1) mod 10^5
                       ->                 0 = {[alpha (mod 10^5)] * [p (mod 10^5)] + 1} (mod 10^5)
                       ->                 0 = [56789 * (p mod 10^5) + 1] (mod 10^5) (5)

    . From (2), (3), (4), (5), we can find the prime that produces alpha using the following algorithm,
        for p in [floor(1/0.00000000138), floor(1/0.00000000137)]:
            if [56789 * (p mod 10^5) + 1] (mod 10^5) == 0 and Mod(10, p).multiplicative_order() == p - 1:
                desired_p = p
                break

    . Note that, due to the definition of cyclic number, each rotation must appear once in the set S = {alpha*k | 1 <= k <= desired_p - 1}
      Therefore, for every position i, the i^th digit of alpha must appear as the last digit in one rotation in S.
      (otherwise, by pigeon hole theorem, there would be two distinct k_1 and k_2 in [1, desired_p - 1] such that alpha * k_1 = alpha * k_2, which disagrees with integer arithmetic).

    . Therefore, we can find the sum of the digits by simply summing up the last digits of desired_p * k for all k in [1, desired_p - 1].
      In other words, digits_sum = sum(k in [1, desired_p-1]) [(desired_p *k) mod 10]
                                 = sum(k in [1, desired_p-1]) [(desired_p mod 10) * (k mod 10)]
                                 = (desired_p mod 10) * sum(k in [1, desired_p-1]) [k mod 10]
      Note that (k mod 10) repeatedly cycle around [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; and 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 = 45
      So sum(k in [1, desired_p-1]) [k mod 10]
       = sum(k in [0, desired_p-1]) [k mod 10]
       = sum([0..9]) * floor((desired_p-1) / 10) + sum([0..(desired_p-1) mod 10])
       = 45 * floor((desired_p-1) / 10) + sum([0..(desired_p-1) mod 10])
      As a result, digits_sum = (desired_p mod 10) * [45 * floor((desired_p-1) / 10) + sum([0..(desired_p-1) mod 10])]
"""

if __name__ == "__main__":
    ans = 0

    p_lowerbound = int(1/0.00000000138)
    p_upperbound = int(1/0.00000000137)

    RIGHT_MOST_DIGITS = 56789
    MOD = 10**5

    p = p_lowerbound
    while p < p_upperbound:
        m = (RIGHT_MOST_DIGITS * (p % MOD) + 1) % MOD
        if m == 0 and (Mod(10, p).multiplicative_order()) == p-1:
            break
        p = next_prime(p)

    digits_sum = 0
    desired_p = p

    sum_0_n = lambda n: n*(n+1)//2

    digits_sum = (desired_p % 10) * (sum_0_n(9) * ((desired_p-1) // 10) + sum_0_n((desired_p-1) % 10))

    ans = digits_sum

    print(ans)


# Disciplina: Mecânica Quântica (FIS01210)
# Aluno: Ramon Rossa de Paula (00243967)

# "Este trabalho foi produzido em Python, utilizando a IDE Visual Studio Code, exclusivamente por mim. Nenhuma parte deste trabalho (texto e fórmulas) foi copiada digitalmente de outras fontes"

# ____________________________________________________________________________________

# Importações

import math
import numpy as np
from numpy import loadtxt
import matplotlib.pyplot as plt
from scipy import integrate
from numpy import sqrt, exp, log, pi, abs

# ____________________________________________________________________________________

# Calculando a área do resultado da integral fundamental:

def fe(a, ep):
    return sqrt(pi/ep) * exp((-a**2)/(4*ep))

# Código para o gráfico:

a = np.arange(-10, 10, 0.01)

plt.title("Área")
plt.xlabel('α')
plt.ylabel('fe(α)')
plt.grid()

plt.plot(a, fe(a, 0.1))   # Largura proporcional a ε e altura proporcional a 1/ε.
plt.plot(a, fe(a, 0.5))
plt.plot(a, fe(a, 1))
plt.plot(a, fe(a, 1.5))
plt.plot(a, fe(a, 2))
plt.plot(a, fe(a, 5))
plt.plot(a, fe(a, 10))
plt.plot(a, fe(a, 20))
plt.plot(a, fe(a, 50))
plt.plot(a, fe(a, 100))

plt.legend(['ε = 0.1', 'ε = 0.5', 'ε = 1', 'ε = 1.5',
            'ε = 2', 'ε = 5', 'ε = 10',
            'ε = 20', 'ε = 50', 'ε = 100',], loc=1)

plt.show()


# To add a new cell, type '# %%'
# To add a new markdown cell, type '# %% [markdown]'
# %%
#integrantes: GABRIEL GOMEZ, EDUARDO DE LA HOZ, STEPHANIA DE LA HOZ

# %%
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import scipy.linalg as la
import sys
import mpl_toolkits.mplot3d as mpl
from numpy import genfromtxt
from collections import Counter

# %%
def cleaner(df,k):
    return np.array(df[(abs(df[0]-np.mean(df[0])) <= k*np.std(df[0])) & (abs(df[1]-np.mean(df[1])) <= k*np.std(df[1]))])

def gerOutliners(df,k):
    return np.array(df[(abs(df[0]-np.mean(df[0])) > k*np.std(df[0])) | (abs(df[1]-np.mean(df[1])) > k*np.std(df[1]))])
def proy(rData,base):
    u1p=np.dot(rData,base[0])
    u2p=np.dot(rData,base[1])
    u3p=np.dot(rData,base[2])
    u1u1=np.linalg.norm(base[0])
    u2u2=np.linalg.norm(base[1])
    u3u3=np.linalg.norm(base[2])
    u1pdu1=u1p/u1u1
    u2pdu2=u2p/u2u2
    u3pdu3=u3p/u3u3
    sum1=np.zeros((len(rData),3))
    sum2=np.zeros((len(rData),3))
    sum3=np.zeros((len(rData),3))
    for i in range(len(rData)):
        sum1[i]=u1pdu1[i]*base[0,:]
        sum2[i]=u2pdu2[i]*base[1,:]
        sum3[i]=u3pdu3[i]*base[2,:]
    rest=sum1+sum2+sum3
    return rest

# %%
df=pd.read_table('irisdata.txt',skiprows=9,header=None)
df=df.drop(columns=4)
rawdata=np.array(df)
covRawData = np.cov(rawdata.T)
resultRaw = la.eig(covRawData)
rawdata[0,:]

# %%
covRawData

# %%
resultRaw[0].real

# %%
resultRaw[1]

# %%
test=np.array(resultRaw[1])
test[0]

# %%
eugenValue=np.array(resultRaw[0].real)
sumEugen=np.sum(eugenValue)
porEugen=eugenValue/sumEugen
porEugen=porEugen*100

# %%
x=np.arange(4)
fig=plt.figure()
ax=fig.add_axes([0,0,1,1])
lang=['PC1','PC2','PC3','PC4']
ax.bar(lang,porEugen)
plt.show()

# %%
rawtest=df.drop(columns=3)
tt=np.array(test[:,0:3])
t=proy(rawtest,tt)
t

# %%
fig=plt.figure()
ax=fig.add_subplot(111,projection='3d')
ax.scatter3D(t[:,0], t[:,1], t[:,2],c=t[:,2],cmap='Dark2')
plt.show()


import numpy as np
from typing import Callable

import LinEq as eq

def LinearRegression(f, x :np.ndarray):
    y = np.array(list(map(f, x)))
    n = x.shape[0]
    k2 = ( n * x.dot(y) - x.sum() * y.sum()) / ( n * (x**2).sum() - x.sum()**2 )
    k1 = np.average(y) - k2 * np.average(x)
    return lambda x: k1 + k2 * x

def ExponentialRegression(f, x :np.ndarray, l = None):
    y = np.vectorize(f)(x)
    A_l = lambda l: (y.dot(np.exp(l * x)) / np.sum(np.exp(2 * l * x)))
    f_l = lambda l: (x * y).dot(np.exp(l * x)) - A_l(l) * x.dot(np.exp(2 * l * x))

    if l == None:
        print('find root for the returned function and supply it as l')
        return f_l
    else:
        A = A_l(l)
        return lambda x: A * np.exp( l * x )

def PolynomialRegression(f : Callable, x: np.ndarray, order: int) -> np.ndarray:
    y = np.vectorize(f)(x)

    T = []
    for i in range(order * 2 - 1):
        T.append(x**i)
    T = np.array(T)

    A = np.zeros((order, order))
    for i, j in enumerate(T, start= - order + 1):
        diag = np.diag(np.fliplr(A),k=-i)
        diag.setflags(write=True)
        diag.fill(np.sum(j))
    C = T[:order].dot(y).T
    poly = eq.Gaussian_Elimination(A,C[...,None])
    return poly


import sympy as sym
X, h = sym.symbols('X h')
half = sym.Rational(1, 2)
psi = [half*(X-1)*X, 1-X**2, half*(X+1)*X]
dpsi_dX = [sym.diff(psi[r], X) for r in range(len(psi))]

# Element matrix
# (2/h)*dpsi_dX[r]*(2/h)*dpsi_dX[s]*h/2
import numpy as np
d = 2
# Use a numpy matrix with general objects to hold A
A = np.empty((d+1, d+1), dtype=object)
for r in range(d+1):
    for s in range(d+1):
        integrand = dpsi_dX[r]*dpsi_dX[s]*2/h
        A[r,s] = sym.integrate(integrand, (X, -1, 1))
print(A)

# Element vector
# f*psi[r]*h/2, f=1
d = 2
b = np.empty(d+1, dtype=object)
for r in range(d+1):
    integrand = -psi[r]*h/2
    b[r] = sym.integrate(integrand, (X, -1, 1))
print(b)


import sys
sys.path.append('..')
import numpy as np
import matplotlib.pyplot as plt
from chebyspectral import *

deg = 16  # degree of Chebyshev polynomial

# Source term
f = lambda xq: np.exp(4*xq)
fHat = chebfit(f, deg)

# Boundary conditions
bc_value_1 = 0
bc_derivative_order_1 = 1  # Neumann (first derivative)
bc_position_1 = -1
bc_axis_1 = 0
bc_1 = [bc_value_1, bc_derivative_order_1, bc_position_1, bc_axis_1]

bc_value_2 = 0
bc_derivative_order_2 = 0 # Dirichlet
bc_position_2 = 1
bc_axis_2 = 0
bc_2 = [bc_value_2, bc_derivative_order_2, bc_position_2, bc_axis_2]

# Differentiation matrix
l_operator = [0, 0, 1]
L = chebdiff(l_operator, deg)
L, fHat = chebbc(L, fHat, [bc_1, bc_2])

# Compute solution
u = np.dot(np.linalg.pinv(L), fHat)

# Plot solution
N = 100
x = np.linspace(-1, 1, N)
exact_sol = (np.exp(4*x) - 4*np.exp(-4)*(x-1) - np.exp(4))/16
series_sol = chebeval(u, x)

fig, ax = plt.subplots()
ax.plot(x, series_sol , 'b', label='Approximation')
ax.plot(x, exact_sol, 'r--', label='Exact')
handles, labels = ax.get_legend_handles_labels()
ax.legend(handles, labels)
plt.xlabel('x')
plt.ylabel('f(x)')
plt.show()


import numpy as np

from compute_cost import compute_cost
from gradient_descent import gradient_descent
from load_data import load_data
from plot_data import plot_data, plot_cost
from predict import predict

# Linear Regression: Company Profit per City Population

# Load File and Set Initial Parameters

filename = 'city_profit.txt'
x, y = load_data(filename)
size = y.size
theta = np.array([[0.0], [0.0]])
alpha = 0.01
iterations = 1500
population = 175000

# Cost Function

cost = compute_cost(x, y, size, theta=theta)
print(f"With given theta: \n\tCost computed = {cost}\n")

# Gradient Descent

new_theta, cost_history = gradient_descent(x, y, size, theta=theta, alpha=alpha,
                                           iterations=iterations)

# Plot Data and Regression Line

plot_data(x, y, new_theta)

# Plot Cost History

plot_cost(iterations, cost_history)

# Make a Prediction

predict(population, new_theta)


import math
import numpy as np
from scipy.special import beta, betaln, comb, gammaln

# Probability mass functions

def beta_binomial_pmf(k, n, a, b, log_scale=False):
    '''
    The pmf of a beta-binomial distribution.

    Parameters
    ----------
    k, integer
        number of "successes".
    n, integer
        number of draws.
    a, positive real
        alpha parameter for the beta-binomial.
    b, positive real
        beta parameter for the beta-binomial.
    log_scale, boolean
        should the pmf be returned on the log scale?

    Returns
    -------
    prob, array-like of positive reals
        probability mass of k
    '''
    if log_scale:
        return (np.log(comb(n, k)) +
                np.log(beta(k + a, n - k + b)) -
                np.log(beta(a, b)))
    else:
        return (comb(n, k) *
                beta(k + a, n - k + b) /
                beta(a, b))

def dirichlet_multinomial_pmf(x, n, a, log_scale=False):
    '''
    The pmf of a Dirichlet-multinomial distribution.

    Parameters
    ----------
    x, array-like of integers
        number of "successes". This can be a list of integers
        if this is just one set of observations, or it can be
        a KxS list of lists or numpy array if there are K
        categories and S samples.
    n, array-like of integers
        number of draws.
    a, array-like of positive reals
        alpha parameters for the Dirichlet multinomial.
        This can be a K-list of alpha values if we have one
        set of observations, or it can be KxS list of lists
        or numpy array if there are K categories and S samples.
    log_scale, boolean
        should the pmf be returned on the log scale?

    Returns
    -------
    prob, array-like of positive reals
        probability mass of k
    '''
    np.seterr(divide='ignore', invalid='ignore')
    x = np.array(x)
    a = np.array(a)
    n = np.array(n)

    # x and a must have the same dimensions.
    assert(np.shape(x) == np.shape(a))

    sum_a = a.sum(axis=0)

    # 1 if the observation was valid (i.e. all x >= 0) and 0 otherwise
    valid_obs = (x >= 0).prod(axis=0)

    if log_scale:
        log_constant = np.log(n) + betaln(sum_a, n)
        # In product in pmf, we want to include only x's that are non-zero.
        summands = np.log(x) + betaln(a, x)
        summands[x == 0] = 0
        # \log (\prod_{k : x_k > 0} x_k B(alpha_k, x_k))
        log_product = summands.sum(axis=0)

        # turn back into np array just in case it was cast to float
        log_pmf = np.array(log_constant - log_product)
        # if the observation was invalid, it has a probability of 0,
        # thus log-prob of -inf
        log_pmf[valid_obs == 0] = -math.inf
        # if there are "no draws" (i.e. everything already observed)
        # then the pmf is 1 iff all of the x's are 0.
        # This is just by convention, since n = 0 is technically
        # an invalid input to the pmf.
        # sum_of_abs_x is 0 iff all x are 0
        sum_of_abs_x = np.abs(x).sum(axis=0)
        log_pmf[n == 0] = np.log(sum_of_abs_x[n == 0] == 0)
        return log_pmf
    else:
        constant = n * beta(sum_a, n)
        # In product in pmf, we want to include only x's that are non-zero.
        multiplicands = x * beta(a, x)
        multiplicands[x == 0] = 1
        # \prod_{k : x_k > 0} x_k B(alpha_k, x_k)
        product = multiplicands.prod(axis=0)

        # turn back into np array just in case it was cast to float
        pmf = np.array(constant / product)
        # if the observation was invalid, it has a probability of 0
        pmf[valid_obs == 0] = 0

        # if there are "no draws" (i.e. everything already observed)
        # then the pmf is 1 iff all of the x's are 0.
        # This is just by convention, since n = 0 is technically
        # an invalid input to the pmf.
        # sum_of_abs_x is 0 iff all x are 0
        sum_of_abs_x = np.abs(x).sum(axis=0)
        pmf[n == 0] = sum_of_abs_x[n == 0] == 0
        # Get an array back from the 1xL matrix where L is the length of x
        return np.squeeze(np.multiply(constant, product))

def mvt_hypergeo_pmf(k, T, log_scale=False):
    '''
    The pmf of a multivariate hypergeometric distribution.

    Parameters
    ----------
    k, array-like of integers
        number of "successes". This can be a list of integers
        if this is just one set of observations, or it can be
        a KxS list of lists or numpy array if there are K
        categories and S samples.
    T, integer
        true number of "successes"
    log_scale, boolean
        should the pmf be returned on the log scale?

    Returns
    -------
    prob, array-like of positive reals
        probability mass of k
    '''
    k = np.array(k)
    T = np.array(T)
    assert(np.shape(k) == np.shape(T))

    # Turn into column vector if only one observation
    k = k[:, None] if np.ndim(k) == 1 else k
    T = T[:, None] if np.ndim(T) == 1 else T

    # Total balls in urn
    N = T.sum(axis=0)
    # Total number of balls sampled from urn
    n = k.sum(axis=0)

    valid_inputs = np.logical_and(k >= 0, T - k >= 0).prod(axis=0)

    if log_scale:
        log_numerator = (gammaln(T + 1) -
                         gammaln(T - k + 1) -
                         gammaln(k + 1)).sum(axis=0)
        log_denominator = gammaln(N + 1) -\
            gammaln(N - n + 1) -\
            gammaln(n + 1)

        log_pmf = log_numerator - log_denominator
        log_pmf[np.logical_not(valid_inputs)] = -math.inf
        return log_pmf
    else:
        numerator = comb(T, k).prod(axis=0)
        denominator = comb(N, n)
        pmf = numerator / denominator
        pmf[np.logical_not(valid_inputs)] = 0
        return pmf

def beta_pdf(x, a, b, log_scale=False):
    x = np.array(x)
    a = np.array(a)
    b = np.array(b)

    if log_scale:
        log_numer = (a - 1) * np.log(x) +\
            (b - 1) * np.log(1 - x)
        log_denom = betaln(a, b)
        return(log_numer - log_denom)
    else:
        numer = np.power(x, a - 1) *\
            np.power(1 - x, b - 1)
        denom = beta(a, b)
        return(numer/denom)

def pval_from_martingale(martingale, running_min=False):
    '''
    Get a p-value from a martingale with initial expectation 1

    Parameters
    ----------
    martingale, array-like
        the martingale
    running_min, boolean
        should the running minimum be taken?

    Returns
    -------
    p, array-like
        p-values
    '''
    pval = np.minimum(1/martingale, 1)
    pval = np.minimum.accumulate(pval) if running_min else pval

    return pval


import numpy as np
import matplotlib.pyplot as plt

def gaussian_func(sigma, x):
    return 1 / np.sqrt(2 * np.pi * (sigma ** 2)) * np.exp(-(x ** 2) / (2 * (sigma ** 2)))

def gaussian_random_generator(sigma=5, numbers=100000):
    uniform_random_numbers = np.random.rand(numbers, 2)
    rho = sigma * np.sqrt(-2 * np.log(1 - uniform_random_numbers[:, 0]))
    theta = 2 * np.pi * uniform_random_numbers[:, 1]

    gaussian_random = rho * np.array([np.cos(theta), np.sin(theta)])
    gaussian_random_numbers = gaussian_random.flatten()

    min_value = np.min(gaussian_random_numbers)
    max_value = np.max(gaussian_random_numbers)
    x = np.linspace(min_value, max_value + 1, 1000)
    y = gaussian_func(sigma, x)
    plt.hist(gaussian_random_numbers, bins=np.arange(min_value - 0.5, max_value + 1, 1), density=True)
    plt.plot(x, y, linewidth=3)
    plt.xlabel(r'numbers')
    plt.ylabel(r'density')
    plt.savefig("images/q4_" + str(sigma) + "_" + str(numbers) + '.png')
    plt.show()

gaussian_random_generator()


import numpy as np
import pandas as pd

datafile = './data/IBM.csv'

data = pd.read_csv(datafile, sep=',')
# print(data['Adj Close'])

S = data['Adj Close']
N = len(S) - 1
d_t = 1
v_hat = np.log(S[N] / S[0]) / N
print('v_hat (daily return):', v_hat)
print('N * v_hat (annual return):', N * v_hat)
s_2 = 0
for i in range(1, len(S)):
    s_2 += np.power(np.log(S[i] / S[i - 1]) - v_hat, 2)
s_2 /= (N - 1)
print('s (daily volatility):', np.sqrt(s_2))
print('s (annual volatility):', np.sqrt(s_2 * N))

q = 0.5 + 0.5 * (1 / np.sqrt(s_2 / (v_hat ** 2 * d_t) + 1))
q_aprx = 0.5 * 0.5 * v_hat / np.sqrt(s_2) * np.sqrt(d_t)
print('q:', q, 'q approximated:', q_aprx)

U = np.exp(np.sqrt(s_2 * d_t + (v_hat * d_t) ** 2))
D = np.exp(-np.sqrt(s_2 * d_t + (v_hat * d_t) ** 2))
print('U:', U, 'D:', D)

U_aprx = np.exp(np.sqrt(s_2 * d_t))
D_aprx = np.exp(-np.sqrt(s_2 * d_t))
print('U approximated:', U_aprx, 'D approximated:', D_aprx)


import numba
from numba import f8
import numpy as np
from scipy.spatial.qhull import Delaunay
from shapely.geometry import Polygon, Point

@numba.jit(f8(f8[:], f8[:], f8[:]), nopython=True, nogil=True)
def triangle_area(a, b, c):
    return np.abs(a[0] * (b[1] - c[1]) +
                  b[0] * (c[1] - a[1]) +
                  c[0] * (a[1] - b[1])) / 2

@numba.jit(f8[:](f8[:], f8[:], f8[:]), nopython=True, nogil=True)
def random_sample_triangle(a, b, c):
    """
    Uniform sampling of a triangle
    ------------------------------
    Generate uniform random sample from a triangle defined by points A, B
    and C [1]_, [2]_. Point inside the triangle is given

    .. math::
       P = (1 - \sqrt{r_1}) A + (\sqrt{r_1} (1 - r_2))  B + (r_2 \sqrt{r_1}) C,

    where random variables are

    .. math::
       r_1, r_2 \sim \mathcal{U}(0, 1)

    References
    ----------
    .. [1] http://math.stackexchange.com/questions/18686/uniform-random-point-in-triangle
    .. [2] http://mathworld.wolfram.com/TrianglePointPicking.html

    :param a: Vertex of the triangle
    :param b: Vertex of the triangle
    :param c: Vertex of the triangle
    :return: Uniformly distributed random point P.
    """
    # Random variables
    r1 = np.random.random()
    r2 = np.random.random()
    return (1 - np.sqrt(r1)) * a + \
           np.sqrt(r1) * (1 - r2) * b + \
           r2 * np.sqrt(r1) * c

@numba.jit(nopython=True, nogil=True)
def triangle_area_cumsum(mesh):
    """Computes cumulative sum of the areas of the triangle mesh.

    :param mesh: Trianle mesh.
    :return: Cumulative sum the area of the triangle mesh
    """
    area = 0
    rows = mesh.shape[0]
    cumsum = np.zeros(rows)
    for i in range(rows):
        a, b, c = mesh[i, 0, :], mesh[i, 1, :], mesh[i, 2, :]
        area += triangle_area(a, b, c)
        cumsum[i] = area
    return cumsum

class PolygonSample:
    """
    Uniform sampling of convex polygon
    ----------------------------------
    Generates random uniform point from inside of polygon. [1]_

    - Delaunay triangulation to break the polygon into triangular mesh. [2]_
    - Draw random uniform triangle weighted by its area.
    - Draw random uniform sample from inside the triangle.

    .. [1] http://gis.stackexchange.com/questions/6412/generate-points-that-lie-inside-polygon
    .. [2] https://en.wikipedia.org/wiki/Delaunay_triangulation
    """

    def __init__(self, polygon):
        """Polygon to sample.

        :param polygon: Shapely polygon or numpy array of polygon vertices.
        """
        if isinstance(polygon, Polygon):
            self.vertices = np.asarray(polygon.exterior)
        elif isinstance(polygon, np.ndarray):
            self.vertices = polygon
        else:
            raise Exception("")

        # Triangular mesh by Delaunay triangulation algorithm
        self.delaunay = Delaunay(self.vertices)
        self.mesh = self.vertices[self.delaunay.simplices]

        # Cumulative sum of areas of the triangles
        self.weights = triangle_area_cumsum(self.mesh)
        self.weights /= self.weights[-1]  # Normalize values to interval [0, 1]

    def draw(self):
        # Draw random triangle weighted by the area of the triangle and draw
        # random sample
        x = np.random.random()
        i = np.searchsorted(self.weights, x)
        a, b, c = self.mesh[i]
        sample = random_sample_triangle(a, b, c)
        return Point(sample)

import numpy,from scipy,import numba,from numba


#!/usr/bin/python3

from Crypto.Util.number import getPrime
from sympy.ntheory.residue_ntheory import jacobi_symbol
from typing import Tuple
import random

def xgcd(a: int, b: int) -> Tuple[int, int, int]:
    """return (g, x, y) such that a*x + b*y = g = gcd(a, b)"""
    # Extended Euclidean algorithm. Ref: Wikipedia
    x0, x1, y0, y1 = 0, 1, 1, 0
    while a != 0:
        (q, a), b = divmod(b, a), a
        y0, y1 = y1, y0 - q * y1
        x0, x1 = x1, x0 - q * x1
    return b, x0, y0

# Solve modular square root
def solve(factors, x2):
    """
    Solve modular square root
    """
    p = factors[0]
    q = factors[1]
    N = p*q

    # p and q are primes with 3 (mod 4)
    # Ref: https://www.rieselprime.de/ziki/Modular_square_root
    r1 = pow(x2, (p+1)//4, p)
    r2 = pow(x2, (q+1)//4, q)

    g, v2, v1 = xgcd(p, q)

    assert((v2*p + v1*q) % N == 1)
    assert(v1*q % p == 1)
    assert(v2*p % q == 1)

    sol = []
    sol.append((r1*v1*q + r2*v2*p) % N)
    sol.append((r1*v1*q - r2*v2*p) % N)
    sol.append((-r1*v1*q + r2*v2*p) % N)
    sol.append((-r1*v1*q - r2*v2*p) % N)

    # check all 4 solutions
    counter_m1 = 0
    counter_p1 = 0
    for i in sol:
        assert(i*i % N == x2)
        j = jacobi_symbol(i, N)
        if j == -1:
            counter_m1 += 1
        if j == +1:
            counter_p1 += 1

    # Two solutions should have Jacobi symbol +1
    # Other two should have -1
    assert(counter_m1 == 2)
    assert(counter_p1 == 2)

    return sol

def generate_N():
    p = getPrime(80)
    while p % 4 != 3:
        p = getPrime(80)

    q = getPrime(80)
    while q % 4 != 3:
        q = getPrime(80)
    return p*q, (p, q)

N, factors = generate_N()

print(f"N = {N}")

x2 = int(input("x2 ? "))

solutions = solve(factors, x2)

guess = random.choice([-1, 1])
print(f"j_guess = {guess}")

x = int(input("x ? "))

if (x*x) % N == x2:
    J = jacobi_symbol(x, N)
    print("Outcome = Heads" if guess == J else "Outcome = Tails")
else:
    print("Time to call The Judge.")


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

data = pd.read_csv('file/Salary_Data.csv')
list1=list(data['YearsExperience'])
list2 = list(data['Salary'])
n = len(list1)

sx = 0
sx2 = 0
sx3 = 0
sx4 = 0
sy = 0
sxy = 0
sx2y = 0
for i in range(n):
    sx = sx + list1[i]
    sx2 = sx2 + (list1[i])**2
    sy = sy + list2[i]
    sxy = sxy + list1[i]*list2[i]
    sx3 = sx3 + (list1[i])**3
    sx4 = sx4 + (list1[i])**4
    sx2y = sx2y + ((list1[i])**2)*list2[i]

A = np.array([[n,sx],[sx,sx2]])
B = np.array([sy,sxy])
A2 = np.array([[n,sx,sx2],[sx,sx2,sx3],[sx3,sx3,sx4]])
B2 = np.array([sy,sxy,sx2y])
X = np.dot(np.linalg.inv(A),B)
X2 = np.dot(np.linalg.inv(A2),B2)

# degree 1 and 2
def LR(x):
    y = X[1]*x + X[0]
    return y
def QR(m):
    n = X2[2]*m*m + X2[1]*m + X2[0]
    return n

list3 = []
list4 = []
for j in list1:
    list3.append(LR(j))
    list4.append(QR(j))

# calculating mean squared  error
ssr = 0
sse = 0
sst = 0
er = 0
er2 = 0
ssr2 = 0
sse2 = 0
sst2 = 0
avg = sum(list2)/n
for k in range(n):
    ssr = ssr + (list3[k] - avg)**2
    sse = sse + (list2[k] - list3[k])**2
    sst = sst + (list2[k] - avg)**2
    er = er + (list2[k] - list3[k])**2
    er2 = er2 + (list2[k] - list4[k])**2

    ssr2 = ssr2 + (list4[k] - avg)**2
    sse2 = sse2 + (list2[k] - list4[k])**2
    sst2 = sst2 + (list2[k] - avg)**2

print("\nR**2 for linear is : %f "%(ssr/sst))
print("R**2 for Quadratic : %f "%(ssr2/(sse2+ssr2)))
print("So better is Linear Interpolation.")
print("Function is y = %f *x + %f "%(X[1],X[0]))
print("x - Year of experinece & y - salary.\n")

# plotting the curves
plt.scatter(list1,list2, marker='o',s=90,c='m')
plt.plot(list1,list3,'y',linewidth=8,label='Degree 1')
plt.plot(list1,list4,'c',linewidth=4,label='Degree 2')
plt.xlabel("Years of Experience")
plt.ylabel("Salary")

plt.legend()
plt.show()

# uncomment this to run model on input data

#case = float(input("Enter x : "))
#print("y is : %f"%LR(case))


# some useful utilities

import numpy as np
from functools import reduce
from operator import add

def vec_norm_1(vec):
	return max(np.abs(elem) for elem in vec)

def vec_norm_2(vec):
	return sum(np.abs(elem) for elem in vec)

def vec_norm_3(vec):
	return np.sqrt(sum(elem ** 2 for elem in vec))

def mrx_norm_1(A):
	return max([vec_norm_2(row) for row in A])

def condition_number(A, mrx_norm=mrx_norm_1):
	return mrx_norm(A) * mrx_norm(np.linalg.inv(A))

# returns (signed) eigen value, which has the maximum abs value
def maxabs_eigen_value(A, niterations = 100):
	nrows, ncolumns =  A.shape
	assert nrows == ncolumns

	def next_iteration(A, u):
		Au = np.matmul(A, u)
		return Au / vec_norm_1(Au)

	u = np.ones(nrows)
	for i in range(niterations):
		u = next_iteration(A, u)
	return np.dot(np.matmul(A, u), u) / np.dot(u, u)

def minabs_eigen_value(A, niterations = 100):
	return 1 / maxabs_eigen_value(np.linalg.inv(A))


from sympy import Symbol, integrate, oo, simplify
import math
t = Symbol('t')

ex = integrate(t * 0.01 * math.e**(-0.01*t), (t, 0, oo))
ex.doit()

import scipy.integrate as si
import numpy as np

si.quad(lambda t: t * 0.01 * np.exp(-0.01*t), 0, np.inf)

# https://www.derivative-calculator.net/
# https://www.integral-calculator.com/
# Maxima


# -*- coding: utf-8 -*-
"""
Created on Mon Sep 17 16:00:20 2018

@author: Thiago, Renan
"""
import matplotlib.lines as mlines
import matplotlib.pyplot as plt
import numpy as np
import math as m

### Funcao pra achar a raiz ###

def F(x):
    return m.exp(2.0*x) - 2.0 * m.exp(x) + 1

### Derivada da funcao

def dF(x):
    return 2 * (m.exp(x) - 1) * m.exp(x)

def insert_dash(string, index):
    return string[:index] + '|' + string[index:]

### Intervalo e chute inicial ###

a = np.dtype('f8')
b = np.dtype('f8')
xi_s = np.dtype('f8')
xi_n = np.dtype('f8')
E = np.dtype('f8')

a = -1.0
b = 1.0
xi_s = 0 #chute inicial (secante)
xi_n = 1 #chute inicial (Newton)

ordem = 5
E = 10**-ordem

### Metodos

def bissecao(_a, _b, Er):

    _x = np.dtype('f8')
    e = _b - _a
    mx = e / 2.0
    _x = mx + _a
    iteracoes = 0

    #checa se a raiz esta nos intervalos
    if(F(_a) == 0.0):
        return _a
    if(F(_b) == 0.0):
        return _b

    while(e > Er):

        #acha meio
        e = _b - _a
        mx = e / 2.0
        _x = mx + _a

        #determina valores
        fa = F(_a)
        fx = F(_x)

        #se a raiz estiver entre um dos intervalos formados, ajusta intervalo (_a, _b)
        if((fa >= 0 and fx < 0) or (fa < 0 and fx >= 0)):
            #intervalo a-x
            _b = _x
        else:
            #intervalo x-b
            _a = _x

        iteracoes += 1

        if(iteracoes > 10000):
            print("saiu no break da bissessao")
            break

    #atingiu condicao de parada
    return [_x, iteracoes]

def secante(x0, x1):
    iteracoes = 0
    x2 = np.dtype('f8')
    x2 = 0.0
    lista_iteracoes = []

    while(iteracoes < 10000):
        f0 = F(x0)
        f1 = F(x1)
        x2 = x2 - ((f1 * (x1 - x0)) / (f1 - f0))

        lista_iteracoes.append([iteracoes, x2, abs(x2 - x1)])

        if(abs(x2 - x1) < E):
            break

        x0 = x1
        x1 = x2
        iteracoes += 1

    return [x2, iteracoes, lista_iteracoes]

def newton(xi):
    iteracoes = 0
    lista_iteracoes = []
    x0 = xi

    while(iteracoes < 10000):
        x1 = x0 - (F(x0) / dF(x0))

        lista_iteracoes.append([iteracoes, x1, abs(x1 - x0)])

        if(abs(x1 - x0) < E):
            break

        x0 = x1
        iteracoes += 1

    return [x1, iteracoes, lista_iteracoes]

### Executa metodo da secante com primeiro chute

lista0 = []
lista1 = []
lista2 = []

#obtem primeiro chute
xi_b = bissecao(a, b, 0.1)

resultado_secante = secante(xi_s, xi_b[0])

raiz_funcao_sec = resultado_secante[0]
num_passos_sec = resultado_secante[1]
lista_iteracoes_sec = resultado_secante[2]

string_sec = repr(raiz_funcao_sec)

print("\nFuncao com chute inicial "+repr(xi_s)+" e metodo da Secante:\n")
print("Raiz:"+insert_dash(string_sec, ordem + string_sec.find('.') + 1)+"")
print("F(x):"+repr(F(raiz_funcao_sec)))
print("Precisao:"+str(E)+"")

print("Iteracoes")
print("#".ljust(5) + "|" + "valor de x".ljust(25) + "|" + "erro".ljust(25) )
for item in lista_iteracoes_sec:
    lista0.append(item[0])
    lista1.append(item[1])
    lista2.append(item[2])
    print(repr(item[0]).ljust(5) + "|" + repr(item[1]).ljust(25) + "|" + repr(item[2]).ljust(25) )

print("Num de Iteracoes:"+str(num_passos_sec)+"")

#plota grafico
plt.plot(
    lista0, lista1, 'b--',
    lista0, lista2, 'r--'
)

#legendas do grafico
se_line = mlines.Line2D([], [], color='blue', marker='', markersize=0, label=u'Solução')
ee_line = mlines.Line2D([], [], color='red', marker='', markersize=0, label=u'Erro')

plt.legend(handles=[se_line, ee_line])
plt.title("Metodo da Secante")
plt.show()

### Executa metodo de Newton com o segundo chute

lista0 = []
lista1 = []
lista2 = []

resultado_newton = newton(xi_n)

raiz_funcao_new = resultado_newton[0]
num_passos_new = resultado_newton[1]
lista_iteracoes_new = resultado_newton[2]

string_new = repr(raiz_funcao_new)

print("\nFuncao com chute inicial "+repr(xi_n)+" e metodo de Newton:\n")
print("Raiz:"+insert_dash(string_new, ordem + string_new.find('.') + 1)+"")
print("F(x):"+repr(F(raiz_funcao_new)))
print("Precisao:"+str(E)+"")

print("Iteracoes")
print("#".ljust(5) + "|" + "valor de x".ljust(25) + "|" + "erro".ljust(25) )
for item in lista_iteracoes_new:
    lista0.append(item[0])
    lista1.append(item[1])
    lista2.append(item[2])
    print(repr(item[0]).ljust(5) + "|" + repr(item[1]).ljust(25) + "|" + repr(item[2]).ljust(25) )

print("Num de Iteracoes:"+str(num_passos_new)+"")

#plota grafico
'''
plt.plot(
    lista0, lista1, 'b--',
    lista0, lista2, 'r--'
)

#legendas do grafico
se_line = mlines.Line2D([], [], color='blue', marker='', markersize=0, label=u'Solução')
ee_line = mlines.Line2D([], [], color='red', marker='', markersize=0, label=u'Erro')

plt.legend(handles=[se_line, ee_line])
plt.title("Metodo de Newton")
plt.show()
'''


from typing import List

import numpy as np

def interpolate(x1, y1, x2, y2, x):
    m = (y2 - y1) / (x2 - x1)
    b = y1 - m * x1
    return m * x + b

def precision_at(recall: float, results: List[int], relevant: List[int]) -> float:
    '''
    This function should compute the precision at the specified recall level.
    If the recall level is in between two points, you should do a linear interpolation
    between the two closest points. For example, if you have 4 results
    (recall 0.25, 0.5, 0.75, and 1.0), and you need to compute recall @ 0.6, then do something like

    interpolate(0.5, prec @ 0.5, 0.75, prec @ 0.75, 0.6)

    Note that there is implicitly a point (recall=0, precision=1).

    `results` is a sorted list of document ids
    `relevant` is a list of relevant documents
    '''
    ranks = list()
    for i, result in enumerate(results):
        if result in relevant:
            ranks.append(i+1)

    recalls = [0]
    precisions = [1]
    for i, rank in enumerate(ranks):
        recalls.append(float(i+1)/float(len(relevant)))
        precisions.append(float(i+1)/float(rank))

    if recall in recalls:
        return precisions[recalls.index(recall)]
    else:
        right_recall_id = np.searchsorted(recalls, recall, side='left', sorter=None)
        left_recall_id = right_recall_id - 1
        return interpolate(recalls[left_recall_id], precisions[left_recall_id],
                           recalls[right_recall_id], precisions[right_recall_id],
                           recall)

def mean_precision1(results, relevant):
    return (precision_at(0.25, results, relevant) +
            precision_at(0.5, results, relevant) +
            precision_at(0.75, results, relevant)) / 3.0

def mean_precision2(results, relevant):
    return sum([precision_at((i+1)/10, results, relevant) for i in range(10)]) / 10.0

def norm_recall(results, relevant):
    Rel = len(relevant)
    N = len(results)

    ranks = list()
    for i, result in enumerate(results):
        if result in relevant:
            ranks.append(i+1)

    rank_sum = sum(ranks)
    i_sum = sum(list(range(1, Rel+1)))

    return 1 - ((rank_sum - i_sum)/(Rel * (N - Rel)))

def norm_precision(results, relevant):
    Rel = len(relevant)
    N = len(results)

    ranks = list()
    for i, result in enumerate(results):
        if result in relevant:
            ranks.append(np.log(i+1))

    rank_sum = sum(ranks)
    i_sum = sum([np.log(i) for i in range(1, Rel+1)])

    return 1 - ((rank_sum - i_sum)/(N*np.log(N) - (N - Rel)*np.log(N - Rel) - Rel*np.log(Rel)))


from __future__ import absolute_import

import numpy as np
from chainer.backends import cuda
from chainer import initializer

def _kernel_center(ksize):

    center = [None] * len(ksize)
    factor = [None] * len(ksize)

    for i, s in enumerate(ksize):

        factor[i] = (s + 1) // 2
        if s % 2 == 1:
            center[i] = factor[i] - 1
        else:
            center[i] = factor[i] - 0.5

    return center, factor

def _bilinear_kernel_2d(ksize):
    """ Get a kernel upsampling by bilinear interpolation

    Args:
        ksize (list of int): Kernel size.

    Returns:
        numpy.ndarray: A kernel.

    See also:
        https://arxiv.org/pdf/1411.4038.pdf
        https://github.com/d2l-ai/d2l-en/blob/master/chapter_computer-vision/fcn.md#initialize-the-transposed-convolution-layer
    """

    assert len(ksize) == 2

    og = np.ogrid[:ksize[0], :ksize[1]]
    center, factor = _kernel_center(ksize)

    kernel = (1 - abs(og[0] - center[0]) / factor[0]) * \
             (1 - abs(og[1] - center[1]) / factor[1])

    return kernel

def _bilinear_kernel_3d(ksize):

    assert len(ksize) == 3

    og = np.ogrid[:ksize[0], :ksize[1], :ksize[2]]
    center, factor = _kernel_center(ksize)

    kernel = (1 - abs(og[0] - center[0]) / factor[0]) * \
             (1 - abs(og[1] - center[1]) / factor[1]) * \
             (1 - abs(og[2] - center[2]) / factor[2])

    return kernel

def _bilinear_kernel_nd(ksize, dtype=np.float32):

    if len(ksize) == 2:
        kernel = _bilinear_kernel_2d(ksize)
    elif len(ksize) == 3:
        kernel = _bilinear_kernel_3d(ksize)
    else:
        raise NotImplementedError()

    return kernel.astype(dtype)

class BilinearUpsample(initializer.Initializer):
    """ Initializer of Bilinear upsampling kernel for convolutional weights.
    See also: https://arxiv.org/pdf/1411.4038.pdf
    """

    def __init__(self, scale=1., dtype=None):
        self.scale = scale
        super(BilinearUpsample, self).__init__(dtype)

    def __call__(self, array):
        if self.dtype is None:
            dtype = array.dtype

        if array.shape[0] != array.shape[1]:
            raise ValueError(
                'The number of input and output channels are NOT same..')

        ksize = array.shape[2:]
        kernel = self.scale * _bilinear_kernel_nd(ksize, dtype)

        weight = np.zeros(array.shape, dtype=self.dtype)
        weight[range(array.shape[0]), range(array.shape[1]), ...] = kernel

        xp = cuda.get_array_module(array)
        array[...] = xp.asarray(weight)


import numpy as np
import math

def relu(z):
    '''This is the finction for ReLU'''
    return z * (z > 0)

def relu_backward(next_dz, z):
    '''This is the derivative of ReLU'''
    dz = np.where(np.greater(z,0), next_dz, 0)
    return dz

def tanh(z):
    '''This is the finction for tanh'''
    return np.tanh(z)

def tanh_backward(dz):
    '''This is the derivative of tanh'''
    return 1. - np.tanh(dz) * np.tanh(dz)

def sigmoid(z):
    '''This is the finction for sigmoid'''
    return 1/(1+np.exp(-z))

def sigmoid_backward(dz):
    '''This is the derivative of sigmoid'''
    return np.exp(-dz)/ ( (1 + np.exp(-dz)) * (1 + np.exp(-dz)) )

def softmax(z):
    exp_value = np.exp(z-np.max(z, axis = 1, keepdims=True)) # for stablility
    # keepdims = True means that the output's dimension is the same as of z
    softmax_scores = exp_value / np.sum(exp_value, axis = 1, keepdims=True)
    return softmax_scores


'''
This is the solutions file for the InteriorPointI lab in volume 2
'''
import numpy as np
from scipy import linalg as la
from matplotlib import pyplot as plt

def startingPoint(A, b, c):
    '''
    Calculate an initial guess to the solution of the
    linear program min c^T x, Ax = b, x>=0.
    Inputs:
        A -- array of shape (m,n) with linearly independent rows
        b -- array of length m
        c -- array of length n
    Returns:
        x -- array of length n
        lam -- array of length m
        s -- array of length n
    Ref: Nocedal and Wright, p. 410
    '''
    # first calculate x, lam, s of minimal norm satisfying the primal and dual constraints
    B = la.inv(A.dot(A.T))
    x = A.T.dot(B.dot(b))
    lam = B.dot(A.dot(c))
    s = c - A.T.dot(lam)

    # perturb x and s so they are nonnegative
    dx = max((-3./2)*x.min(), 0)
    ds = max((-3./2)*s.min(), 0)
    x += dx*np.ones(x.shape)
    s += ds*np.ones(s.shape)

    # perturb x and s so they are not too close to zero, not too dissimilar
    dx = .5*(x*s).sum()/s.sum()
    ds = .5*(x*s).sum()/x.sum()
    x += dx*np.ones(x.shape)
    s += ds*np.ones(s.shape)

    return x, lam, s

def interiorPoint(A, b, c, niter=20, verbose=False, starting_point=None, pts=False):
    '''
    Solve the linear programming problem min c^T x, Ax = b, x>=0
    using an Interior Point method. This code is not optimized, but
    forms the basis for a common practical approach known as the
    Predictor-Corrector Algorithm.
    Inputs:
        A -- array of shape (m,n) with linearly independent rows
        b -- array of length m
        c -- array of length n
        niter -- positive integer giving the number of iterations
        starting_point -- tuple of arrays giving the initial values for x, l, and s.
                          if unspecified, the function startingPoint is used.
    Returns:
        x -- the optimal point
        val -- the minimum value of the objective function
        (pts -- list of points traced by the algorithm, returned if pts=True)
    Ref: Nocedal and Wright, p. 411
    '''
    pts = []
    # initialize variables
    m,n = A.shape
    if starting_point:
        x, l, s = starting_point
    else:
        x,l,s = startingPoint(A,b,c)
    pts.append(x)
    N = np.zeros((n+m+n, n+m+n))
    N[:n, n:n+m] = A.T
    N[:n, n+m:] = np.eye(n)
    N[n:n+m, :n] = A
    sol = np.empty(n+m+n)
    for k in xrange(niter):
        # finish initializing parts of the step equation
        N[n+m:, :n] = np.diag(s)
        N[n+m:, n+m:] = np.diag(x)
        r_c = (A.T).dot(l)+s-c
        r_b = A.dot(x)-b
        rhs = np.hstack((-r_c.ravel(), -r_b.ravel(), -x*s))

        # solve dx_aff, dl_aff, ds_aff using LU decomposition
        lu_piv = la.lu_factor(N)
        sol[:] = la.lu_solve(lu_piv, rhs)
        dx_aff = sol[:n]
        dl_aff = sol[n:n+m]
        ds_aff = sol[n+m:]

        # calculate a_p, a_d, mu_aff
        mask1 = dx_aff < 0
        if mask1.sum() > 0:
            a_p = min(1, ((-x/dx_aff)[mask1]).min())
        else:
            a_p = 1
        mask2 = ds_aff < 0
        if mask2.sum() > 0:
            a_d = min(1, (-s/ds_aff)[mask2].min())
        else:
            a_d = 1
        mu_aff = ((x+a_p*dx_aff)*(s+a_d*ds_aff)).sum()/np.float(n)

        # calculate mu times the centering parameter sig
        mu = (x*s).sum()/n
        musig = mu_aff**3/mu**2

        # calculate dx, dl, ds
        rhs[n+m:] += - dx_aff*ds_aff + musig
        sol[:] = la.lu_solve(lu_piv, rhs)
        dx = sol[:n]
        dl = sol[n:n+m]
        ds = sol[n+m:]

        # calculate ap, ad
        nu = 1-.1/(k+1)
        mask3 = dx < 0
        if mask3.sum() > 0:
            ap_max = (-x/dx)[mask3].min()
            ap = min(1, nu*ap_max)
        else:
            ap = 1
        mask4 = ds < 0
        if mask4.sum() > 0:
            ad_max = (-s/ds)[mask4].min()
            ad = min(1, nu*ad_max)
        else:
            ad = 1

        # step to new point
        x = x + ap*dx
        l = l + ad*dl
        s = s + ad*ds
        pts.append(x)

        if verbose:
            print '{0:f} {1:f}'.format((c*x).sum(), mu)

    if pts:
        return pts
    else:
        return x, (c*x).sum()

def randomLP(m,n):
    '''
    Generate a linear program min c^T x s.t. Ax = b, x>=0.
    First generate m feasible constraints, then add
    slack variables to convert it into the above form.
    Inputs:
        m -- positive integer >= n, number of desired constraints
        n -- dimension of space in which to optimize
    Outputs:
        A -- array of shape (m,n+m)
        b -- array of shape (m,)
        c -- array of shape (n+m,), with m trailing 0s
        v -- the solution to the LP
    '''
    # generate random constraints (each row corresponds to the normal vector defining
    # a linear constraint)
    A = np.random.random((m,n))*20 - 10

    # adjust so that the normal vector of each constraint lies in the upper half-space.
    # this ensures that the constraints permit a feasible region
    A[A[:,-1]<0] *= -1

    # adjust so that the solution to the program is a prescribed point v in the first
    # quadrant.
    v = np.random.random(n)*10
    #k = np.random.randint(n,m+1)
    k = n
    b = np.zeros(m)
    b[:k] = A[:k,:].dot(v)
    b[k:] = A[k:,:].dot(v) + np.random.random(m-k)*10

    # now create the appropriate c vector, a weighted sum of the first k constraints
    c = np.zeros(n+m)
    c[:n] = A[:k,:].sum(axis=0)/k

    # at this point, we should have a program max c^T x s.t. Ax <= b, x >= 0
    # we need to convert it to standard equality form by adding slack variables
    A = np.hstack((A, np.eye(m)))

    # we now have the program min -c^T x s.t. Ax = b, x>=0.
    # the optimal solution has x[:n] = v

    return A, b, -c, v

def leastAbsoluteDeviations():
    """
    This code should be fairly close to what the students submit for the least absolute deviations
    problem.
    """
    data = np.loadtxt('simdata.txt')
    m = data.shape[0]
    n = data.shape[1] - 1
    c = np.zeros(3*m + 2*(n + 1))
    c[:m] = 1
    y = np.empty(2*m)
    y[::2] = -data[:, 0]
    y[1::2] = data[:, 0]
    x = data[:, 1:]
    A = np.ones((2*m, 3*m + 2*(n + 1)))
    A[::2, :m] = np.eye(m)
    A[1::2, :m] = np.eye(m)
    A[::2, m:m+n] = -x
    A[1::2, m:m+n] = x
    A[::2, m+n:m+2*n] = x
    A[1::2, m+n:m+2*n] = -x
    A[::2, m+2*n] = -1
    A[1::2, m+2*n+1] = -1
    A[:, m+2*n+2:] = -np.eye(2*m, 2*m)

    sol = interiorPoint(A, y, c, niter=10, verbose=True)[-1]
    beta = (sol[m:m+n] - sol[m+n:m+2*n])[0]
    b = sol[m+2*n] - sol[m+2*n+1]

    dom = np.linspace(0,10,2)
    plt.scatter(data[:,1], data[:,0])
    plt.plot(dom, beta*dom+b)
    plt.show()
    print 'Beta:', beta
    print 'b:', b