import numpy as np
import scipy.linalg as la
from scipy.stats import bernoulli

def acceptance(x, y, mu, sigma):
    p = min(1, np.exp(-0.5 * (np.dot(x - mu, la.solve(
        sigma, x - mu)) - np.dot(y - mu, la.solve(sigma, y - mu)))))
    return bernoulli.rvs(p)

def nextState(x, mu, sigma):
    K = len(x)
    y = np.random.multivariate_normal(x, np.eye(K))
    accept = acceptance(y, x, mu, sigma)
    if accept:
        return y
    else:
        return x

def lmvnorm(x, mu, sigma):
    return -0.5 * (np.dot(x - mu, la.solve(sigma, x - mu)) - len(x) * np.log(2 * np.pi) - np.log(la.det(sigma)))

def metropolis(x, mu, sigma, n_samples=1000):
    logprobs = np.zeros(n_samples)
    x_samples = np.zeros((n_samples, len(x)))
    for i in xrange(n_samples):
        logprobs[i] = lmvnorm(x, mu, sigma)
        x = nextState(x, mu, sigma)
        x_samples[i, :] = x.copy()
    return x_samples, logprobs


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sat Apr 27 18:57:47 2019

@author: khaledghobashy
"""

# Third party imports.
import numpy as np

def skew_matrix(v):
    x, y, z = v.flatten()
    vs = np.array([[0, -z, y], [z, 0, -x], [-y, x, 0]])
    return vs

def orthogonal_vector(v):
    dummy = np.ones((3,1))
    i = np.argmax(np.abs(v))
    dummy[i] = 0
    m = np.linalg.multi_dot([skew_matrix(v), dummy])
    return m

def triad(v1, v2=None):
    k = v1/np.linalg.norm(v1)
    if v2 is not None:
        i = v2/np.linalg.norm(v2)
    else:
        i = orthogonal_vector(k)
        i = i/np.linalg.norm(i)
    j = np.linalg.multi_dot([skew_matrix(k), i])
    j = j/np.linalg.norm(j)
    m = np.concatenate([i, j, k], axis=1)
    return m

def mirrored(v):
    if v.shape != (3, 1):
        return v
    else:
        m = np.array([[1, 0, 0],
                      [0,-1, 0],
                      [0, 0, 1]], dtype=np.float64)
        return m.dot(v)

def centered(*args):
    p = np.sum(args, 0)
    p = p/len(args)
    return p

def oriented(*args):
    if len(args) == 2:
        v = args[1] - args[0]
    elif len(args) == 3:
        a1 = args[1] - args[0]
        a2 = args[2] - args[0]
        v = np.cross(a2, a1, axisa=0, axisb=0)
        v = np.reshape(v, (3, 1))
    v = v/np.linalg.norm(v)
    return v


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

#-------------------------------------- DATA PREPROCESSING ---------------------------------#

# Imports
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import math

from matplotlib.animation import FuncAnimation

# Reading the dataset from data
dataset = pd.read_csv(r'..\\data\\auto_insurance.csv')

# Creating Dependent and Independent variables
X = dataset['X'].values
y = dataset['Y'].values

# Visualizing the data
title='Linear Regression on <Dataset>'
x_axis_label = 'X-value < The corresponding attribute of X in dataset >'
y_axis_label = 'y-value < The corresponding attribute of X in dataset >'
title='Linear Regression on Auto Insurance Sweden Dataset'
x_axis_label = "Total Payment"
y_axis_label = "Number of Claims"

plt.scatter(X,y)
plt.title(title)
plt.xlabel(x_axis_label)
plt.ylabel(y_axis_label)
plt.show()

# Splitting the data into training set and test set
X_train,X_test = np.split(X,indices_or_sections = [int(len(X)*0.8)])
y_train,y_test = np.split(y,indices_or_sections = [int(len(X)*0.8)])

#------------------------------------ DATA PREPROCESSING ENDS -----------------------------#

#--------------------------------------- TRAINING   ---------------------------------------#

# Functions for caluculation of gradient descent

# Function to caluculate mean square error
def mean_square_error(slope,intercept,x_data,y_data):
    n = len(x_data)
    sum_of_squares = 0
    for i in range(n):
        y_pred = x_data[i]*slope+intercept
        y_actual = y_data[i]
        sum_of_squares += (y_actual - y_pred)**2

    mean_square_error = math.sqrt(sum_of_squares/n)
    return mean_square_error

# Function to caluculate Gardient of slope at each intermidiatory iteration
def gradient_slope(slope,intercept,x_data,y_data):
    n = len(x_data)
    sum_of_gradients = 0
    for i in range(n):
        y_pred = x_data[i]*slope + intercept
        y_actual = y_data[i]
        sum_of_gradients += x_data[i]*(y_actual-y_pred)
    sum_of_gradients = -1*sum_of_gradients
    gradient_slope = sum_of_gradients*(2/n)
    return gradient_slope

# Function to caluculate Gardient of intercept at each intermidiatory iteration
def gradient_intercept(slope,intercept,x_data,y_data):
    n = len(x_data)
    sum_of_gradients = 0
    for i in range(n):
        y_pred = x_data[i]*slope +intercept
        y_actual = y_data[i]
        sum_of_gradients += -1 *(y_actual-y_pred)
    sum_of_gradients = -1*sum_of_gradients
    gradient_intercept = sum_of_gradients*(2/n)
    return gradient_intercept

# Gradient Decent function
slope_history = []
intercept_history = []
loss_history = []
def gradient_decent(x_data,y_data,epochs,learning_rate,initial_slope,initial_intercept):
    slope = initial_slope
    intercept = initial_intercept
    for epoch in range(epochs):
        slope  = slope - learning_rate*(gradient_slope(slope,intercept,x_data,y_data))
        intercept = intercept - learning_rate*(gradient_intercept(slope,intercept,x_data,y_data))
        loss = mean_square_error(slope,intercept,x_data,y_data)
        print("The loss obtained is %0.2f "%(loss))
        loss_history.append(loss)
        slope_history.append(slope)
        intercept_history.append(intercept)
    return (slope,intercept)

# Training
# Hyperparameters
epochs = 500
learning_rate = 0.00001
initial_slope = 0
initial_intercept = 0

(slope,intercept) = gradient_decent(X_train,y_train,epochs = epochs,learning_rate=learning_rate,initial_slope = initial_slope,initial_intercept =initial_intercept)

# The plot to inspect the decrease in loss
plt.title("Loss Function")
plt.plot(loss_history)
plt.show()

print('gif is created')

# The plot to inspect the variation in slope and intercept
plt.plot(slope_history)
plt.plot(intercept_history)
plt.show()

#-------------------------------------- TRAINING ENDS  ------------------------------------#

#------------------------------- PREDICTION AND PLOTING -----------------------------------#

m = slope
c = intercept

# Predicting the Results
y_pred = X_test*m + c

# Visualizing the Results
plt.scatter(X_test,y_test,c='red')
plt.plot(X_test,y_pred)

plt.title(title)
plt.xlabel(x_axis_label)
plt.ylabel(y_axis_label)
plt.show()

# Animation of Gradient Descent

fig, ax = plt.subplots()
xdata, ydata = [], []
ln, = ax.plot([], [], 'b', animated=True)
sc = plt.scatter(X_test,y_test,c='red',animated=True)

def init():
    ax.set_title(title)
    plt.xlabel(x_axis_label)
    plt.ylabel(y_axis_label)
    ax.set_xlim(min(X_test)-10, max(X_test)+10)
    ax.set_ylim(min(y_test)-10, max(y_test)+10)
    return ln,

def update(frame):
    i = frame
    m = slope_history[i]
    c = intercept_history[i]
    y_pred = X_test*m + c
    loss = mean_square_error(m,c,X_test,y_pred)
    ax.text(2,3,loss)
    ln.set_data(X_test, y_pred)

anim = FuncAnimation(fig, update, frames=range(len(slope_history)),init_func=init)
anim.save('gradient_descent.gif', fps=30)
plt.show()

#------------------------------ PREDICTION AND PLOTING ENDS--------------------------------#


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

from sympy.core import Symbol
from sympy import lambdify

from numpy import linspace, pi
from matplotlib import pyplot as plt

from .glt import Stiffness

def plot_stiffness_symbols(degrees=[2, 3], nx=100):
    """
    Plots the stiffness symbol for different degrees on a given number of elements.

    degrees: list, tuple
        a list/tuple of spline degrees

    nx: int
        number of points used for plot
    """

    colors = ["r", "b", "g", "y", "m", "k", "c"]

    for i,p in enumerate(degrees):

        t = Symbol('t')

        symbol = Stiffness(p, t)

        # ... make the symbol a numeric function, that can be evaluated
        f = lambdify(t, symbol, "numpy")

        t1 = linspace(-pi,pi, nx)
        w = f(t1)
        # ...

        plt.plot(t1, w.real, "-"+colors[i], label="$p=" + str(p) + "$")

    plt.xlabel('fequencies')
    plt.ylabel('$\mathfrak{s}_p$')
    plt.legend(loc=9)


import numpy as np

from Losses import Loss

class MeanSquaredError(Loss):
    def call(self, true_labels, predicted_labels):
        return np.mean(np.power((predicted_labels - true_labels), 2))

    def __call__(self, true_labels, predicted_labels):
        return self.call(true_labels, predicted_labels)


import math
import numpy as np

# ---- convention for accessing all 4 pi sr by just two angles, theta and phi ----

def gamma_convention():
    return 0

def beta_convention(theta):
    return -np.pi/2 + theta  # theta \in [0, pi]

def alpha_convention(phi):
    return phi  # phi \in [0, 2*pi]
# ----

def get_zxz_rot(alpha, beta, gamma):
    """
    calculate active rotation R_z(gamma) R_x(beta) R_z(alpha)
    think like this: the application is in the reverse order,
    and the order of arguments is the order of application,
    so, again reversed!
    and the index namings can also be flipped around without change
    """
    return np.einsum("ij,jk",
                     np.einsum("ij,jk", get_R_z(alpha), get_R_x(beta)),
                     get_R_z(gamma))

    # return np.dot(get_R_x(beta), get_R_z(alpha))

    # return np.dot(get_R_z(gamma), np.dot(get_R_x(beta), get_R_z(alpha)))  # this produces the wrong result
    # import ipdb; ipdb.set_trace()  # noqa BREAKPOINT
    # return np.einsum("ij,jk,kl", get_R_z(alpha), get_R_x(beta), get_R_z(gamma))

def get_R_x(angle):
    return np.array([[1, 0, 0],
                     [0, math.cos(angle), -math.sin(angle)],
                     [0, math.sin(angle), math.cos(angle)]])

def get_R_y(angle):
    return np.array([[math.cos(angle), 0, math.sin(angle)],
                     [0, 1, 0],
                     [-math.sin(angle), 0, math.cos(angle)]])

def get_R_z(angle):
    # import ipdb; ipdb.set_trace()  # noqa BREAKPOINT
    return np.array([[math.cos(angle), -math.sin(angle), 0],
                     [math.sin(angle), math.cos(angle), 0],
                     [0, 0, 1]])


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

### Hyperparameters ###

LEARNING_RATE = 50.0
OPTIMIZER_CONSTRUCTOR = tf.train.AdagradOptimizer
NUM_ITERS = 20000

# Load the data, and convert to 1x30 vectors
D = pd.read_csv("homicide.csv")
x_data = np.matrix(D.age.values)
y_data = np.matrix(D.num_homicide_deaths.values)

### Model definition ###

# Define x (input data) placeholder
x = tf.placeholder(tf.float32, shape=(1, None))

# Define the trainable variables
a = tf.get_variable("a", shape=())
b = tf.get_variable("b", shape=())

# Define the prediction model
y_predicted = a*x + b

### Loss function definition ###

# Define y (correct data) placeholder
y = tf.placeholder(tf.float32, shape=(1, None))

# Define the loss function
L = tf.reduce_sum((y_predicted - y)**2)

### Summary setup ###

log_name = "%g, %s" % (LEARNING_RATE, OPTIMIZER_CONSTRUCTOR.__name__)
tf.summary.scalar('a', a)
tf.summary.scalar('b', b)
tf.summary.scalar('L', L)
summary_node = tf.summary.merge_all()
summary_writer = tf.summary.FileWriter('/tmp/tensorflow/single_var_reg/' + log_name)
print("Open /tmp/tensorflow/single_var_reg/ with tensorboard")

### Training the model ###

# Define optimizer object
optimizer = OPTIMIZER_CONSTRUCTOR(learning_rate=LEARNING_RATE).minimize(L)

# Create a session and initialize variables
session = tf.Session()
session.run(tf.global_variables_initializer())

# Main optimization loop
for t in range(NUM_ITERS):
    _, summary = session.run([optimizer, summary_node], feed_dict={
        x: x_data,
        y: y_data
    })
    summary_writer.add_summary(summary, t)
    # print("t = %g, loss = %g, a = %g, b = %g" % (t, current_loss, current_a, current_b))


import numpy as np
from nn_utils import read_dataset

size = 1000

def sigmoid(x, deriv=False):
    if (deriv == True):
        return x * (1 - x)
    return 1 / (1 + np.exp(-x))

X, y = read_dataset(180, 1000)

np.random.seed(5)
# synapses
w0 = 2 * np.random.random((X.size / X.__len__(), X.__len__())) - 1
w1 = 2 * np.random.random((X.__len__(), X.__len__())) - 1
w2 = 2 * np.random.random((X.__len__(), 1)) - 1

# training step
for j in xrange(60000):

    # Calculate forward through the network.
    l0 = X
    l1 = sigmoid(np.dot(l0, w0))
    l2 = sigmoid(np.dot(l1, w1))
    l3 = sigmoid(np.dot(l2, w2))

    # Error back propagation of errors using the chain rule.
    l3_error = y - l3
    if (j % 10) == 0:
        print("Error: " + str(np.mean(np.abs(l3_error))))

    l3_adjustment = l3_error * sigmoid(l3, deriv=True)  # (y-a).d/dw(-a), a = sigmoid(Sum Xi*Wi)
    l2_error = l3_adjustment.dot(w2.T)

    l2_adjustment = l2_error * sigmoid(l2, deriv=True)  # (y-a).d/dw(-a), a = sigmoid(Sum Xi*Wi)
    l1_error = l2_adjustment.dot(w1.T)

    l1_adjustment = l1_error * sigmoid(l1, deriv=True)  # (y-a).d/dw(-a), a = sigmoid(Sum Xi*Wi)

    # update weights for all the synapses (no learning rate term)
    w2 += l2.T.dot(l3_adjustment)
    w1 += l1.T.dot(l2_adjustment)
    w0 += l0.T.dot(l1_adjustment)

print("Output after training")
print(l3)

def predict(X1):
    l0 = np.zeros((X.__len__(), X.size / X.__len__()))
    max = np.matrix(X1).max()
    l0[0] = 2 * np.asanyarray(X1, dtype=np.float32) / max - 1
    l1 = sigmoid(np.dot(l0, w0))
    l2 = sigmoid(np.dot(l1, w1))
    l3 = sigmoid(np.dot(l2, w2))
    return l3[0][0]  # since process X1[0] output would be l2[0]

test_dataset = [1, 9, 19, 33, 16, 2, 1]
result = predict(test_dataset)
print("expected output 1, predicted output " + repr(result))
assert (result > 0.95), "Test Failed. Exepected result > 0.95"

test_dataset = [1, 0, 1, 4, 1, 3, 1]
result = predict(test_dataset)
print("expected output 0, predicted output " + repr(result))
assert (result < 0.95), "Test Failed. Exepected result < 0.95"


# Perform linear regression and print performance.
# Correlation between the number of rooms and the price of the house.
#
# Ref. https://medium.com/@amitg0161/sklearn-linear-regression-tutorial-with-boston-house-dataset-cde74afd460a

import numpy as np
import pandas as pd
from sklearn.datasets import load_boston

boston_housing = load_boston()
boston_df = pd.DataFrame(boston_housing.data, columns=boston_housing.feature_names)
boston_df['PRICE'] = boston_housing.target

X_rooms = boston_df.RM
y_price = boston_df.PRICE

X_rooms = np.array(X_rooms).reshape(-1,1)
y_price = np.array(y_price).reshape(-1,1)

# Splitting features and target datasets into: train and test
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X_rooms, y_price, test_size=0.30)

# Training a Linear Regression model with fit()
print("Training linear regression for RM vs PRICE...")
from sklearn.linear_model import LinearRegression
lm = LinearRegression()
lm.fit(X_train, y_train)

# Predicting the results for our test dataset
predicted_values = lm.predict(X_train)

# Calculating and printing the model performance
# Ref. https://towardsdatascience.com/how-to-select-the-right-evaluation-metric-for-machine-learning-models-part-1-regrression-metrics-3606e25beae0
#
from sklearn.metrics import mean_squared_error
rmse = (np.sqrt(mean_squared_error(y_train, predicted_values)))
r2 = round(lm.score(X_train, y_train),2)

print("The model performance for training set")
print("--------------------------------------")
print('RMSE is {}'.format(rmse))
print('R2 score is {}'.format(r2))
print("\n")


import numpy as np

def mad_based_outlier(points, thresh=3.5, two_sided=False):
    '''Identifies outliers using Median Absolute Deviation.

    By default, returns outliers who are greater than the main distribution.

    Args:
        points (numpy.array): Data points.
        thresh (float): Modified Z-score threshold.
        two_sided (bool, default=False): If True, returns outliers both greater
            than and less than the main distribution.
    Returns:
        numpy.array: A boolean array of outliers.
    '''
    if len(points.shape) == 1:
        points = np.array(points)[:, None]
    median = np.median(points, axis=0)
    diff = np.sum((points - median)**2, axis=-1)
    diff = np.sqrt(diff)
    med_abs_deviation = np.median(diff)
    signed_diff = np.sum((points - median), axis=-1)
    modified_z_score = 0.6745 * signed_diff / med_abs_deviation
    return modified_z_score > thresh


# -*- coding: utf-8 -*-
# math_helpers.py

def simple_linear_regression(x, y):
    import numpy as np

    x = np.array(x)
    y = np.array(y)

    n = x.shape[0]
    assert n > 2, "not enough data points"

    sum_x = np.sum(x)
    sum_xx = np.sum(x * x)

    slope = (n * np.sum(x * y) - sum_x * np.sum(y)) / (n * sum_xx - sum_x ** 2)
    bias = y.mean() - slope * x.mean()

    residuals_sq = ((y - (slope * x + bias)) ** 2).sum()
    std_error_slope = np.sqrt(residuals_sq / (n - 2) / (np.sum((x - x.mean()) ** 2)))

    std_error_bias = np.sqrt(
        residuals_sq / (n - 2) / n * sum_xx / (np.sum((x - x.mean()) ** 2))
    )

    return (slope, std_error_slope), (bias, std_error_bias)

def correlation(x, y) -> float:
    from statistics import stdev, mean

    mean_x, std_x = mean(x), stdev(x)
    mean_y, std_y = mean(y), stdev(y)

    if (std_y == 0) or (std_x == 0):
        return 0

    running_sum = 0
    running_count = 0
    for (x_, y_) in zip(x, y):
        running_sum += (x_ - mean_x) * (y_ - mean_y)
        running_count += 1

    if running_count < 1:
        return 0

    return (running_sum / (running_count - 1)) / std_y / std_x


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

df = pd.read_csv('bc.txt', sep=",", header=None)
df.head()
df1 = df.drop([0,10],axis=1)
data = np.array(df1)

def find_converging_centroid(k):
    clusters = np.zeros(data.shape[0])
    C = np.random.uniform(low=np.min(data), high=np.max(data), size=(k,data.shape[1]))
    print(C)
    C_previous = np.zeros(C.shape)
    change_in_centroid = euclidean_distance(C,C_previous,None)

    while change_in_centroid !=0:
        empty_cluster = False
        empty_cluster_index = 0
        biggest_cluster = 0
        single_biggest_cluster = []
        biggest_cluster_index = 0
        #CLASSIFY
        for i in range(data.shape[0]):
            distance_X_allC = euclidean_distance(data[i],C)
            cluster_index = np.argmin(distance_X_allC)
            clusters[i] = cluster_index
        C_previous = np.array(C, copy=True)
        #RECENTER
        for i in range(k):
            x_of_single_cluster = []
            for h in range(data.shape[0]):
                if clusters[h] == i:
                    x_of_single_cluster.append(data[h])
            if len(x_of_single_cluster)==0:
                empty_cluster = True
                empty_cluster_index = i
                print("empty cluster found")
            else:
                C[i] = np.mean(x_of_single_cluster,axis=0)
            if biggest_cluster < len(x_of_single_cluster):
                biggest_cluster = len(x_of_single_cluster)
                single_biggest_cluster = copy.copy(x_of_single_cluster)
                biggest_cluster_index = i
        if empty_cluster:
            #divide the biggest cluster into two equal cluster
            list1 = single_biggest_cluster[:int(len(single_biggest_cluster)/2)]
            list2 = single_biggest_cluster[int(len(single_biggest_cluster)/2):]
            C[biggest_cluster_index] = np.mean(list1,axis=0)
            C[empty_cluster_index] = np.mean(list2,axis=0)
        change_in_centroid = euclidean_distance(C, C_previous, None)
    return C,clusters

def euclidean_distance(x,y, along=1):
    #return scipy.spatial.distance.cdist(x,y,'euclidean')
    return np.linalg.norm(x-y,axis=along)

k_list = [2,3,4,5,6,7,8]
t =0
L = [0]* len(k_list)
for k in k_list:
    C,clusters = find_converging_centroid(k)
    for i in range(data.shape[0]):
        L[t] = L[t] + np.sum(np.square(C[int(clusters[i])]-data[i]))
    t = t+1
    print("L = ",L," & K = ",k)

plt.plot(L, label="Testing Error")
plt.xticks(range(len(k_list)),k_list)
plt.xlabel('Different K values')
plt.ylabel('(Potential Function) Accumulated Distance from centroid')
plt.title('K-Means k versus distance')
plt.legend()
plt.show()


import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.preprocessing import StandardScaler

# Data preprocessing
data = pd.read_csv("data.csv")

# Converting Pandas dataframe to numpy array
X = data.x.values.reshape(-1, 1)
Y = data.y.values.reshape(-1, 1)

# Add bias
m = X.shape[0]  # sample count
bias = np.ones((m, 1))
X_train = np.append(bias, X, axis=1)

# Add x^2 values
x2 = X**2
X_train = np.append(X_train, x2, axis=1)
Y_train = np.array(Y)

# Calculating theta with Normal Equation formula
def normalEquation(X, Y):
    theta = []

    # Normal Equation formula is :
    # inverse(X^T * X) * X^T * y
    X_transpose = np.transpose(X)
    theta = np.linalg.inv(X_transpose.dot(X)).dot(X_transpose).dot(Y)

    return theta

# Get theta
theta = normalEquation(X_train, Y_train)
print("Theta = ", theta)

# Predicted Values
Y_pred = X_train.dot(theta)

# Model Evaluation
def rmse(Y, Y_pred):
    rmse = np.sqrt(sum((Y - Y_pred) ** 2) / Y.shape[0])
    return rmse

def r2_score(Y, Y_pred):
    mean_y = np.mean(Y)
    ss_tot = sum((Y - mean_y) ** 2)
    ss_res = sum((Y - Y_pred) ** 2)
    r2 = 1 - (ss_res / ss_tot)
    return r2

# Print Scores
print("RMSE = ", rmse(Y_train, Y_pred))
print("R2 Score = ", r2_score(Y_train, Y_pred))

# Visualization
# Ploting Regression Line
plt.plot(X, Y_pred, color='#c93e4e', label='Regression Line')
# Ploting Scatter Points
plt.scatter(X, Y, c='#54a774', label='Scatter Plot')
plt.xlabel('Size')
plt.ylabel('Price')
plt.legend()
plt.show()


# The Sudoku board is a 9x9 grid, which is further divided into a 3x3 grid
# of 3x3 grids.  Each cell in the grid must take a value from 0 to 9.
# No two grid cells in the same row, column, or 3x3 subgrid may take the
# same value.
#
# In the MIP formulation, binary variables x[i,j,v] indicate whether
# cell <i,j> takes value 'v'.  The constraints are as follows:
#   1. Each cell must take exactly one value (sum_v x[i,j,v] = 1)
#   2. Each value is used exactly once per row (sum_i x[i,j,v] = 1)
#   3. Each value is used exactly once per column (sum_j x[i,j,v] = 1)
#   4. Each value is used exactly once per 3x3 subgrid (sum_grid x[i,j,v] = 1)
#
# Input datasets for this example can be found in examples/data/sudoku*.

import os
from os.path import dirname, join
project_root = dirname(dirname(__file__))
data_path = join(project_root, 'Data', '')
import math
import gurobipy as gp
from gurobipy import GRB
import numpy as np
from tqdm import tqdm
import multiprocessing

class SudokuSolver:
    def __init__(self, dir_path):
        self.dir = dir_path
        self.grid = []

    def loadTxt(self):
        file = open(self.dir, 'r')
        self.grid = np.array([ list(line.strip()) for line in file])
        file.close()
        return self.grid

    def solve(self):
        grid = self.loadTxt()

        n = len(grid[0])
        s = int(math.sqrt(n))

        # Create our 3-D array of model variables
        model = gp.Model('sudoku')
        vars = model.addVars(n, n, n, vtype=GRB.BINARY, name='G')

        model.setParam('OutputFlag', 0)
        # Fix variables associated with cells whose values are pre-specified

        for i in range(n):
            for j in range(n):
                if grid[i][j] != '0':
                    v = int(grid[i][j]) - 1
                    vars[i, j, v].LB = 1

        # Each cell must take one value

        model.addConstrs((vars.sum(i, j, '*') == 1
                         for i in range(n)
                         for j in range(n)), name='V')

        # Each value appears once per row

        model.addConstrs((vars.sum(i, '*', v) == 1
                         for i in range(n)
                         for v in range(n)), name='R')

        # Each value appears once per column

        model.addConstrs((vars.sum('*', j, v) == 1
                         for j in range(n)
                         for v in range(n)), name='C')

        # Each value appears once per subgrid

        model.addConstrs((
            gp.quicksum(vars[i, j, v] for i in range(i0*s, (i0+1)*s)
                        for j in range(j0*s, (j0+1)*s)) == 1
            for v in range(n)
            for i0 in range(s)
            for j0 in range(s)), name='Sub')

        model.optimize()

        # Retrieve optimization result

        solution = model.getAttr('X', vars)

        solutionGrid = np.zeros((n, n))

        for i in range(n):
            sol = ''
            for j in range(n):
                for v in range(n):
                    if solution[i, j, v] > 0.5:
                        sol += str(v+1)
                        solutionGrid[i,j] = v+1
            print(sol)

        return solutionGrid

def dataParser(dir):
    if len(os.listdir(data_path + 'p096_sudoku')) != 0:
        print('Folder exists.')
        return 'All file dispatched.'

    agrregateData = open(dir, 'r')
    for line in agrregateData:
        if line.startswith('Grid'):
            data_container = []
            output_name = line.strip()
        else:
            data_container.append(line.strip())

        if len(data_container) == 9:
            with open(data_path + 'p096_sudoku/'+ output_name + '.txt', "w") as outfile:
                outfile.write("\n".join(data_container))
    return 'All file dispatched.'

def main(dir):
    solver = SudokuSolver(data_path + 'p096_sudoku/' + dir )
    res = solver.solve().ravel()
    three_digit = ''.join([str(int(res[i])) for i in range(3)])
    return int(three_digit)

if __name__ == '__main__':
    data_dir = data_path + 'p096_sudoku.txt'
    dataParser(data_dir)
    files = os.listdir(data_path + 'p096_sudoku')

    res = 0
    for file in tqdm(files):
        res += main(file)
    print('Final result',res)

    # with multiprocessing.Pool(processes=os.cpu_count()//2) as p:
    #     MAX_COUNT = len(files)
    #     res = tqdm(p.imap(main, files), total=MAX_COUNT)
    # print(sum(res))


"""
This code includes functions for computing
the eigenvalues of large sparse matrices.

The main eigenvalue of interest is the second
smallest eigenvalue of the graph laplacian
(known as the algerbaic connectivity).

"""

#Import packages:
from scipy.sparse.linalg import LinearOperator, eigsh, minres
import numpy as np

def Largest_EV(M,return_eigenvector = False) :

	"""

	Computes the largest eigenvalue of a sparse matrix M

	Parameters
	------------

	M : scipy sparse matrix

	Returns
	----------

	EV : double

	The largest eigenvalue of the matrix M

	"""
	M = M.asfptype()

	if return_eigenvector == True:
		evals_large , evecs_large = eigsh(M, 1, which='LM', tol=1E-6, return_eigenvectors=True)
		return evals_large[0], np.transpose(evecs_large)[-1]
	else:
		evals_large = eigsh(M, 1, which='LM', tol=1E-6, return_eigenvectors=False)
		return evals_large[0]

def Smallest_Non_Zero(M, return_eigenvector = False , v0 = None , Threshold = 1E-8 , zero_eig_limit = 100) :

		"""

		Method to find the smallest non zero eigenvalue of a positive semidefinite matrix.

		-This method can be used when we want to estimate the mu2 value
		without having to assume that we have initially extracted the LCC.

		-Recommend using this even for matrices which we expect to have a single
		zero eigenvalue as the eigsh method can sometimes return multiple values
		close to zero due to numerical error in the eigensolver.

		Terminates if the first 100 eigenvalues are found to be below
		the threshold.

		From M we can construct a linear operator which is used in the eigenvalue computation:
		(See https://github.com/scipy/scipy/issues/4170 or https://docs.scipy.org/doc/scipy-0.18.1/reference/generated/scipy.sparse.linalg.LinearOperator.html for details )

		Parameters
		---------------

		M : scipy sparse matrix

		matrix to find eigenvalues of (This code has been desigend for this to be a
		graph laplacian matrix).

		return_eigenvector : bool (optional)

		option to return the eigenvector associated with the smallest non-zero eigenvalue.

		v0 : vector/array (optional)

		Vector to use as a starting point for iteration.

		Threshold : float (optional)

		Threshold for eigenvalues to be assumed to be zero.
		Set to 1E-8 by default. Has to be non-zero otherwise
		we will incorrectly return zero eigenvalues as non-zero
		due to numerical error.

		zero_eig_limit : int

		Terminate if we find more than 'zero_eig_limit' eigenvalues close to zero.

		"""

		Found_Non_Zero = False
		k = 0

		#Construct the linear operator to use in the solver:
		OPinv = LinearOperator(matvec=lambda v: minres(M, v, tol=1e-6)[0], shape=M.shape, dtype=M.dtype)

		"""Compute eigenvalues and eigenvectors until we find one
		which is greater than a certain threshold."""
		while Found_Non_Zero == False and k < zero_eig_limit :

			#Compute eigenvalues and eigenvectors: (looks for at least two eigenvalues)
			evals_small , evecs_small = eigsh(M, k+2, sigma= 0, which='LM', tol = 1E-6, return_eigenvectors = True , OPinv = OPinv , v0 = v0)

			#Check if any eigenvalues are above the threshold:
			if max(evals_small) > Threshold :
				Found_Non_Zero = True
				Mu2 = max(evals_small)
			k = k + 1

		if return_eigenvector == True :
			return Mu2 , np.transpose(evecs_small)[-1]
		else:
			return Mu2


import numpy as np
from numba import njit
from time import time
from tensiga.iga.auxkv import auxkv
from tensiga.iga.Bspline import Bspline
from tensiga.quadrature.afftf import afftf

def glint(kv, p):
    """Univariate, global Gauss-Legendre quadrature rule

    Parameters:
        n (int) : quadrature order n > 0

    Returns:
        ip (np.array(float)) : array integration point coordinates
        W (numpy.array(float)) : weights W[k] corresponding to ip[k]
    """
    dim = len(kv)
    aux, _ = auxkv(kv)
    nelem = len(aux) - 1

    ip, W = proto_rule = np.polynomial.legendre.leggauss(p)

    glob_ip = [None] * ip.size * nelem
    glob_W = [None] * ip.size * nelem
    for idx in range(nelem):
        lbound = aux[idx]
        rbound = aux[idx+1]

        x, dx = afftf(ip, [lbound, rbound])
        glob_ip[(idx*ip.size):(idx*ip.size + ip.size)] = x
        glob_W[(idx*ip.size):(idx*ip.size + ip.size)] = W * dx

    return np.array(glob_ip), np.array(glob_W)

if __name__ == '__main__':
    def f1(x):
        return x**2 + 3*x - 10

    kv = np.array([0, 1, 1, 1, 2, 3, 4, 4, 5, 6, 6, 6])
    kv = np.linspace(0,6,1000)

    tstart = time()
    ip, W = glint(kv, 2)
    print('time:', time()-tstart)

    res = 0
    for (ip_k, W_k) in zip(ip, W):
        res += W_k * f1(ip_k)

    print(res) # exact: 66


import numpy as np
'''
ベクトル[の|][演算|計算]を[する|行う]
行列[の|][演算|計算]を[する|行う]
numpyを[使う|入れる|インポートする]
@prefix(aArray;配列)
'''

iterable = np.array([0, 1, 2, 3])
aArray = np.array([1, 2, 3, 4])
aArray2 = iterable
aList = [1, 2]

np.array(aList)
'''
aListから配列を[作る]
'''

np.array(iterable)
'''
iterableから配列を作る
'''

aArray.shape()
'''
aArrayの[形状|形]を調べる
'''

aArray.dtype()
'''
aArrayの[データ型|型]を調べる
'''

np.ndim(aArray)
'''
aArrayの[次元数|次元の数]を調べる
'''

np.arange(10)
'''
0から9までの配列を作る
'''

aArray.reshape(3, 3)
'''
aArrayを3×3の多次元配列に変形する
'''

np.concatenate([aArray, aArray2])
'''
aArrayと@aArray2を[列方向|縦方向]に連結する
'''

np.concatenate([aArray, aArray2], axis=0)
'''
aArrayと@aArray2を[列方向|縦方向]に連結する
'''

np.concatenate([aArray, aArray2], axis=1)
'''
aArrayと@aArray2を[行方向|横方向]に連結する
'''

np.sum(aArray)
'''
aArrayの[合計値|合計]を調べる
'''

np.sum(aArray, axis=0)
'''
aArrayの列ごとの[合計値|合計]を調べる
'''

np.sum(aArray, axis=1)
'''
aArrayの行ごとの[合計値|合計]を調べる
'''

np.mean(aArray)
'''
aArrayの[平均値|平均]を調べる
'''

np.mean(aArray, axis=0)
'''
aArrayの列ごとの[平均値|平均]を調べる
'''

np.mean(aArray, axis=1)
'''
aArrayの行ごとの[平均値|平均]を調べる
'''

np.min(aArray)
'''
aArrayの[最小値|最小]を調べる
'''

np.min(aArray, axis=0)
'''
aArrayの列ごとの[最小値|最小]を調べる
'''

np.min(aArray, axis=1)
'''
aArrayの行ごとの[最小値|最小]を調べる
'''

np.max(aArray)
'''
aArrayの[最大値|最大]を調べる
'''

np.max(aArray, axis=0)
'''
aArrayの列ごとの[最大値|最大]を調べる
'''

np.max(aArray, axis=1)
'''
aArrayの行ごとの[最大値|最大]を調べる
'''

np.std(aArray)
'''
aArrayの標準偏差を調べる
'''

np.std(aArray, axis=0)
'''
aArrayの列ごとの標準偏差を調べる
'''

np.std(aArray, axis=1)
'''
aArrayの行ごとの標準偏差を調べる
'''

np.var(aArray)
'''
aArrayの分散を調べる
'''

np.var(aArray, axis=0)
'''
aArrayの列ごとの分散を調べる
'''

np.var(aArray, axis=1)
'''
aArrayの行ごとの分散を調べる
'''

np.eye(3)
'''
3×3の単位行列を作る
'''

np.identity(3)
'''
3×3の単位行列を作る
'''

np.empty(5)
'''
要素数5の[空配列|空の配列]を作る
'''

np.empty((2, 3))
'''
2×3の[空配列|空の配列]を作る
'''

np.empty_like(aArray)
'''
aArrayと同じ大きさの[空配列|空の配列]を作る
'''

np.gcd(aArray, aArray2)
'''
aArrayと@aArray2の要素ごとの最大公約数を調べる
'''

np.lcm(aArray, aArray2)
'''
aArrayと@aArray2の要素ごとの最小公倍数を調べる
'''

np.unique(aArray)
'''
aArrayから重複を除いた配列を作る
aArrayのユニークな要素を調べる
'''

u, counts = np.unique(aArray, return_counts=True)
'''
aArrayのユニークな要素とその個数を調べる
'''

u, indices = np.unique(aArray, return_index=True)
'''
aArrayのユニークな要素とその位置を調べる
'''

np.cumsum(aArray)
'''
aArrayの累積和を調べる
'''

np.cumprod(aArray)
'''
aArrayの累積積を調べる
'''

aArray.flatten()
'''
aArrayを[一次元にする|一次元化|平坦化]
'''


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

from numpy import*
# 将文本信息转换为矩阵返回
def loadDataSet(fileName):
    fr = open(fileName)
    stringArr = [line.strip().split('\t') for line in fr.readlines()]
    datArr = [map(float,line) for line in stringArr]     #map(float,line)第一个参数是一个函数，第二个参数是输入的数据，函数作用于第二个输入的每一个对象并返回list
    return mat(datArr)

# PCA算法实现
def pca(dataMat,topNfeat):
    meanVals = mean(dataMat ,axis = 0)  #对矩阵的每一列取平均值
    meanRemoved = dataMat - meanVals   #去均值
    covMat = cov(meanRemoved,rowvar = 0)
    eigVals,eigVects = linalg.eig(mat(covMat))   #算得特征值(是个数组)和特征向量（是个矩阵）
    eigValInd = argsort(eigVals)               #对特征值进行从小到大的排序
    eigValInd = eigValInd[:-(topNfeat+1):-1]
    redEigVects = eigVects[:,eigValInd]
    loadDataMat = meanRemoved * redEigVects  #将去除均值后的数据矩阵*压缩矩阵，转换到新的空间，使维度降低为N
    reconMat = (loadDataMat * redEigVects.T) + meanVals  #利用降维后的矩阵反构出原数据矩阵(用作测试，可跟未压缩的原矩阵比对)
    return loadDataMat,reconMat

# 自适应PCA算法实现
def zsypca(dataMat):
    meanVals = mean(dataMat ,axis = 0)  #对矩阵的每一列取平均值
    meanRemoved = dataMat - meanVals   #去均值
    covMat = cov(meanRemoved,rowvar = 0)
    eigVals,eigVects = linalg.eig(mat(covMat))   #算得特征值(是个数组)和特征向量（是个矩阵）
    eigVals = real(eigVals)
    eigValInd = argsort(eigVals)               #对特征值进行从小到大的排序
    N = len(eigValInd)                         #特征值的个数
    eigValInd = eigValInd[:-(N+1):-1]
    newEigValInd = []
    sumEigVals = sum(eigVals)
    i = 0
    sumOfEigVls= 0
    while sumOfEigVls/float(sumEigVals) < 0.98:  # 压缩比约为98%
        sumOfEigVls += eigVals[i]
        newEigValInd.append(i)
        i += 1
    demension = i
    compressRatio = sumOfEigVls/float(sumEigVals)
    newEigValInd = array(newEigValInd)
    redEigVects = eigVects[:,newEigValInd]
    redEigVects = real(redEigVects)
    loadDataMat = meanRemoved * redEigVects  #将去除均值后的数据矩阵*压缩矩阵，转换到新的空间，使维度降低为N
    reconMat = (loadDataMat * redEigVects.T) + meanVals  #利用降维后的矩阵反构出原数据矩阵(用作测试，可跟未压缩的原矩阵比对)
    return loadDataMat,reconMat,demension ,compressRatio,redEigVects,meanVals


# Starting in the top left corner of a 2×2 grid,
# and only being able to move to the right and down,
# there are exactly 6 routes to the bottom right corner.
#
# How many such routes are there through a 20×20 grid?

from scipy.special import binom

def solution():
    return binom(40, 20)

if __name__ == '__main__':
    print(solution())


##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
##                          K-Means clustering of Etch data
## %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

#%% import required packages
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans

#%% fetch data
import scipy.io

matlab_data = scipy.io.loadmat('MACHINE_Data.mat', struct_as_record = False)
Etch_data = matlab_data['LAMDATA']
calibration_dataAll = Etch_data[0,0].calibration # calibration_dataAll[i,0] corresponds to a 2D data from ith batch where columns correspond to different variables

variable_names = Etch_data[0,0].variables

##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
##                          perform Multiway PCA
## %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

#%% generate unfolded data matrix
n_vars = variable_names.size - 2 # first 2 columns are not process variables
n_samples = 85 # following the work of He et al.

unfolded_dataMatrix = np.empty((1,n_vars*n_samples))
for expt in range(calibration_dataAll.size):
    calibration_expt = calibration_dataAll[expt,0][5:90,2:] # removing first 5 measurements as done in He et al.

    if calibration_expt.shape[0] < 85:
        continue

    unfolded_row = np.ravel(calibration_expt, order='F')[np.newaxis,:]
    unfolded_dataMatrix = np.vstack((unfolded_dataMatrix, unfolded_row))

unfolded_dataMatrix = unfolded_dataMatrix[1:,:]

#%% scale data
from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
data_train_normal = scaler.fit_transform(unfolded_dataMatrix)

#%% PCA
from sklearn.decomposition import PCA

pca = PCA(n_components = 3) # following the work of He et al.
score_train = pca.fit_transform(data_train_normal)

#%% visualize in 2D
plt.figure()
plt.scatter(score_train[:,0],score_train[:,1])
plt.xlabel('PC1 scores')
plt.ylabel('PC2 scores')

##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
##                          K-Means on PCA scores
## %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

#%% determining number of clusters via elbow method
SSEs = []
for n_cluster in range(1, 10):
    kmeans = KMeans(n_clusters = n_cluster, random_state = 100).fit(score_train)
    SSEs.append(kmeans.inertia_)

plt.figure()
plt.plot(range(1,10), SSEs, marker='o')
plt.xlabel('Number of clusters')
plt.ylabel('SSEs')
plt.show()

#%% fit k-means model
n_cluster = 3
kmeans = KMeans(n_clusters = n_cluster, random_state = 100).fit(score_train)
cluster_label = kmeans.predict(score_train) # can also use kmeans.labels_

plt.figure()
plt.scatter(score_train[:, 0], score_train[:, 1], c = cluster_label, s = 20, cmap = 'viridis')
plt.xlabel('PC1 scores')
plt.ylabel('PC2 scores')

cluster_centers = kmeans.cluster_centers_
cluster_plot_labels = ['Cluster ' + str(i+1) for i in range(n_cluster)]
for i in range(n_cluster):
    plt.scatter(cluster_centers[i,0], cluster_centers[i,1], c = 'red', s = 40, marker = '*', alpha = 0.9)
    plt.annotate(cluster_plot_labels[i], (cluster_centers[i,0], cluster_centers[i,1]))

##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
##                          Analyzing cluster quality via silhouette plots
## %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

#%% average silhouette score
from sklearn.metrics import silhouette_samples, silhouette_score

silhouette_avgValue = silhouette_score(score_train, cluster_label)
print('Average silhouette score is :', silhouette_avgValue)

#%% silhouette plot
from matplotlib import cm

plt.figure()
silhouette_values = silhouette_samples(score_train, cluster_label)
y_lower, y_upper = 0, 0
yticks = []
for i in range(n_cluster):
    cluster_silhouette_vals = silhouette_values[cluster_label == i]
    cluster_silhouette_vals.sort()

    y_upper += len(cluster_silhouette_vals)
    color = cm.nipy_spectral(i / n_cluster)
    plt.barh(range(y_lower, y_upper),cluster_silhouette_vals,height=1.0,edgecolor='none',color=color)

    yticks.append((y_lower + y_upper) / 2)
    y_lower += len(cluster_silhouette_vals)

plt.axvline(silhouette_avgValue, color="red", linestyle="--")
plt.yticks(yticks, np.arange(n_cluster)+1)
plt.xlabel('Silhouette coefficient values')
plt.ylabel('Cluster')


# Exercise 5.21
# Author: Noah Waterfield Price

import numpy as np
import matplotlib.pyplot as plt

def factorial(n):
    if n == 0:
        return 1
    else:
        return n * factorial(n - 1)

def S(x, n):
    ans = 0
    for j in range(n + 1):
        ans += (-1) ** j * x ** (2 * j + 1) / factorial(2 * j + 1)
    return ans

x = np.linspace(0, 4 * np.pi, 1001)

plt.plot(x, np.sin(x), '--k', linewidth=2)
for n in [1, 2, 3, 6, 12]:
    plt.plot(x, S(x, n))

plt.ylim([-1.1, 1.1])
plt.legend(['n = 1', 'n = 2', 'n = 3', 'n = 6', 'n = 12', 'sin(x)'])
plt.xlabel('x')
plt.ylabel('f(x)')
plt.show()


# -*- coding: utf-8 -*-
"""
Created on Thu Feb 14 19:00:16 2019

@author: z
"""

import numpy as np
import scipy.stats as ss
import statsmodels.api as sm
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split

#生成数据
n = 100
beta_0 = 5
beta_1 = 2
beta_2 = -1
np.random.seed(1)
x_1 = 10 * ss.uniform.rvs(size=n)
x_2 = 10 * ss.uniform.rvs(size=n)
X = np.stack([x_1,x_2], axis=1)
y_sci = beta_0 + beta_1 * x_1 + beta_2 * x_2 + ss.norm.rvs(loc=0, scale=1, size=n)

x = 10 * ss.uniform.rvs(size=n)
y = beta_0 + beta_1 * x + ss.norm.rvs(loc=0, scale=1, size=n)

plt.figure()
plt.plot(x,y,"o",ms=5)
xx = np.array([0,10])
plt.plot(xx,beta_0 + beta_1 * xx)
plt.xlabel("x")
plt.ylabel("y");

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(X[:,0], X[:,1], y_sci, c=y_sci)
ax.set_xlabel("$x_1$")
ax.set_ylabel("$x_2$")
ax.set_zlabel("$y_sci$");

#计算方差
def compute_rss(y_estimate, y):
  return sum(np.power(y-y_estimate, 2))
def estimate_y(x, b_0, b_1):
  return b_0 + b_1 * x
rss = compute_rss(estimate_y(x, beta_0, beta_1), y)

#最小二乘估计
rss = []
slopes = np.arange(-10,15,0.01)
for slope in slopes:
    rss.append(np.sum((y - beta_0 - slope * x)**2))
ind_min = np.argmin(rss)

plt.figure()
plt.plot(slopes,rss)
plt.xlabel("Slope")
plt.ylabel("RSS")
print("Estimate for the slope: ", slopes[ind_min])

#使用Statsmodel模型库
X_sm = sm.add_constant(x)
mod = sm.OLS(y,X_sm)
est = mod.fit()
print(est.summary())

#使用Scikit_Learn机器学习库
lm = LinearRegression(fit_intercept=True)
lm.fit(X,y_sci)
print("beta 0: ",lm.intercept_)    #截距
print("beta 1&2: ",lm.coef_)         #变量数组
X_0 = np.array([2,4])
print("预测 [%d,%d]处y值: %.4f" % (X_0[0], X_0[1], lm.predict(X_0.reshape(1, -1))))
print("R2 :",lm.score(X, y_sci))

#测试数据
X_train, X_test, y_train, y_test = train_test_split(X, y_sci, train_size=0.5, random_state=1)
lm = LinearRegression(fit_intercept=True)
lm.fit(X_train, y_train)
lm.score(X_test, y_test)

import numpy,import scipy,import statsmodels


# ---------------------------------
# Prepare the data etc.
# ----------------------------------
import numpy as np
import pandas as pd

# train_x is the training data, train_y is the target values, and test_x is the test data
# stored in pandas DataFrames and Series (numpy arrays also used)

train = pd.read_csv('../input/sample-data/train_preprocessed_onehot.csv')
train_x = train.drop(['target'], axis=1)
train_y = train['target']
test_x = pd.read_csv('../input/sample-data/test_preprocessed_onehot.csv')

# ---------------------------------
# Use argsort() to do index sort
# ---------------------------------
# Arrays can be ordered using index sort into ascending and descending order with argsort()
ary = np.array([10, 20, 30, 0])
idx = ary.argsort()
print(idx)  # Ascending order - [3 0 1 2]
print(idx[::-1])  # Descending order - [2 1 0 3]

print(ary[idx[::-1][:3]])  # Output best three - [30, 20, 10]

# ---------------------------------
# Correlation coefficient
# ---------------------------------
import scipy.stats as st

# Correlation coefficient
corrs = []
for c in train_x.columns:
    corr = np.corrcoef(train_x[c], train_y)[0, 1]
    corrs.append(corr)
corrs = np.array(corrs)

# Spearman's rank correlation coefficient
corrs_sp = []
for c in train_x.columns:
    corr_sp = st.spearmanr(train_x[c], train_y).correlation
    corrs_sp.append(corr_sp)
corrs_sp = np.array(corrs_sp)

# Output in order to top importance (maximum of top 5)
# Using np.argsort(), you can get the indices of the ordered values
idx = np.argsort(np.abs(corrs))[::-1]
top_cols, top_importances = train_x.columns.values[idx][:5], corrs[idx][:5]
print(top_cols, top_importances)

idx2 = np.argsort(np.abs(corrs_sp))[::-1]
top_cols2, top_importances2 = train_x.columns.values[idx][:5], corrs_sp[idx][:5]
print(top_cols2, top_importances2)

# ---------------------------------
# Chi-square statistic
# ---------------------------------
from sklearn.feature_selection import chi2
from sklearn.preprocessing import MinMaxScaler

# Chi-square statistic
x = MinMaxScaler().fit_transform(train_x)
c2, _ = chi2(x, train_y)

# Output in order to top importance (maximum of top 5)
idx = np.argsort(c2)[::-1]
top_cols, top_importances = train_x.columns.values[idx][:5], corrs[idx][:5]
print(top_cols, top_importances)

# ---------------------------------
# Mutual information
# ---------------------------------
from sklearn.feature_selection import mutual_info_classif

# Mutual information
mi = mutual_info_classif(train_x, train_y)

# Output in order to top importance (maximum of top 5)
idx = np.argsort(mi)[::-1]
top_cols, top_importances = train_x.columns.values[idx][:5], corrs[idx][:5]
print(top_cols, top_importances)


import logging
from math import pi
import numpy as np

log = logging.getLogger(__name__)

def linear(N):
    return (np.linspace(-1, 1, N), np.ones(N))

def trapezoid(N):
    points = np.linspace(-1.0, 1.0, N)
    w = 1.0 / float(N)
    weights = np.ones(N) * 2.0 * w
    weights[0] = weights[-1] = w
    return (points, weights)

def periodic_trapezoid(N):
    shift = 1.0 / float(N)
    points = np.linspace(-1 + shift, 1 - shift, N)
    weights = np.ones(N) * (2.0 / float(N))
    return (points, weights)

def legendre_gauss_lobatto(N):
    # Use the Chebyshev-Gauss-Lobatto nodes as the first guess
    x = np.cos(np.linspace(0, pi, N))
    # The Legendre Vandermonde Matrix
    P = np.zeros((N, N))
    # Compute P_(N) using the recursion relation
    # Compute its first and second derivatives and
    # update x using the Newton-Raphson method.
    xold = 2
    while np.amax(np.abs(x - xold)) > (1e-15):
        xold = x
        P[:, 0] = 1
        P[:, 1] = x
        for k in range(2, N):
            P[:, k] = ((2 * k - 1) * x * P[:, k - 1] -
                       (k - 1) * P[:, k - 2]) / k
        x = xold - (x * P[:, N - 1] - P[:, N - 2]) / (N * P[:, N - 1])

    w = 2.0 / ((N - 1) * N * np.square(P[:, N - 1]))

    return (np.array(x[::-1]), np.array(w[::-1]))


import pandas as pd
import numpy as np
import typing as t
from scipy import stats as ss

class Ranker:
    """ Ranks features. Uses Spearman's correlation for numerical features and Cramer's V for
        binary features
    """

    @staticmethod
    def _cramer_v(x: pd.Series, y: pd.Series, /) -> t.Tuple[float, float]:
        cm = pd.crosstab(x, y)
        chi2, pval, _, _ = ss.chi2_contingency(cm)
        n = cm.sum().sum()
        phi2 = chi2 / n
        r, k = cm.shape
        phi2corr = max(0, phi2 - (k-1)*(r-1)/(n-1))
        rcorr = r - (r-1)**2/(n-1)
        kcorr = k - (k-1)**2/(n-1)
        return np.sqrt(phi2corr / min(kcorr-1, rcorr-1)) * 100, -np.log10(pval)

    @staticmethod
    def _spearman_r(x: pd.Series, y: pd.Series, /) -> t.Tuple[float, float]:
        r, pval = ss.spearmanr(x, y)
        return r * 100, -np.log10(pval)

    def rank(self, X: pd.DataFrame, y: pd.Series, /) -> pd.DataFrame:
        return pd.DataFrame.from_dict(
            data={
                v: self._cramer_v(X[v], y) if X[v].nunique() == 2 else self._spearman_r(X[v], y)
                for v in X
            },
            orient='index',
            columns=['assoc', 'significance']
        )


import numpy as np

def beta_model(So, r, rc, beta):
    ''' Beta model with 3 parameters.
    So -- normalization
    rc -- core radius
    beta -- powerlaw slope

    returns the flux (Cnts/pixel)

    '''

    return So * ( 1.0 + (r / rc)**2)**(-3.0 * beta + 0.5)

def integ_beta_model(r, rc, beta, r_start=0):
    ''' 2pi*r integral of the above Beta model with 3 parameters.
    r -- r to integrate to
    rc -- core radius
    beta -- powerlaw slope
    r_start -- starting point for integration

    This equation comes from Moretti et al. 2005. Their eq. 2.

    It's been updated with our beta.

    '''

    rc2 = rc * rc

    beta = -3.0 * beta + 0.5

    area1 = np.pi * rc2 / (1 - beta) * ((1 + r_start**2 / rc2)**(1 - beta) - 1)
    area2 = np.pi * rc2 / (1 - beta) * ((1 + r**2 / rc2)**(1 - beta) - 1)

    return area2 - area1

def inv_beta_model(So, rc, beta, bkg):
    ''' Solves for where (radius) the beta model is equal to the background

    Make sure you keep track of the units going into all this. You wanna make
    sure the radius comes out as something that makes sense.

    '''

    a = -3 * beta + 0.5

    b = (bkg / So)**(1 / a) - 1

    c = b * rc**2

    return np.sqrt(c)

def chi2(model, y, y_err):
    '''Chi error. We are going to square this to make it the chi2 error.'''
    return np.sum(((model - y) / y_err)**2)

def like(theta, x, y, yerr):
    So, rc, beta, bg = theta
    model = beta_model(So, x, rc, beta) + bg
    #return -0.5 * np.sum(np.log(2 * np.pi * yerr) + (y - model)**2 / yerr)
    return -chi2(model, y, yerr)

def prior(theta):
    So, rc, beta, bg = theta
    if So < 0:
        return -np.inf
    elif rc < 0 or rc > 10:
        return -np.inf
    elif beta < 0 or beta > 3:
        return -np.inf
    elif bg < 0 or bg > 1:
        return -np.inf
    else:
        return 0.0

def prob(theta, x, y, yerr):
    lp = prior(theta)
    if not np.isfinite(lp):
        return -np.inf
    return lp + like(theta, x, y, yerr)


import math
import numpy as np

def length(vec, eps=1e-6):
    return math.sqrt(np.sum(vec*vec)) + eps

def distance(source, target):
    return length(np.array(target) - np.array(source))

def angle(source, target):
    diff = np.array(target) - np.array(source)
    return 360*np.arctan2(diff[1], diff[0])/(2*np.pi) % 360

def cosine_sim(v1, v2):
    return (v1*v2).sum()/length(v1)/length(v2)

def between(x, a, b, threshold=-0.9):
    x = np.array(x)
    return cosine_sim(np.array(a) - x, np.array(b) - x) < threshold


import numpy as np

class LinearRegression:

    def __init__(self, iterations, learning_rate):
        self.iterations = iterations
        self.learning_rate = learning_rate

    def fit(self, X, Y):

        # m = training no. , n = features no.
        self.m , self.n = X.shape

        # Parameters Initialization
        self.W = np.zeros(self.n)

        # Bias
        self.b = 0
        self.X = X
        self.Y = Y

        for i in range(self.iterations):
            self.update_weights()
        return self

    def update_weights(self):
        #  Gradient Descent
        Y_pred = self.predict(self.X)

        #  Calculate Gradients
        dW = - ( 2 * (self.X.T).dot(self.Y - Y_pred) ) / self.m
        db = - ( 2 * np.sum(self.Y - Y_pred) ) / self.m

        #  Update W
        self.W = self.W - self.learning_rate * dW
        self.b = self.b - self.learning_rate * db

        return self

    def predict(self, X):
        return X.dot(self.W) + self.b


import numpy as np
import pandas as pd

def gini(actual, predicted):
    """
    Calculates Gini

    :param actual: array-like binary target
    :param predicted: array-like predicted values
    :return: float Gini value
    """
    a = np.asarray(np.c_[actual, predicted, np.arange(len(actual))], dtype=np.float)
    a = a[np.lexsort((a[:, 2], -1 * a[:, 1]))]
    total_losses = a[:, 0].sum()
    gini_sum = a[:, 0].cumsum().sum() / total_losses
    gini_sum -= (len(actual) + 1) / 2.
    return gini_sum / len(actual)

def gini_normalized(actual, predicted):
    """
    Calculates Normalized Gini

    :param actual: array-like binary target
    :param predicted: array-like predicted values
    :return: float normalized gini value in 0-1 range
    """
    return gini(actual, predicted) / gini(actual, actual)

def iv_table(x, y):
    """
    Calculates WoE-IV table

    :param x: array-like feature
    :param y: array-like binary target
    :return: Pandas DataFrame of WoE-IV statistics
    """
    table = pd.crosstab(x, y, normalize='columns') \
        .assign(woe=lambda dfx: np.log(dfx[1] / dfx[0])) \
        .assign(iv=lambda dfx: np.sum(dfx['woe'] * (dfx[1] - dfx[0])))
    return table


from math import sin, cos, radians, pow, sqrt

import numpy as np

class BadEllipseShape(Exception):
    def __init__(self, msg):
        self.msg = msg

class Ellipse:

    def __init__(self, rotated_rect, coeffs=None):

        """ Converts rotated_rect from cv2.findEllipse into conic equation
        Ellipse is isocontour at Q(x,y) = Ax^2 + Bxy + Cy^2 + Dx + Ey + F = 0
        """

        # Save rotated_rect for error calculation and easier cv2 drawing
        self.rotated_rect = rotated_rect

        if coeffs is None:
            (ell_x0, ell_y0), (ell_w, ell_h), angle = rotated_rect
            axis_x, axis_y = cos(radians(angle)), sin(radians(angle))
            a2 = ell_w * ell_w / 4
            b2 = ell_h * ell_h / 4

            # Initialise ellipse conic equation constants
            self.A = axis_x * axis_x / a2 + axis_y * axis_y / b2;
            self.B = 2 * axis_x * axis_y / a2 - 2 * axis_x * axis_y / b2;
            self.C = axis_y * axis_y / a2 + axis_x * axis_x / b2;
            self.D = (-2 * axis_x * axis_y * ell_y0 - 2 * axis_x * axis_x * ell_x0) / a2 + (2 * axis_x * axis_y * ell_y0 - 2 * axis_y * axis_y * ell_x0) / b2;
            self.E = (-2 * axis_x * axis_y * ell_x0 - 2 * axis_y * axis_y * ell_y0) / a2 + (2 * axis_x * axis_y * ell_x0 - 2 * axis_x * axis_x * ell_y0) / b2;
            self.F = (2 * axis_x * axis_y * ell_x0 * ell_y0 + axis_x * axis_x * ell_x0 * ell_x0 + axis_y * axis_y * ell_y0 * ell_y0) / a2 + (-2 * axis_x * axis_y * ell_x0 * ell_y0 + axis_y * axis_y * ell_x0 * ell_x0 + axis_x * axis_x * ell_y0 * ell_y0) / b2 - 1;
        else:
            self.A,self.B,self.C,self.D,self.E,self.F = coeffs

    def algebraic_distance(self, (px, py)):

        """ Returns value of Q at x,y
        """

        return self.A * px * px + self.B * px * py + self.C * py * py + self.D * px + self.E * py + self.F;

    def algebraic_gradient(self, (px, py)):

        """ Returns gradient of Q at x,y
        """

        grad_x = 2 * self.A * px + self.B * py + self.D
        grad_y = self.B * px + 2 * self.C * py + self.E

        if grad_x * grad_y == 0:
            raise BadEllipseShape('Gradient at point %d, %d = 0' % (px, py))

        return (2 * self.A * px + self.B * py + self.D,
                self.B * px + 2 * self.C * py + self.E);

    def algebraic_gradient_dir(self, (px, py)):

        """ Returns direction of gradient of Q at x,y
        """

        grad_x, grad_y = self.algebraic_gradient((px, py))
        length = sqrt(grad_x ** 2 + grad_y ** 2)
        return (grad_x / length, grad_y / length)

    def distance(self, p):

        """ EOF2 from Rosin '96: Q(x,y) / |grad.Q(x,y)|
        """

        dist = self.algebraic_distance(p)
        grad_x, grad_y = self.algebraic_gradient(p)
        sqgrad = grad_x ** 2 + grad_y ** 2
        return dist / pow(sqgrad, (0.45 / 2))

    ### --- Faster Numpy versions of methods for operating on all points at once ---
    # ##
    # ## requires pts_x ~ [ [x1] [x2] ... [xn] ]
    # ## requires pts_y ~ [ [y1] [y2] ... [yn] ]

    def algebraic_distances(self, pts_x, pts_y):

        """ Returns value of Q at for all points in numpy array [[pts_x pts_y] ... ]
        """

        return self.A * pts_x ** 2 + self.B * pts_x * pts_y + self.C * pts_y ** 2 + self.D * pts_x + self.E * pts_y + self.F;

    def algebraic_gradients(self, pts_x, pts_y):

        """ Returns gradient of Q at for all points in Numpy array
        """

        return (2 * self.A * pts_x + self.B * pts_y + self.D,
                self.B * pts_x + 2 * self.C * pts_y + self.E);

    def algebraic_gradient_dirs(self, pts_x, pts_y):

        """ Returns directions of gradients of Q in Numpy array
        """

        grads_x, grads_y = self.algebraic_gradients(pts_x, pts_y)
        lengths = np.sqrt(grads_x.dot(grads_x) + grads_y.dot(grads_y))
        return (grads_x / lengths, grads_y / lengths)

    def distances(self, pts_x, pts_y):

        """ Numpy array version of EOF2 from Rosin '96: Q(x,y) / |grad.Q(x,y)|
        """

        dists = self.algebraic_distances(pts_x, pts_y)
        grads_x, grads_y = self.algebraic_gradients(pts_x, pts_y)
        sqgrads = grads_x.dot(grads_x) + grads_y.dot(grads_y)
        return dists / (sqgrads ** (0.45 / 2))


import numpy as np

np.random.seed(1013)

inputs = np.array([
    [0,0,1],
    [1,1,1],
    [1,0,1],
    [0,1,1]
])

outputs = [[0], [1], [1], [0]]

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

def sigmoid_derivative(x):
    sx = sigmoid(x)
    return sx * (1-sx)

weights = 2 * np.random.random((3,1)) - 1

print("\n\nLet's start with a simple array of observations.\n\
Each observation is generated by 3 characteristics.\n\
I'll call them 'OB1', 'OB2', & 'OB3'.")
print("\n")
print("Here's 4 observations to start:")
print("\n")
print("Observation 1 - OB1:", inputs[0][0])
print("Observation 1 - OB2:", inputs[0][1])
print("Observation 1 - OB3:", inputs[0][2])
print("\n")
print("Observation 2 - OB1:", inputs[1][0])
print("Observation 2 - OB2:", inputs[1][1])
print("Observation 2 - OB3:", inputs[1][2])
print("\n")
print("Observation 3 - OB1:", inputs[2][0])
print("Observation 3 - OB2:", inputs[2][1])
print("Observation 3 - OB3:", inputs[2][2])
print("\n")
print("Observation 4 - OB1:", inputs[3][0])
print("Observation 4 - OB2:", inputs[3][1])
print("Observation 4 - OB3:", inputs[3][2])
print("\n")
print("So a simple perceptron will resolve to 4 responses.\n\
Our outputs are as follows:")
print("\n")
print("Output 1:", outputs[0][0])
print("Output 2:", outputs[1][0])
print("Output 3:", outputs[2][0])
print("Output 4:", outputs[3][0])

for iteration in range(100000):

    # Weighted sum of inputs / weights
    weighted_sum = np.dot(inputs, weights)
    print("Weighted sum:", weighted_sum[0],
          weighted_sum[1], weighted_sum[2],
          weighted_sum[3])
    # Activate!
    activated_output = sigmoid(weighted_sum)
    print("Activated output:", activated_output[0],
          activated_output[1], activated_output[2],
          activated_output[3])
    # Cac error
    error = outputs - activated_output
    print("Errors:", error[0], error[1], error[2],
          error[3])

    adjustments = error * sigmoid_derivative(weighted_sum)
    print("Adjustments to weight based on error:",
          adjustments[0], adjustments[1], adjustments[2],
          adjustments[3])
    # Update the Weights
    weights += np.dot(inputs.T, adjustments)
    print("New weight:",
          weights)

print("Weights after training")
print(weights)

print("Output after training")
print(activated_output)


import numpy as np
import math

def get_grad_mad(grad,ref):
  dim=grad.size
  diff=ref-grad
  s=sum(np.absolute(diff))
  return s/dim

def unit_vec(v):
  # much faster than np.linalg.norm because safetly checks
  l=math.sqrt((v[0])**2+(v[1])**2+(v[2])**2)
  return [v[0]/l,v[1]/l,v[2]/l]

def np_angle(v1, v2):
    v1_u=unit_vec(v1)
    v2_u=unit_vec(v2)
    return np.arccos(np.clip(np.dot(v1_u, v2_u), -1.0, 1.0))

def get_grad_angle(grad,ref):
  ''' mean angle of all gradient components in deg'''
  import numpy as np
  g=np.reshape(grad,(3,-1))
  r=np.reshape(ref,(3,-1))
  dim=g.shape[1]
  angle=0.0
  for i in range(dim):
    angle+=np.degrees(np_angle(g[:,i],r[:,i]))
  return angle/dim


import numpy as np
from scipy.fftpack import fft
import matplotlib.pyplot as plt
from numpy import array
import sys
import os

file_name = sys.argv[1]
r_file = open(file_name, "r")
lines = r_file.readlines()

stripped = lines[3].strip()

data_in = stripped.split()
data_in = data_in[0:256]

for i in range(0,len(data_in)):
	data_in[i] = float(data_in[i])

### input data => np array conversion
fft_data_in = np.array(data_in)

### fft calculation
fft_data_complex = fft(fft_data_in)

### fft complex => real abs magnitude conversion
fft_data_abs = np.abs(fft_data_complex)

### fft abs magnitude => power spectral density conversion
fft_pden = np.square(fft_data_abs)/len(fft_data_abs)/len(fft_data_abs)

### fft plot range set ( 0~128) : 129ea
fft_pden = fft_pden[0:len(fft_pden)/2+1]

### fft => log conversion
fft_pden_log = 10*np.log10(fft_pden)

### max value find for normalization
fft_max_log=np.max(fft_pden_log[2:256])

### fft normalization to 0dB
fft_pden_log = fft_pden_log - fft_max_log

### plot fft
#plt.plot(fft_pden_log)
#plt.show()

fft_pden_sort = np.sort(fft_pden[1:])[::-1]

max_val = fft_pden_sort[0]
max_val_2nd = fft_pden_sort[1]
fft_sum = np.sum(fft_pden[1:])

sndr = 10*np.log10(max_val/(fft_sum-max_val-fft_pden[-1]/2))
sfdr = 10*np.log10(max_val/max_val_2nd)

print("sndr = %f\n"%sndr)
print("sfdr = %f\n"%sfdr)


import numpy as np
from scipy.optimize import minimize
from numpy.linalg import cholesky
from scipy.linalg import solve_triangular
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import animation, cm

def RBF(X1,X2,l,s):
    dist_norm = np.sum(X1**2, 1).reshape(-1, 1) + np.sum(X2**2, 1) - 2 * X1@X2.T
    return s**2*np.exp(-0.5*dist_norm/l**2)

def MLE(X_train,Y_train):
    Y_train = Y_train.ravel()
    def log_p(theta):
        K = RBF(X_train,X_train, theta[0], theta[1]) + theta[2]**2*np.eye(len(X_train))
        L = cholesky(K)
        A1 = solve_triangular(L, Y_train, lower=True)
        A2 = solve_triangular(L.T, A1, lower=False)
        objective =  np.sum(np.log(np.diagonal(L))) + 0.5 * Y_train.dot(A2) + 0.5*len(X_train) * np.log(2*np.pi)
        return objective
    return log_p

def plot_MLE_posterior_dist(gx,gy,X_train,Y_train,X_pred,theta,title):
    K = RBF(X_train,X_train, theta[0], theta[1]) + theta[2]**2*np.eye(len(X_train))
    L = cholesky(K)
    A1 = solve_triangular(L, Y_train, lower=True)
    A2 = solve_triangular(L.T, A1, lower=False)
    K_s = RBF(X_train,X_pred, theta[0], theta[1])
    mu = K_s.T@A2

    ax = plt.gcf().add_subplot(1, 1, 1, projection='3d')
    ax.plot_surface(gx, gy, mu.reshape(gx.shape), cmap=cm.jet, linewidth=0, alpha=0.35, antialiased=True)
    ax.scatter(X_train[:,0], X_train[:,1], Y_train, c=Y_train, cmap=cm.jet)
    ax.set_title(title)


import math

import numpy
import sympy

from ..helpers import article
from ._helpers import TetrahedronScheme

citation = article(
    authors=["P. Silvester"],
    title="Symmetric quadrature formulae for simplexes",
    journal="Math. Comp.",
    volume="24",
    pages="95-100",
    year="1970",
    url="https://doi.org/10.1090/S0025-5718-1970-0258283-6",
)

def _newton_cotes(n, point_fun):
    degree = n

    # points
    idx = numpy.array(
        [
            [i, j, k, n - i - j - k]
            for i in range(n + 1)
            for j in range(n + 1 - i)
            for k in range(n + 1 - i - j)
        ]
    )
    points = point_fun(idx, n)

    # weights
    if n == 0:
        weights = numpy.ones(1)
        return weights, points, weights, degree

    def get_poly(t, m, n):
        return sympy.prod(
            [
                sympy.poly((t - point_fun(k, n)) / (point_fun(m, n) - point_fun(k, n)))
                for k in range(m)
            ]
        )

    weights = numpy.empty(len(points))
    idx = 0
    for i in range(n + 1):
        for j in range(n + 1 - i):
            for k in range(n + 1 - i - j):
                L = n - i - j - k
                # Compute weight.
                # Define the polynomial which to integrate over the
                # tetrahedron.
                t = sympy.DeferredVector("t")
                g = (
                    get_poly(t[0], i, n)
                    * get_poly(t[1], j, n)
                    * get_poly(t[2], k, n)
                    * get_poly(t[3], L, n)
                )
                # The integral of monomials over a tetrahedron are well-known,
                # see Silvester.
                weights[idx] = numpy.sum(
                    [
                        c
                        * numpy.prod([math.factorial(k) for k in m])
                        * 6.0
                        / math.factorial(numpy.sum(m) + 3)
                        for m, c in zip(g.monoms(), g.coeffs())
                    ]
                )
                idx += 1
    return weights, points, degree, citation

def newton_cotes_closed(n):
    return TetrahedronScheme(
        f"Newton-Cotes (closed, {n})", *_newton_cotes(n, lambda k, n: k / float(n))
    )

def newton_cotes_open(n):
    scheme = TetrahedronScheme(
        f"Newton-Cotes (open, {n})",
        *_newton_cotes(n, lambda k, n: (k + 1) / float(n + 4)),
    )
    if n == 0:
        scheme.degree = 1
    return scheme


# Author: Meduri Venkata Shivaditya
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import minimize, line_search

def aokiFn(x):
    """
        F(x,y) = 0.5 x (x^2 - y)^2 + 0.5 x (x-1)^2
    """
    f = 0.5 * np.square(np.square(x[:][0]) - x[:][1]) + 0.5 * np.square(x[:][0] - 1)
    return f

def aoki(x):
    """
            F(x,y) = 0.5 x (x^2 - y)^2 + 0.5 x (x-1)^2
    """
    f = 0.5 * np.square(np.square(x[0]) - x[1]) + 0.5 * np.square(x[0] - 1)
    return f

def aoki_gd(x):
    """
            First-Order derivative of aoki function(Nabia - 1)
    """
    g_x = 2 * np.dot((np.square(x[0]) - x[1]), x[0]) + x[0] - 1
    g_y = -1 * (np.square(x[0]) - x[1])
    return np.array((g_x, g_y))

def aoki_hess(x):
    """
                Second-Order derivative - Hessian Matrix of aoki function(Nabia - 2)
    """
    g_xx = 6 * np.square(x[0]) - 2*x[1] + 1
    g_xy = -2 * x[0]
    g_yy = 1
    H = np.diag((2,2))
    H[0][0] = g_xx
    H[0][1] = g_xy
    H[1][0] = g_xy
    H[1][1] = g_yy
    return H
def gradient_descent(x0, f, f_prime, hessian=None, adaptative=False):
    """
                    Steepest-Descent algorithm with option for line search
    """
    x_i, y_i = x0
    all_x_i = list()
    all_y_i = list()
    all_f_i = list()

    for i in range(1, 100):
        all_x_i.append(x_i)
        all_y_i.append(y_i)
        all_f_i.append(f([x_i, y_i]))
        dx_i, dy_i = f_prime(np.asarray([x_i, y_i]))
        if adaptative:
            # Compute a step size using a line_search to satisfy the Wolf
            # conditions
            step = line_search(f, f_prime,
                                np.r_[x_i, y_i], -np.r_[dx_i, dy_i],
                                np.r_[dx_i, dy_i], c2=.05)
            step = step[0]
            if step is None:
                step = 0
        else:
            step = 1
        x_i += - step*dx_i
        y_i += - step*dy_i
        if np.abs(all_f_i[-1]) < 1e-16:
            break
    return all_x_i, all_y_i, all_f_i

def main():
    x1 = np.arange(0, 2, 0.1)
    x2 = np.arange(-0.5, 3, 0.1)
    x = np.meshgrid(x1, x2)
    z = aokiFn(np.array(x))
    plt.contour(x1, x2, z, 50)
    plt.plot(1, 1, 'go', MarkerSize=10)
    r = gradient_descent(np.array((0.0, 0.0)), aoki, aoki_gd, hessian = aoki_hess, adaptative = True)
    plt.scatter(r[0][:10], r[1][:10])
    plt.plot(r[0][:10], r[1][:10])
    plt.title('exact line search')
    plt.savefig("steepestDescentDemo.png", dpi = 300)
    plt.show()

if __name__ == "__main__":
    main()


# Class to setup root finding algorithm for practice. One could use
# the Scipy package for more optimized methods.

import numpy as np

class OptimalRoots(object):
    """
    Class to hold values from a root finding algorithm.

    Parameters
    ----------
    root_value: float
        Value of the root.
    func_value: float
        Value of the function.
        Should be close to 0.
    iteration: int
        Number of iterations.
    """

    def __init__(self, root_value, func_value, iteration):
        self.root_value = root_value
        self.func_value = func_value
        self.iteration = iteration

def brent(f, a, b, args=(), max_iteration=100, tolerance=1e-8):
    """
    Calculate roots using Brent's method.

    Parameters
    ----------
    f: function
        Objective function.
    a: float
        Lower bound for the roots.
    b: float
        Upper bound for the roots.
    args: tuple, optional
        Additional arguments for the function.
    max_iteration: int, optional
        Max number of iterations for the root finding algorithm.
    tolerance: float, optional
        Tolerance criteria for the root finding algorithm.

    Returns
    -------
    root_value: float
        Value of the root.
    func_value: float
        Value of the function.
        Should be close to 0.
    iteration: int
        Number of iterations.

    """

    # Calculate end points:
    fa = f(*((a,) + args))
    fb = f(*((b,) + args))

    # Check if fa is less than fb
    if abs(fa) < abs(fb):
        a, b = b, a
        fa, fb, = fb, fa

    # Create point c and d:
    c = a
    fc = fa
    d = 0.0

    # Loop until root found:
    loop_counter = 0
    mflag = 1

    while loop_counter <= max_iteration:
        # Update counter:
        loop_counter = loop_counter + 1

        # Update point:
        if (fa != fc) and (fb != fc):
            # Inverse quadratic interpolation:
            term_one = (a*fb*fc) / ((fa - fb)*(fa - fc))
            term_two = (b*fa*fc) / ((fb - fa)*(fb - fc))
            term_three = (c*fa*fb) / ((fc - fa)*(fc - fb))

            s = term_one + term_two + term_three
        else:
            # Secant method:
            s = b - (fb*(b - a)/(fb - fa))

        # Setup some conditions:
        between_numbers = np.sort([(3.0*a + b)/4.0, b])
        condition_one = (s < between_numbers[0]) and \
                        (s > between_numbers[1])
        condition_two = (mflag == 1) and \
                        (abs(s-b) >= (abs(b-c) * 0.5))
        condition_three = (mflag == 0) and \
                          (abs(s-b) >= (abs(c-d) * 0.5))
        condition_four = (mflag == 1) and (abs(b-c) < abs(tolerance))
        condition_five = (mflag == 0) and (abs(c-d) < abs(tolerance))

        # Check conditions:
        if condition_one or condition_two or condition_three or \
                condition_four or condition_five:
            # Bisection method:
            s = 0.5 * (a+b)
            mflag = 1
        else:
            mflag = 0

        # Calculate f(s):
        fs = f(*((s,) + args))

        # Update points:
        d = c
        c = b
        fc = fb

        if (fa * fs) < 0.0:
            b = s
            fb = fs
        else:
            a = s
            fa = fs

        # Check if fa is less than fb:
        if abs(fa) < abs(fb):
            a, b = b, a
            fa, fb, = fb, fa

        # Check convergence:
        if (abs(fb) <= tolerance) or (abs(fs) <= tolerance) or (
                abs(b-a) <= tolerance):
            return OptimalRoots(s, fs, loop_counter)

        if loop_counter == max_iteration:
            return OptimalRoots(s, fs, loop_counter)


"""
Version: 1.0
Last modified on: 17 November, 2014
Developers: Eduardo Nobre Luis, Fabricio Olivetti de Franca.
     email: eduardo_(DOT)_luis_(AT)_aluno_(DOT)_ufabc_(DOT)_edu_(DOT)_br
          : folivetti_(AT)_ufabc_(DOT)_edu_(DOT)_br
Based on source-code by Michael G. Epitropakis and Xiaodong Li
available at http://goanna.cs.rmit.edu.au/~xiaodong/cec15-niching/competition/
"""

import numpy as np
from numba.decorators import jit, autojit

@autojit
def sphere_func(x):
    return (x**2).sum()

@autojit
def rastrigin_func(x):
    return np.sum( (x**2)-(10.*np.cos( 2.*np.pi*x ))+10)

@autojit
def grienwank_func(x):
    i = np.sqrt(np.arange(x.shape[0])+1.0)
    return np.sum(x**2)/4000.0 - np.prod(np.cos(x/i)) + 1.0

@autojit
def weierstrass_func(x):
    alpha = 0.5
    beta = 3.0
    kmax = 20
    D = x.shape[0]

    c1 = alpha**np.arange(kmax+1)
    c2 = 2.0*np.pi*beta**np.arange(kmax+1)
    c = -D*np.sum(c1*np.cos(c2*0.5))

    C1 = np.tile(c1, (D,1))
    C2 = np.tile(c2, (D,1))
    X = np.reshape(np.repeat(x,kmax+1),(D,kmax+1)) + 0.5
    return (C1*np.cos(C2*X)).sum() + c

@autojit
def F8F2_func(x):
    f2 = 100.0 * ( (x[0]+1.0)**2 - x[1] - 1.0 )**2 + x[0]**2
    return 1.0 + (f2**2)/4000.0 - np.cos(f2)

@autojit
def FEF8F2_func(x):
    D = x.shape[0]
    fi = np.zeros(D)
    for i in np.arange(D-1):
        fi[i] = F8F2_func( (x[i],x[i+1]) )
    fi[D-1] = F8F2_func( (x[D-1],x[0]) )
    return fi.sum()
    '''
    return sum( F8F2_func(y) for y in zip( x[:D-1], x[1:D] ) ) + F8F2_func(
            (x[D-1],x[0]) )
    '''
@autojit
def RotMatrixCondition(D,c):
    A = np.random.randn( D, D )
    P,r = np.linalg.qr(A)
    A = np.random.randn( D, D )
    Q,r = np.linalg.qr(A)[0]
    u = np.random.rand(1,D)
    Dm = np.diag(c**( (u-np.min(u))(np.max(u)-np.min(u)) ))
    M = P.dot(Dm).dot(Q)
    return M

@autojit
def hybrid_comp( x, fn, f, o, sigma, lamb, bias, M ):

    D = x.shape[0]

    #criando w
    dx = x - o[:fn]
    w = np.exp(-(dx**2).sum(axis=1)/(2.0*D*sigma**2))
    '''
    w = np.zeros(fn)
    for i in range(fn):
        w[i] = np.exp(-np.sum( (x - o[i,:])**2 )/(2.0*D*sigma[i]**2))
    #w = np.array([ np.exp(-np.sum( (x - o[i,:])**2 )/(2.0*D*sigma[i]**2)) for i in range(fn) ])
    '''
    # cuidado aqui, como vamos alterar w, temos que armazenar o valor maximo, pois poderemos altera-lo
    # veja tambem que nao precisa do else!
    maxw = w.max()
    maxw10 = maxw**10 # para nao ter que calcular isso n vezes
    w[w != maxw] = w[w != maxw]*(1.0 - maxw10)
    w = w/w.sum()

    f_hat = np.zeros( fn )
    xx = np.ones(D)*5.0/lamb
    dx = dx/lamb

    for i in range(fn):
        f_hat[i] = f[i](dx[i,:].dot(M[i])) / f[i](xx[i,:].dot(M[i]))
    #f_hat = 2000.0*np.array([f[i](((x - o[i,:])/lamb[i,:]).dot(M[i])) / f[i]((xx/lamb[i,:]).dot(M[i])) for i in range(fn)])
    return -(2000*w*f_hat).sum()  # note que embora na documentacao ele retorna o valor positivo, no codigo exemplo eles retornam negativo


'''
This module provides functions for fitting
least-squares regression curves to water
level data.
'''

import datetime

import numpy as np
from matplotlib.dates import date2num

def polyfit(dates: list[datetime.datetime], levels: list[float],
        p: int = 3) -> tuple[np.poly1d, float, list[float]]:
    '''
    Finds a polynomial best-fit (least squares) curve to a given dataset.

    #### Arguments

    `dates` (list[datetime.datetime]): a list of dates where there is level data
    `levels` (list[float]): a list of level data points to fit
    `p` (int, default = 3): the degree of the polynomial curve to use

    #### Returns

    tuple[np.poly1d, float, list[float]]: the callable polynomial function, the constant
    offset used to shift the dates from their mean, and the original dates as numbers, respectively

    #### Raises

    `TypeError`: if inputs are not the specified type(s)
    `ValueError`: if degree is not integer
    '''

    # standard data type and bounds input checks
    if len(dates) != len(levels):
        raise ValueError(f'Inputs must be same length; sizes are {len(dates)} and {len(levels)}')
    if not all([isinstance(d, datetime.datetime) for d in dates]):
        raise TypeError('All dates must be datetime.datetime instances.')
    if not all([isinstance(lev, (float, int)) for lev in levels]):
        raise TypeError('All levels must be numbers.')
    if not (isinstance(p, int) and 0 <= p <= len(dates) - 1):
        raise ValueError('Polynomial degree must be integer, positive and less than the input length.')

    # convert datetime objects to floats
    date_nums = date2num(dates)

    # to minimise the size of the numbers inputted to np.polyfit, offset it by the mean of the dataset
    time_shift = np.mean(date_nums)
    p_coeff = np.polyfit(date_nums - time_shift * np.ones(len(date_nums)), levels, p)

    # convert to a callable polynomial function
    poly = np.poly1d(p_coeff)

    # return the polynomial, the shift and the input data (as floats)
    return (poly, time_shift, date_nums)

def moving_average(dates: list[datetime.datetime], levels: list[float],
        interval: int = 3) -> tuple[list[float], np.ndarray]:
    '''
    Calculates a moving average of the given data, extending the domain to use
    smaller intervals at the endpoints. If the interval is odd, the output domain
    will be the same; if the interval is even, the output domain will be at the
    midpoints of the original.

    #### Arguments

    `dates` (list[datetime.datetime]): list of dates where there is level data
    `levels` (list[float]): list of levels to be averaged
    `interval` (int, default = 3): symmetric window size over which to average

    #### Returns

    tuple[list[float], np.ndarray]: the new domain and averaged values at these points, respectively

    #### Raises

    `ValueError`: if interval is not between 1 and the input length
    '''

    if not (isinstance(interval, int) and 1 <= interval <= len(dates)):
        raise ValueError('Interval size must between 1 and the input length')

    date_nums = date2num(dates)

    # find the moving average, ignoring the ends
    averages = np.convolve(levels, np.ones(interval), mode='valid') / interval

    if interval % 2 == 1:
        # odd number of points: append original values to either end
        half_end = interval // 2
        averages = np.insert(averages, 0, levels[:half_end])
        averages = np.insert(averages, len(averages), levels[-1 * half_end:])
        return date_nums, averages

    else:
        # even number of points: append moving averages of the missing intervals to either end,
        # and move date values over by half an interval to account for this
        half_end = round((interval / 2) - 1)
        averages = np.insert(averages, 0, np.convolve(levels[:half_end + 1], (0.5, 0.5), mode='valid'))
        averages = np.insert(averages, len(averages),
            np.convolve(levels[-1 * half_end - 1:], (0.5, 0.5), mode='valid'))
        date_interval = date_nums[1] - date_nums[0]
        date_nums = [dn + date_interval / 2 for dn in date_nums]
        date_nums.pop()
        return date_nums, averages

def identify_potentially_bad_data(station_name: str, levels: list[float],
        data_origin_type: str = None, **kwargs: dict) -> set[str]:
    '''
    Check for suspicious values within a station's water level records. Tests for:

    1. If a level is given as a tuple instead of a float
    2. If negative (when not a tidal station) or extremely large values
    3. If the level fluctuates significantly between readings

    and returns appropriate warning messages or an empty set if there are none.

    #### Arguments

    `station_name` (str): string name of a station to be displayed. Does not have to be the official name.
    `levels` (list[float]): list of level data to be checked
    `data_origin_type` (str, default = None): either 'River Level', 'Tidal', 'Groundwater',
        'Rainfall', representing what this data input is from, or unspecified (None)

    #### Returns

    set[str]: a set of string messages detailing the potential errors in the data.
    '''

    NEGATIVE_LEVEL_TO_ZERO      = kwargs.get('negative_level_to_zero',      True)   # noqa
    REPLACE_TUPLE_WITH_INDEX    = kwargs.get('replace_tuple_with_index',    1)      # noqa
    TOO_HIGH_CUTOFF             = kwargs.get('too_high_cutoff',             2500)   # noqa
    TOO_HIGH_TO_PREVIOUS_LEVEL  = kwargs.get('too_high_to_previous_level',  True)   # noqa

    IS_TIDAL        = getattr(kwargs.get('station_obj', None), 'is_tidal', False)   # noqa

    flags = set()

    for i in range(len(levels)):

        # Check for erroneous case: level was a tuple instead of float
        if not isinstance(levels[i], (float, int)):

            if isinstance(correct_level := levels[i][REPLACE_TUPLE_WITH_INDEX], (float, int)):
                warn_str = f"Data for {station_name} station on date may be unreliable. "
                warn_str += f"Found water level value {levels[i]}. \n"
                warn_str += f"This has been replaced with {correct_level}."
                flags.add(warn_str)
                levels[i] = correct_level
            else:
                warn_str = f"Data for {station_name} station on date may be unreliable. "
                warn_str += f"Found water level value {levels[i]}. This item was \n"
                warn_str += "unable to be resolved into a numerical value, and has not been altered."
                flags.add(warn_str)

        # Check for potentially invalid values: negative or impossibly high
        if levels[i] < 0 and not IS_TIDAL:

            warn_str = f"Data for {station_name} station may be unreliable. "
            warn_str += "Some water levels were found to be negative, \nand this station is not tidal. "
            if NEGATIVE_LEVEL_TO_ZERO:
                warn_str += "These have been set to 0 m."
                levels[i] = 0

            flags.add(warn_str)

        if levels[i] > TOO_HIGH_CUTOFF and len(levels) >= 2:

            warn_str = f"Data for {station_name} station may be unreliable. "
            warn_str += f"Some water levels were found to be very high, above {TOO_HIGH_CUTOFF} m.\n"
            if TOO_HIGH_TO_PREVIOUS_LEVEL:
                warn_str += "These have been set to whatever the value before the spike."
                levels[i] = levels[i - 1]

            flags.add(warn_str)

    # Check for potentially invalid values: many sudden changes (allow for rainfall etc)
    if data_origin_type == 'River Level':
        if has_rapid_fluctuations(levels):

            warn_str = f"Data for {station_name} station may be unreliable. "
            warn_str += "There are many sudden spikes between consecutive measurements. \n"
            warn_str += "These values have not been altered."

            flags.add(warn_str)

    return flags

def has_rapid_fluctuations(levels: list[float], interval: int = 3, tol: float = 5e-3) -> bool:
    '''
    Applies a simple statistical estimate to check whether a
    dataset has rapid changes between values. Aims to allow daily
    cycles which are natural for tidal stations.

    The test applied is: mean squared error of the levels relative
    to the moving (interval-specified) average must be less than a
    (tol-specified) fraction of the squared mean level.

    #### Arguments

    `levels` (list[float]): list of level data to analyse
    `interval` (int, default = 3): the interval of the moving average used in the computation
    `tol` (float, default = 5e-3): the relative tolerance when compared to the mean square level

    #### Returns

    bool: True if there are rapid fluctuations detected; False otherwise
    '''

    import numpy as np

    lv = np.array(levels)
    _, avg = moving_average(*zip(*enumerate(levels)), interval)
    mse = ((lv - avg) ** 2).mean()

    return mse / (lv.mean() ** 2) >= tol


# -*- coding: utf-8 -*-
# author: ysoftman
# python version : 3.x
# desc : numpy 테스트

# pip install np
import numpy as np

# start=1 부터 stop=10 까지 num=20개 값을 균일하게 생성
l = np.linspace(1, 10, 20)
print(l)
# start=1 부터 stop=10 까지 num=20개 값을 균일하게 생성, int 값으로
l = np.linspace(1, 10, 20, dtype=int)
print(l)


import numpy as np

import pyfma

# See <https://www.johndcook.com/blog/2020/05/31/kahan-determinant/>
def test_determinant():
    a = np.pi
    b = np.e
    c = 355 / 113
    d = 23225 / 8544
    naive = a * d - b * c

    # This dot-product is hard to compute, cf.
    # ```
    # accupy.cond([np.pi, np.e], [23225 / 8544, -355 / 113])
    # ```
    # ```
    # 48525073.17687677
    # ```
    # When computing all values a,b,c,d with many digits,  mpmath and wolframalpha both
    # give the same result
    # ```
    # mp.fdot([mp.pi, mp.e], [mp.mpf("23225 / 8544"), -mp.mpf("355 / 113")])
    # https://www.wolframalpha.com/input/?i=det%28%5B%5Bpi%2C+e%5D%2C+%5B+355+%2F+113%2C+23225+%2F+8544%5D%5D%29
    # ```
    # ```
    # -7.0394408762183022632862048647535951845717763186391e-7
    # -7.039440876218302263286204864753595184571776388044517499102e-7
    # ```
    # When starting with the np/Python rounding of a,b,c,d, accupy and mpmath give the
    # same result:
    # ```
    # mp.fdot([np.pi, np.e], [23225 / 8544, -355 / 113])
    # accupy.fdot([np.pi, np.e], [23225 / 8544, -355 / 113]).item()
    # ```
    # ```
    # [-7.0394408]801519439901320097075016572198321233241348743e-7
    # [-7.0394408]80151944e-07
    # ```
    # (The brackets mark the correct digits.)
    # The naive computation gives
    # ```
    # -7.039440870215685e-07
    # ```
    # which actually isn't much further from the real value either.
    ref = -7.0394408762183022632862048647535951845717763186391e-7
    print("naive:", naive, naive - ref)
    assert abs(naive - ref) < 1.0e-8 * abs(ref)

    w = b * c
    e = pyfma.fma(-b, c, w)
    f = pyfma.fma(a, d, -w)
    kahan = f + e
    print("kahan:", kahan, kahan - ref)

    assert abs(kahan - ref) < 1.0e-9 * abs(ref)


"""
Tests for inequality.py

"""

import numpy as np
from numpy.testing import assert_allclose, assert_raises
from scipy.stats import linregress
from quantecon import lorenz_curve, gini_coefficient, \
     shorrocks_index, rank_size

def test_lorenz_curve():
    """
    Tests `lorenz` function, which calculates the lorenz curve

    An income distribution where everyone has almost the same wealth should
    be similar to a straight line

    An income distribution where one person has almost the wealth should
    be flat and then shoot straight up when it approaches one
    """
    n = 3000

    # Almost Equal distribution
    y = np.repeat(1, n) + np.random.normal(scale=0.0001, size=n)
    cum_people, cum_income = lorenz_curve(y)
    assert_allclose(cum_people, cum_income, rtol=1e-03)

    # Very uneven distribution
    y = np.repeat(0.001, n)
    y[4] = 100000
    pop_cum, income_cum = lorenz_curve(y)
    expected_income_cum = np.repeat(0., n + 1)
    expected_income_cum[-1] = 1.
    assert_allclose(expected_income_cum, income_cum, atol=1e-4)

def test_gini_coeff():
    """
    Tests how the function `gini_coefficient` calculates the Gini coefficient
    with the Pareto and the Weibull distribution.

    Analytically, we know that Pareto with parameter `a` has
    G = 1 / (2*a - 1)

    Likewise, for the Weibull distribution with parameter `a` we know that
    G = 1 - 2**(-1/a)

    """
    n = 10000

    # Tests Pareto: G = 1 / (2*a - 1)
    a = np.random.randint(2, 15)
    expected = 1 / (2 * a - 1)

    y = (np.random.pareto(a, size=n) + 1) * 2
    coeff = gini_coefficient(y)
    assert_allclose(expected, coeff, rtol=1e-01)

    # Tests Weibull: G = 1 - 2**(-1/a)
    a = np.random.randint(2, 15)
    expected = 1 - 2 ** (-1 / a)

    y = np.random.weibull(a, size=n)
    coeff = gini_coefficient(y)
    assert_allclose(expected, coeff, rtol=1e-01)

def test_shorrocks_index():
    """
    Test Shorrocks mobility index function against the example used in 'Wealth
    distribution and social mobility in the US: A quantitative approach'
    (Benhabib, Bisin, Luo, 2017).''
    https://www.econ.nyu.edu/user/bisina/RevisionAugust.pdf
    """

    # Construct the mobility matrix from Benhabib et al.
    P = [[0.222, 0.222, 0.215, 0.187, 0.081, 0.038, 0.029, 0.006],
         [0.221, 0.220, 0.215, 0.188, 0.082, 0.039, 0.029, 0.006],
         [0.207, 0.209, 0.210, 0.194, 0.090, 0.046, 0.036, 0.008],
         [0.198, 0.201, 0.207, 0.198, 0.095, 0.052, 0.040, 0.009],
         [0.175, 0.178, 0.197, 0.207, 0.110, 0.067, 0.054, 0.012],
         [0.182, 0.184, 0.200, 0.205, 0.106, 0.062, 0.050, 0.011],
         [0.123, 0.125, 0.166, 0.216, 0.141, 0.114, 0.094, 0.021],
         [0.084, 0.084, 0.142, 0.228, 0.170, 0.143, 0.121, 0.028]]

    expected = 0.98  # result from paper
    index = shorrocks_index(P)
    assert_allclose(expected, index, rtol=1e-2)

def test_rank_size():
    """
    Tests `rank_size` function, which generates rank-size data for
    a Pareto distribution.

    The rank-size plot for a sample drawn from a Pareto distribution
    should be a straight line.

    The length of the `rank_data` array should be within (c x 100)%
    of the size of the distribution.
    """

    np.random.seed(15)
    sample_size = 10000
    c = 0.74

    # Tests Pareto; r_squared ~ 1
    pareto_draw = np.exp(np.random.exponential(scale=1.0, size=sample_size))
    rank_data, size_data = rank_size(pareto_draw, c=c)

    assert len(rank_data) == len(size_data)
    assert_allclose(c*sample_size, len(rank_data), rtol=1e-3)

    _, _, r_value, _, _ = linregress(np.log(rank_data), np.log(size_data))
    r_sqval = r_value**2

    assert_allclose(r_sqval, 1, rtol=1e-3)

    # Tests Exponential; r_squared < 1
    z = np.random.randn(sample_size)

    exp_draw = np.exp(z)
    rank_data_exp, size_data_exp = rank_size(exp_draw, c=c)

    _, _, r_value_exp, _, _ = linregress(np.log(rank_data_exp),
                                         np.log(size_data_exp))
    r_sqval_exp = r_value_exp**2

    assert_raises(AssertionError, assert_allclose, r_sqval_exp, 1, rtol=1e-3)


import numpy

def compute_fundamental(x1, x2):
  '''Computes the fundamental matrix from corresponding points x1, x2 using
  the 8 point algorithm.'''
  n = x1.shape[1]
  if x2.shape[1] != n:
    raise ValueError('Number of points do not match.')

  # Normalization is done in compute_fundamental_normalized().
  A = numpy.zeros((n, 9))
  for i in range(n):
    A[i] = [x1[0, i] * x2[0, i],  x1[0, i] * x2[1, i],  x1[0, i] * x2[2, i],
            x1[1, i] * x2[0, i],  x1[1, i] * x2[1, i],  x1[1, i] * x2[2, i],
            x1[2, i] * x2[0, i],  x1[2, i] * x2[1, i],  x1[2, i] * x2[2, i],
           ]

  # Solve A*f = 0 using least squares.
  U, S, V = numpy.linalg.svd(A)
  F = V[-1].reshape(3, 3)

  # Constrain F to rank 2 by zeroing out last singular value.
  U, S, V = numpy.linalg.svd(F)
  S[2] = 0
  F = numpy.dot(U, numpy.dot(numpy.diag(S), V))
  return F / F[2, 2]

def compute_fundamental_normalized(x1, x2):
  '''Computes the fundamental matrix from corresponding points x1, x2 using
  the normalized 8 point algorithm.'''
  n = x1.shape[1]
  if x2.shape[1] != n:
    raise ValueError('Number of points do not match.')

  # normalize.
  x1 = x1 / x1[2]
  mean_1 = numpy.mean(x1[:2], axis=1)
  S1 = numpy.sqrt(2) / numpy.std(x1[:2])
  T1 = numpy.array([[S1, 0, -S1 * mean_1[0]],
                    [0, S1, -S1 * mean_1[1]],
                    [0, 0, 1]])
  x1 = numpy.dot(T1, x1)

  x2 = x2 / x2[2]
  mean_2 = numpy.mean(x2[:2], axis=1)
  S2 = numpy.sqrt(2) / numpy.std(x2[:2])
  T2 = numpy.array([[S2, 0, -S2 * mean_2[0]],
                    [0, S2, -S2 * mean_2[1]],
                    [0, 0, 1]])
  x2 = numpy.dot(T2, x2)

  F = compute_fundamental(x1, x2)

  # denormalize.
  F = numpy.dot(T1.T, numpy.dot(F, T2))
  return F / F[2, 2]

def compute_right_epipole(F):
  '''Returns e with F * e = 0 (call with F.T for left epipole).'''
  U, S, V = numpy.linalg.svd(F)
  e = V[-1]  # S is diag([l1, l2, 0]). e's scale is arbitrary.
  return e / e[2]

def plot_epipolar_line(im, F, x, epipole=None, show_epipole=True):
  '''Plot the epipole and epipolar line F*x = 0.'''
  import pylab

  m, n = im.shape[:2]
  line = numpy.dot(F, x)

  t = numpy.linspace(0, n, 100)
  lt = numpy.array([(line[2] + line[0] * tt) / (-line[1]) for tt in t])

  ndx = (lt >= 0) & (lt < m)
  pylab.plot(t[ndx], lt[ndx], linewidth=2)

  if show_epipole:
    if epipole is None:
      epipole = compute_right_epipole(F)
    pylab.plot(epipole[0] / epipole[2], epipole[1] / epipole[2], 'r*')

def triangulate_point(x1, x2, P1, P2):
  '''Given two image coordinates x1, x2 of the same point X under different
  projections P1, P2, recovers X.'''
  M = numpy.zeros((6, 6))
  M[:3, :4] = P1
  M[:3, 4] = -x1

  M[3:, :4] = P2
  M[3:, 5] = -x2  # Intentionally 5, not 4.

  U, S, V = numpy.linalg.svd(M)
  X = V[-1, :4]
  return X / X[3]

def triangulate(x1, x2, P1, P2):
  '''Given n pairs of points, returns their 3d coordinates.'''
  n = x1.shape[1]
  if x2.shape[1] != n:
    raise ValueError('Number of points do not match.')

  X = [triangulate_point(x1[:, i], x2[:, i], P1, P2) for i in range(n)]
  return numpy.array(X).T

def compute_P(x, X):
  '''Computes camera matrix from corresponding (homogeneous)
  2D and 3D points.'''
  n = x.shape[1]
  if X.shape[1] != n:
    raise ValueError('Number of points do not match.')

  M = numpy.zeros((3 * n, 12 + n))
  for i in range(n):
    M[3 * i          , 0:4] = X[:, i]
    M[3 * i + 1      , 4:8] = X[:, i]
    M[3 * i + 2      , 8:12] = X[:, i]
    M[3 * i:3 * i + 3, i + 12] = -x[:, i]

  U, S, V = numpy.linalg.svd(M)
  return V[-1, :12].reshape((3, 4))

def skew(a):
  '''Skew matrix A such that a x v = A*v for any v.'''
  return numpy.array([[0, -a[2], a[1]],
                      [a[2], 0, -a[0]],
                      [-a[1], a[0], 0]])

def compute_P_from_fundamental(F):
  '''Computes second camera matrix, assuming P1 = [I 0].
  Only up to a homography, since no calibration is given.'''
  e = compute_right_epipole(F.T)  # left epipole
  Te = skew(e)
  return numpy.vstack((numpy.dot(Te, F.T).T, e)).T

def compute_P_from_essential(E):
  # make sure E is rank 2
  U, S, V = numpy.linalg.svd(E)
  if numpy.linalg.det(numpy.dot(U, V)) < 0:
    V = -V
  E = numpy.dot(U, numpy.dot(numpy.diag([1, 1, 0]), V))

  # create matrices ("Hartley p 258" XXX)
  Z = skew([0, 0, -1])  # FIXME: Unused?
  W = numpy.array([[0, -1, 0], [1, 0, 0], [0, 0, 1]])

  P2 = [numpy.vstack((numpy.dot(U, numpy.dot(W, V)).T,  U[:,2])).T,
        numpy.vstack((numpy.dot(U, numpy.dot(W, V)).T, -U[:,2])).T,
        numpy.vstack((numpy.dot(U, numpy.dot(W.T, V)).T,  U[:,2])).T,
        numpy.vstack((numpy.dot(U, numpy.dot(W.T, V)).T, -U[:,2])).T]
  return P2

class RansacModel(object):
  def fit(self, data):
    data = data.T
    x1 = data[:3, :8]
    x2 = data[3:, :8]
    return compute_fundamental_normalized(x1, x2)

  def get_error(self, data, F):
    data = data.T
    x1 = data[:3]
    x2 = data[3:]

    # Sampson distance as error.
    Fx1 = numpy.dot(F, x1)
    Fx2 = numpy.dot(F, x2)
    denom = Fx1[0]**2 + Fx1[1]**2 + Fx2[0]**2 + Fx2[1]**2
    err = (numpy.diag(numpy.dot(x1.T, numpy.dot(F, x2))))**2 / denom
    return err

def F_from_ransac(x1, x2, model, maxiter=5000, match_threshold=1e-6):
  import ransac
  data = numpy.vstack((x1, x2))
  F, ransac_data = ransac.ransac(data.T, model, 8, maxiter, match_threshold, 20,
                                 return_all=True)
  return F, ransac_data['inliers']


import numpy as np

class GaussianMLE(object):
    # http://www.sciencedirect.com/science/article/pii/0024379585900497
    def __init__(self, X):
        # X is a numpy array of size (observations) x (variables)
        self.X = X
        self.N = X.shape[1]
        self.M = X.shape[0]
        self.mu = np.zeros(X.shape[1], dtype=np.float)
        self.sigma = np.zeros((X.shape[1],X.shape[1]), dtype=np.float)
        self.fit = False
        # index mask for conditional probability
        self.mask = np.ones(X.shape[1], dtype=bool)
        self.reverse_mask = np.zeros(X.shape[1], dtype=bool)
        self.conditional_fit = False

    def _mean(self):
        # estimate the sample mean for each variable
        mean = np.mean(self.X, axis=0, dtype=np.float)
        self.mu = mean
        return mean

    def _sigma(self):
        # estimate the variance covariance matrix
        diffs = self.X - self.mu
        dot = np.dot(diffs.T, diffs)
        sigma = dot/self.M
        self.sigma = sigma
        return sigma

    def estimate(self):
        # estimate the distribution
        self._mean()
        self._sigma()
        print('Multivariate Gaussian distribution fit with MLE')
        print('The mean vector shape is:')
        print(self.mu.shape)
        print('The variance-covariance matrix shape is:')
        print(self.sigma.shape)
        self.fit = True

    def draw(self, size=1):
        # generate a random draw from the estimated distribution
        if not self.fit:
            self.estimate()
        return np.random.multivariate_normal(self.mu, self.sigma, size)

    def _conditional_sigma(self):
        # want to partition the variance covariance matrix into
        # dependent and indepenedent var covar parts

        ind_ind = self.sigma[self.mask, :][:, self.mask]
        dep_dep = self.sigma[self.reverse_mask, :][:, self.reverse_mask]
        ind_dep = self.sigma[self.mask, :][:, self.reverse_mask]
        dep_ind = self.sigma[self.reverse_mask, :][:, self.mask]

        # pseudo inverse
        invert_ind_ind = np.linalg.pinv(ind_ind)

        self.conditional_sigma = dep_dep - np.dot(dep_ind, np.dot(invert_ind_ind, ind_dep))
        return self.conditional_sigma

    def _conditional_mean(self, independent):
        # create conditional mean

        # partition means
        dep_means = self.mu[self.reverse_mask]
        ind_means = self.mu[self.mask]

        # slice var covar
        dep_ind = self.sigma[self.reverse_mask, :][:, self.mask]
        ind_ind = self.sigma[self.mask, :][:, self.mask]
        # pseudo inverse
        invert_ind_ind = np.linalg.pinv(ind_ind)

        diff = independent - ind_means

        cond_mean = dep_means + np.dot(dep_ind, np.dot(invert_ind_ind, diff))
        self.conditional_mu = cond_mean
        return cond_mean

    def conditional_estimate(self, dependent, independent):
        # estimate a conditional distribution
        # <dependent> is the list of indices of variables that are to be drawn
        # <independent> is np array of realizations of the variables that <dependent>
        # are being conditioned on

        assert len(independent) + len(dependent) == self.N

        self.mask[dependent] = False
        self.reverse_mask = np.logical_xor(np.ones(self.X.shape[1], dtype=bool), self.mask)

        if not self.fit:
            self.estimate()

        self._conditional_sigma()
        self._conditional_mean(independent)

        print('The conditional distribution estimated. The conditional means are:')
        print(self.conditional_mu)
        print('The conditional var-covar matrix is:')
        print(self.conditional_sigma)

        self.conditional_fit = True

    def conditional_draw(self, size=1):
        # generate a random draw from the estimated conditional distribution
        if not self.conditional_fit:
            raise RuntimeError('Conditional distribution not estimated yet')
        return np.random.multivariate_normal(self.conditional_mu, self.conditional_sigma, size)