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

"""
Some common functions shared by many voting systems
"""
import numpy as np

def droop_quota(votes, seats):
    """
    Threshold of votes required to get elected for STV.

    Parameters
    -----------
    votes : int
        Total number of votes cast in election
    seats : int
        Total number of seats needed to be filled.

    Returns
    -------
    out : int
        Droop quota; number of votes required to get elected.
    """

    return int(np.floor(votes / (seats + 1)) + 1)

def hare_quota(votes, seats):
    return int(np.ceil(votes / seats))

def winner_check(results, numwin=1):
    """
    Check for winner and handle ties, considering results, where the greatest
    result results in a win.

    This function is used as a fundamental building block for other voting
    methods suchas plurality, score, STAR, etc.

    Parameters
    ----------
    results : array of shape (a,)
        Result quantities for `a` # of candidates. Candidate index with
        the greatest result wins.

        - Each element is the candidate "score" as int or float.
        - Set an element to np.NAN to ignore a particular candidate.
    numwin : int
        Number of winners to return

    Returns
    -------
    winners : array of shape(b,)
        Index locations of each winner.
          - b = `numwin` if no ties detected
          - b > 1 if ties are detected.
    ties : array of shape (c,)
        Index locations of ties

    Example
    ---------
    We have run a plurality election for 4 candidates. The final tallies
    for each candidate are

    >>> counts = [2, 10, 4, 5]

    To determine the index location of the winner, use

    >>> w, t = winner_check(counts, numwin=1)
    """
    if numwin > 1:
        return _multi_winners_check(results, numwin=numwin)

    # dummy, empty output array
    a = np.array([], dtype=int)
    sums = np.array(results)
    try:
        imax = np.nanargmax(sums)
    # Error occurs if all sums is NAN. If so, no winner, all ties.
    except ValueError:
        return a, np.arange(len(results))

    iscore = sums[imax]
    winners = np.where(sums == iscore)[0]
    wnum = len(winners)

    if wnum > 1:
        return a, winners
    elif wnum == 1:
        return winners, a
    else:
        raise RuntimeError('This state should not have been reached....')

def _multi_winners_check(results, numwin=1):
    """
    Multi-winner version of winner_check; see `winner_check` for arguments
    """
    results = np.array(results, copy=True, dtype='float64')

    # Get the ranking
    ranking = np.argsort(results)[::-1]

    # Filter out np.NAN
    ikeep = ~np.isnan(results)
    ikeep = ikeep[ranking]
    ranking = ranking[ikeep]

    winners = []
    ikeepnum = np.sum(ikeep)

    if numwin > ikeepnum:
        raise ValueError('Number of winners exceeds valid candidates of %s' % ikeepnum )

    # Loop through number of winners.
    for j in range(numwin):
        winners_left = numwin - len(winners)
        candidate = ranking[j]
        cvotes = results[candidate]

        ties = np.where(cvotes == results)[0]
        tienum = len(ties)
        if tienum > winners_left:
            return np.array(winners, dtype=int), ties
        winners.append(candidate)

        # After winner has been added to list, set np.nan as his votes
        results[candidate] = np.nan

    ties = np.array([], dtype=int)
    winners = np.array(winners)
    return winners, ties

#
#def result_rankings(results):
#    """
#    Sort the results into winning ranks
#    """
#
#    results = np.array(results, copy=True)
#    isort = np.argsort(results)[::-1]
#    results_unique = np.unique(results)
#
#    for ru in results_unique:
#

def winner_check_named(results, candidates: list, numwin: int=1):
    """Check winners variant for named candidates from a list.

    Parameters
    ----------
    results : ndarray
        Result quantities for `a` # of candidates. Candidate index with
        the greatest result wins.

        - Each element is the candidate "score" as int or float.
        - Set an element to np.NAN to ignore a particular candidate.

    candidates : ndarray
        Candidate names.
    numwin : int, optional
        Number of winners to return. The default is 1.

    Returns
    -------
    winners : array of shape(b,)
        Names of each winner
          - b = `numwin` if no ties detected
          - b > 1 if ties are detected.
    ties : array of shape (c,)
        Names of tie candidates
    """
    candidates = np.array(candidates)
    winners, ties = winner_check(results, numwin=numwin)
    win_candidates = candidates[winners]
    tie_candidates = candidates[ties]
    return win_candidates, tie_candidates

def run_with_eliminated(
        func,
        eliminated: list,
        data: np.ndarray,
        numwin: int=1,
        **kwargs):
    """Run election method with list of eliminated candidates.

    Parameters
    ----------
    func : function
        Election method
    eliminated: list[int]
        List of eliminated candidate indices
    data : ndarray (a, b)
        Ballot data for `a` voters and `b` candidates
    numwin : int
        Number of winners to find.

    Returns
    -------
    winners : ndarray (c,)
        Winner candidate indices
    ties : ndarray (t,)
        Tie candidates indices
    outputs : dict
        data output dict
    """
    num_candidates = data.shape[1]

    cbools = np.ones(num_candidates, dtype=bool)
    cbools[eliminated] = False
    cindex = np.where(cbools)[0]

    data1 = data[:, cindex]
    winners1, ties1, output1 = func(data1, numwin=numwin, **kwargs)

    winners = cindex[winners1]
    ties = cindex[ties1]
    return winners, ties, output1

def multi_win_eliminate(func, data, numwin=1, **kwargs):
    """Convert single winner method to multi-winner method,
    using candidate elimination."""
    winners = []
    num_left = numwin
    data = data.copy()
    outputs = []
    ties = []
    while num_left > 0:

        winners_ii, ties_ii, output_ii = run_with_eliminated(
            func,
            winners,
            data,
            numwin=1,
            **kwargs)

        outputs.append(output_ii)
        winner_len = len(winners_ii)
        tie_len = len(ties_ii)

        # Check if single winner has been found
        if winner_len == 1:
            winners_ii = winners_ii[0]
            winners.append(winners_ii)

        elif winner_len == 0:
            # Check if ties have been found, but there are enough
            # slots left to fill them in as winners.
            if num_left >= tie_len:
                winners.extend(ties_ii)

            # Check for ties, but there are no slots left for them all.
            elif tie_len > 1:
                ties = ties_ii
                break

        num_left = numwin - len(winners)

    winners = np.array(winners, dtype=int)
    if len(ties) > 0:
        ties = np.asarray(ties, dtype=int)
    else:
        ties = np.array([], dtype=int)
    return winners, ties, outputs

def multi_win_eliminate_decorator(func):
    """Decorator to convert single winner method to multi-winner method,
    using candidate elimination."""

    def func2(data, numwin=1, **kwargs):
        if numwin == 1:
            return func(data, numwin=numwin, **kwargs)

        winners, ties, out1 = multi_win_eliminate(
            func,
            data,
            numwin = numwin,
            **kwargs
        )
        output = out1[0].copy()
        output['elimination_rounds'] = out1
        return winners, ties, output

    return func2

def rcv_reorder(data):
    """Make sure rankings are sequential integers from [1 to b],
    with 0 meaning eliminated or unranked.

    Parameters
    ----------
    data : array shaped (a, b)
        Election voter rankings, from [1 to b].
        Data composed of candidate rankings, with

           - Voters as the rows
           - Candidates as the columns.

    Returns
    --------
    out : array shaped (a,b)
        Conversion of scores to integer ranked sequenced data from [1 to b].
    """
    data = np.copy(data)
    max_rank = np.max(data)
    unranked = (data == 0)
    data[unranked] = max_rank + 10

    # Need to argsort twice to sort and then unsort but retain integer increments.
    data = np.argsort(np.argsort(data, axis=1), axis=1) + 1
    data[unranked] = 0
    return data

def score2rank(data, cutoff=None):
    """
    Convert scores or ratings to rankings starting from 1.

    Parameters
    -----------
    data : array shaped (a, b)
        Election voter rating, 0 to max.
        Data composed of candidate ratings, with

           - `a`-number of Voters as the rows
           - `b`-number of Candidates as the columns.

        Use 0 to specify unranked (and therefore not to be counted) ballots.

         - a : number of voters dimension.
         - b : number of candidates. A score is assigned for each
               candidate from 0 to b-1.
    cutoff : None or float
        If float, specify a cutoff rating where ratings below this value are
        unranked as ranking=0.

    Returns
    -------
    rank : array shaped (a, b)
        Election rankings of each voter for each candidate

        - a : voters dimension
        - b : candidates dimension

    """
    data = np.array(data)
    izero = data <= 0

    i = np.argsort(np.argsort(-data, axis=1), axis=1) + 1
    i[izero] = 0

    if cutoff is not None:
        ic = data <= cutoff
        i[ic] = 0

    return i

def getplurality(ratings=None, ranks=None):
    """
    Retrieve first-choice plurality votes, given either ratings or rankings data

    Parameters
    ----------
    ratings : array shape (a, b)
        Ratings data. Mutually exlusive with ranks
    ranks : array shape (a, b)
        Rankings data. Mutually exclusive with ratings

    Returns
    --------
    out : array shape (a, b)
        Rank/ratings data converted into single-vote plurality ballots.

    """
    # convert possible cardinal data to a single choice.
    if ranks is not None:
        return (ranks==1).astype(int)
    elif ratings is not None:
        data = np.atleast_2d(ratings)
        new = np.zeros(data.shape)
        i0 = np.arange(data.shape[0])
        i1 = np.argmax(data, axis=1)

        index_blanks = data == 0
#        logger.debug('i0 = %s', i0)
#        logger.debug('i1 = %s', i1)
        new[i0, i1] = 1
        new[index_blanks] = 0

        return new

def handle_ties(winners, ties, numwinners, rstate=None):
    """If ties are found, choose random tied candidate to break tie

    Parameters
    ----------
    winners : array shaped (a,)
        Winning candidate indices
    ties : array shaped (b,)
        Candidates that almost won but have received a tie with other candidates.
    numwinners : int
        Total number of required winners for this election

    Returns
    --------
    winner : array shaped (numwinners,)
        Winners of election. Tie-broken by random choice.
    """
    assert len(winners) + len(ties) > 0, 'Empty winner and ties input.'

    if rstate is None:
        rstate = np.random.RandomState

    winners = np.array(winners)
    num_found = len(winners)
    num_needed =  numwinners - num_found

    if num_needed > 0:

        new = rstate.choice(ties, size=num_needed, replace=False)
        winners = np.append(winners, new)
    return winners.astype(int)


import numpy as np

def softmax(x):
    if x.ndim == 2:
        x = x.T
        x = x - np.max(x, axis=0)
        y = np.exp(x) / np.sum(np.exp(x), axis=0)
        return y.T

    x = x - np.max(x)
    return np.exp(x) / np.sum(np.exp(x))

def mean_squared_error(y, t):
    return 0.5 * np.sum((y-t)**2)

def cross_entropy_error(y, p):
    if p.ndim == 1:
        y = y.reshape(1, y.size)
        p = p.reshape(1, p.size)

    if y.size == p.size:
        y = y.argmax(axis=1)

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

def numerical_gradient(f, x):
    h = 1e-4
    grad = np.zeros_like(x)

    it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite'])
    while not it.finished:
        idx = it.multi_index
        tmp_val = x[idx]
        x[idx] = float(tmp_val) + h
        fxh1 = f(x)

        x[idx] = tmp_val - h
        fxh2 = f(x)
        grad[idx] = (fxh1 - fxh2) / (2*h)

        x[idx] = tmp_val
        it.iternext()

    return grad


import numpy as np
from scipy import stats

# 1-sample t-test

# sample size 10 from normal distribution
A = np.random.normal(500,200,10)

# null hypothesis: mu = 600
t,p = stats.ttest_1samp(A, popmean=600)

print(p)

if p < 0.05:
  print('Reject the null hypothesis')
else:
  print('Fail to reject')

# 2-sample t-test
# does not assume same sample size or variance
# (welch's t-test)

# DE = [700, 1200, 800, 1000, 1100, 1500, 1200, 1600, 1300, 1200]
# ES = [400, 1000, 2000, 1400, 1700, 1100, 1300, 1500, 1400, 1600]

# print(np.mean(DE))
# print(np.mean(ES))

# # null hypothesis: mu_A = mu_B
# t,p = stats.ttest_ind(DE, ES, equal_var=False)

# if p < 0.05:
#   print('Reject the null hypothesis')
# else:
#   print('Fail to reject')

# Mann-Whitney U test, nonparametric, independent samples

# DE = [700, 1200, 800, 1000, 1100, 1500, 1200, 1600, 1300, 1200]*3
# ES = [400, 1000, 2000, 1400, 1700, 1100, 1300, 1500, 1400, 1600]*3

# # null hypothesis: the distributions are the same
# # alternatives: 'less', 'greater', or 'two-sided'
# U,p = stats.mannwhitneyu(DE, ES, alternative='less')
# print(p*2)

# if p*2 < 0.05:
#   print('Reject the null hypothesis')
# else:
#   print('Fail to reject')


#!/Users/marc/miniconda3/bin/python3

import math
import numpy as np

def sphere_vertices( n ):
    phistep = math.pi / n
    thetastep = 2*math.pi / n
    vertices = []

    for i in range( n+1 ):
        phi = - math.pi/2 + i * phistep
        if i == 0:
            tb = 'bottom'
        elif i==n:
            tb = 'top'
        else:
            tb = False
        for j in range( n ):
            theta = j * thetastep
            face = sphere_face( phi, theta, phi+phistep, theta+thetastep, tb )
            vertices.extend( face )

    #vertices = [item for sublist in vertices for item in sublist]
    return np.array( vertices, dtype=np.float32)

def sphere_face( phi0, theta0, phi1, theta1, tb ):

    x0 = .5*math.cos(theta0) * math.cos(phi0)
    x1 = .5*math.cos(theta0) * math.cos(phi1)
    x2 = .5*math.cos(theta1) * math.cos(phi1)
    x3 = .5*math.cos(theta1) * math.cos(phi0)

    y0 = .5*math.sin(theta0) * math.cos(phi0)
    y1 = .5*math.sin(theta0) * math.cos(phi1)
    y2 = .5*math.sin(theta1) * math.cos(phi1)
    y3 = .5*math.sin(theta1) * math.cos(phi0)

    z0 = .5*math.sin(phi0)
    z1 = .5*math.sin(phi1)

    if tb == 'bottom':
        return [ x0,y0,z0, theta0/(2*math.pi), (phi0+math.pi/2)/math.pi,
                 x1,y1,z1, theta0/(2*math.pi), (phi1+math.pi/2)/math.pi,
                 x2,y2,z1, theta1/(2*math.pi), (phi1+math.pi/2)/math.pi, ]
    elif tb == 'top':
        return [ x0,y0,z0, theta0/(2*math.pi), (phi0+math.pi/2)/math.pi,
                 x3,y3,z0, theta1/(2*math.pi), (phi0+math.pi/2)/math.pi,
                 x2,y2,z1, theta1/(2*math.pi), (phi1+math.pi/2)/math.pi ]
    else:
        return  [x0,y0,z0, theta0/(2*math.pi), (phi0+math.pi/2)/math.pi,
                 x1,y1,z1, theta0/(2*math.pi), (phi1+math.pi/2)/math.pi,
                 x2,y2,z1, theta1/(2*math.pi), (phi1+math.pi/2)/math.pi,
                 x0,y0,z0, theta0/(2*math.pi), (phi0+math.pi/2)/math.pi,
                 x3,y3,z0, theta1/(2*math.pi), (phi0+math.pi/2)/math.pi,
                 x2,y2,z1, theta1/(2*math.pi), (phi1+math.pi/2)/math.pi  ]

if __name__ == "__main__":
    sphere = sphere_vertices( 3 )
    np.set_printoptions(precision=3, suppress=True, linewidth=110)
    print(sphere)
    print("Faces: ", len(sphere)/3)


import numpy as np
from matplotlib import pyplot as plt

def NormalD(x, _mean, _var):
    return np.exp(-0.5 * ((x-_mean)/np.sqrt(_var))**2)/(np.sqrt(2*np.pi*_var))

def CreateRandomVar(_n):
    return np.random.rand(1, _n)[0, :]

def MeanOfArray(_array):
    _sum = 0
    for i in _array:
        _sum += i
    return _sum / len(_array)

def VarOfArray(_array):
    sum = 0
    for i in _array:
        sum += i**2
    return (sum / len(_array)) - (MeanOfArray(_array)**2)

def DrawMeanGraph(_n):
    values = []
    vars = CreateRandomVar(_n)
    sum = 0
    for i in range(int(_n)):
        sum += vars[i]
        values.append(sum / (i+1))
    x = list(range(0, _n))
    plt.xlabel("N")
    plt.ylabel("Mean")
    plt.title("Mean of N Times Iterated Uniform Random Variable Graph.")
    plt.plot(x, values, label="Means")

def DrawGaussianGraphs(_n, _color):
    array = np.sort(CreateRandomVar(_n))
    mean = MeanOfArray(array)
    var = VarOfArray(array)
    values = []
    for i in array:
        values.append(NormalD(i, mean, var))

    plt.xlabel("N")
    plt.ylabel("Probability Density")
    plt.plot(array, values, label="Gaussian Distribution " + str(_n) + " Iteration", color=_color)

def DrawGaussianGraphWBar(_n, _color):
    array = np.sort(CreateRandomVar(_n))
    mean = MeanOfArray(array)
    var = VarOfArray(array)
    values = []
    for i in array:
        values.append(NormalD(i, mean, var))
    barInterval = np.arange(array[0], array[-1], (array[-1] - array[0]) / _n)
    plt.bar(barInterval, values, (array[-1] - array[0]) / _n, color="none", edgecolor="black")
    plt.title("N : " + str(_n))
    plt.xlabel("N")
    plt.ylabel("Probability Density")
    plt.plot(array, values, label="Gaussian Distribution " + str(_n) + " Iteration", color=_color)

n = []
colors = ["red", "blue", "green"]

print("[Choose]\n[1] Draw Mean Graph\n[2] Draw Gaussian Graphs On Same Plot\n[3] Draw Gaussain Graph With Bar Graph")
choice = input("Choice: ")

if choice == "1":
    print("[N] number of iteration.\n")
    n.append(input("N: "))
    DrawMeanGraph(int(n[0]))
elif choice == "2":
    print("[Number of Graph]\n[1]\n[2]\n[3]\n")
    graphCount = input("Number of Graph: ")

    print("[N] number of iterations.\n")
    for i in range(int(graphCount)):
        n.append(input("N" + str(i+1) + ": "))

    for i in range(int(graphCount)):
        DrawGaussianGraphs(int(n[i]), colors[i])
elif choice == "3":
    print("[N] number of iterations.\n")
    n.append(input("N: "))
    DrawGaussianGraphWBar(int(n[0]), colors[0])
else:
    quit()

plt.show()


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

"""
Goal: Solve dXt = b(t, Xt)dt + sigma(t, Xt)dWt

Variable Description:

num_sims: number of simulations
t_init: start time
t_end: end time
t_step: size of the time step
x_init: initial value of x
b: function b(t, xt)
sigma: function sigma(t, xt)

"""

import numpy as np
import matplotlib.pyplot as plt

def SDE(num_sims, t_init, t_end, t_step, x_init, b, sigma):

    def dW(delta_t):
        """Sample the increment of Wiener Process"""
        return np.random.normal(loc=0.0, scale=np.sqrt(delta_t))

    ts = np.arange(t_init, t_end, t_step) # t array
    xs = np.zeros(ts.size) # x array

    xs[0] = x_init # initial value of x

    for _ in range(num_sims):
        for i in range(1, ts.size):
            t = (i-1) * t_step
            x = xs[i-1]
            xs[i] = x + b(t,x) * t_step + sigma(t,x) * dW(t_step)
        plt.plot(ts, xs)

    plt.show()

## Test Case (Geometric Brownian Motion)
num_sims = 10  # number of simulations
t_init = 0
t_end  = 1
t_step = 0.001
x_init = 1 # initial condition

# function b and sigma
def b(t, x):
    return 0.8*x

def sigma(t,x):
    return 0.5*x

SDE(num_sims, t_init, t_end, t_step, x_init, b, sigma)


import time
import pylab as pl
from IPython import display
import numpy as np

def taylor_approx(n):
    x = np.linspace(np.pi*(-3), np.pi*(3),100)                          # values of x from -3*pi to 3*pi
    approx = np.zeros(len(x), dtype=np.dtype('O'))
    for i in range(n):
        approx += ((-1)**i) * (x**(2*i)/np.math.factorial(2*i))         # taylor series of cos(x)
        pl.plot(x, np.cos(x))
        pl.plot(x, approx)
        pl.ylim(-1.7,1.7)
        pl.legend(('cos() function', 'Taylor Approximation'), loc = 'upper right')
        pl.text(x = -8, y = 1.25, s = "n = " + str(i), fontsize=15)
        display.clear_output(wait=True)
        display.display(pl.gcf())
        pl.clf()
        time.sleep(1.0)        # pause 1 sec before ploting the next curve

# call the function
taylor_approx(n = 13)


from abc import ABC, abstractmethod
import numpy as np
from .constants import EPSILON

class Loss(ABC):
    def __init__(self, expected_output, predict_output):
        self._expected_output = expected_output
        self._predict_output = predict_output

    @abstractmethod
    def get_loss(self):
        pass

    @abstractmethod
    def get_derivative_loss(self):
        pass

class CrossEntropy(Loss):
    def __init__(self, expected_output, predict_output):
        super().__init__(expected_output, predict_output)

    def get_loss(self):
        loss = np.mean(-(self._expected_output*np.log(self._predict_output) +
                         (1-self._expected_output) * np.log(1-self._predict_output+EPSILON)))
        return loss

    def get_derivative_loss(self):
        dloss = (-(self._expected_output / (self._predict_output+EPSILON)) +
                (1-self._expected_output)/(1-self._predict_output+EPSILON))
        return dloss

class L2(Loss):
    def __init__(self, expected_output, predict_output):
        super().__init__(expected_output, predict_output)

    def get_loss(self):
        return np.mean(np.square(self._predict_output - self._expected_output))

    def get_derivative_loss(self):
        return 2*(self._predict_output - self._expected_output)


#coding:utf-8

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

np.set_printoptions(linewidth=200,suppress=True)

mpl.rcParams['font.sans-serif'] = [u'SimHei']  # FangSong/黑体 FangSong/KaiTi
mpl.rcParams['axes.unicode_minus'] = False
mu = 0
sigma = 1
x = np.linspace(mu - 3 * sigma, mu + 3 * sigma, 51)
y = np.exp(-(x - mu) ** 2 / (2 * sigma ** 2)) / (math.sqrt(2 * math.pi) * sigma)
print(x.shape)
print('x = \n', x)
print(y.shape)
print('y = \n', y)
plt.figure(facecolor='w')
plt.plot(x, y, 'ro-', linewidth=2)
plt.plot(x, y, 'r-', x, y, 'go', linewidth=2, markersize=8)
plt.xlabel('X', fontsize=15)
plt.ylabel('Y', fontsize=15)
plt.title(u'高斯分布函数', fontsize=18)    #
plt.grid(True)
plt.show()


import numpy as np
import datetime
import scipy.stats as si
import numpy as np
import scipy.stats as si
import yfinance as yf

def black_scholes_calc(S, K, T, r, sigma, option = 'call'):
	#S: Current Stock Price
    #K: Strike price
    #T: Time to maturity in Years
    #r: Risk Free interest rate
    #sigma: Volatility of underlying asset

    d1 = (np.log(S / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
    d2 = (np.log(S / K) + (r - 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))

    if option == 'call':
        result = (S * si.norm.cdf(d1, 0.0, 1.0) - K * np.exp(-r * T) * si.norm.cdf(d2, 0.0, 1.0))
    if option == 'put':
        result = (K * np.exp(-r * T) * si.norm.cdf(-d2, 0.0, 1.0) - S * si.norm.cdf(-d1, 0.0, 1.0))

    return result

'''
Sample Run
'''
s = yf.Ticker('AAPL')
opt = s.option_chain('2020-08-21')
call= opt.calls
S = s.history(period = "max")['Close'].iloc[-1]
T = (datetime.date(2020,11,20) - datetime.date(2020,7,24)).days / 365.0
print(S, T)
for i in range(len(call)):
	v = call.iloc[i]['impliedVolatility']
	r = 0.17900
	K = call.iloc[i]['strike']
	print(K)
	print ('Price: %.4f' % black_scholes_calc(S, K, T, 0.014, v))


import numpy as np
import time
import matplotlib.pyplot as plt
import visdom

# find the minimum of y
# y = x^2 + x + 1
# y' = 2x + 1
# y'' = 2

x0 = 91.91

g = 2*x0 + 1  # f'(x0)
gg = 2  # f''(x0)

while abs(g) > 0.001:
    # update x0
    x0 = -g/gg + x0

    # update one order partial
    g = 2*x0 + 1

    # update two order partial, will, in this case it is constant
    gg = 2

    print(g)

y = x0**2 + x0 + 1
print('\nx_final is {0}, and min_y is {1}'.format(x0, y))

#  2-Dim Newton
# z = x^2 + y^2 + x + y + xy + 1
# partial x = 2*x + y + 1
# partial y = 2*y + x + 1

x0 = [1, 1]  # nit point

p_x = 2*x0[0] + x0[1] + 1
p_y = 2*x0[1] + x0[0] + 1

p_xx = 2
p_yy = 2
p_xy = 1
p_yx = 1

g0 = [p_x, p_y]
g0_norm = np.linalg.norm(g0)

H0 = np.array([[p_xx, p_xy],
               [p_yx, p_yy]
               ])

print('H0:\n', H0)

# pts = [x0]
pts = []
z = []

while g0_norm > 0.01:
    # print(g0_norm)

    x0 = x0 - 0.1 * np.dot(np.linalg.inv(H0), g0)  # update x0
    # print('x0:', x0)
    pts.append(x0)

    # update g0 sprct partail x/y
    p_x = 2 * x0[0] + x0[1] + 1
    p_y = 2 * x0[1] + x0[0] + 1
    g0 = [p_x, p_y]
    g0_norm = np.linalg.norm(g0)  # don't forget to update end_condition!
    print('g0: ', g0)

    # this case, H is constant!

    # check y
    y = x0[0]**2 + x0[1]**2 + x0[0] + x0[1] + x0[0]*x0[1] + 1
    print('y: ', y)
    z.append(z)
    time.sleep(0.01)  # fastidium delay...

# pts = np.array(pts).T
# # print(x0.shape)
# print('pts:', pts)
# plt.scatter(pts[0], pts[1], marker='*')
# plt.show()


import numpy as np

def alpine1(x):
    """Alpine 1's function.

    It can be used with 'n' variables and has minimum at 0.
    Also, it is expected to be within [-10, 10] bounds.

    Args:
        x (np.array): An n-dimensional input array.

    Returns:
        y = sum(fabs(x * sin(x) + 0.1 * x))

    """

    # Declaring Alpine 1's function
    y = np.fabs(x * np.sin(x) + 0.1 * x)

    return np.sum(y)

def alpine2(x):
    """Alpine 2's function.

    It can be used with 'n' variables and has minimum at -2.808^n.
    Also, it is expected to be within [0, 10] bounds.

    Args:
        x (np.array): An n-dimensional input array.

    Returns:
        y = -prod(sqrt(x) * sin(x))

    """

    # Declaring Alpine 2's function
    y = np.sqrt(x) * np.sin(x)

    return -np.prod(y)

def chung_reynolds(x):
    """Chung Reynolds' function.

    It can be used with 'n' variables and has minimum at 0.
    Also, it is expected to be within [-100, 100] bounds.

    Args:
        x (np.array): An n-dimensional input array.

    Returns:
        y = (sum(x^2))^2

    """

    # Calculating Sphere's function
    s = sphere(x)

    return s ** 2

def csendes(x):
    """Csendes' function.

    It can be used with 'n' variables and has minimum at 0.
    Also, it is expected to be within [-1, 1] bounds.

    Args:
        x (np.array): An n-dimensional input array.

    Returns:
        y = sum(x^6 * (2 + sin(1 / x)))

    """

    # Declaring Csendes' function
    y = (x ** 6) * (2 + np.sin(1 / x))

    return np.sum(y)

def deb1(x):
    """Deb 1's function.

    It can be used with 'n' variables and has minimum at 5^n.
    Also, it is expected to be within [-1, 1] bounds.

    Args:
        x (np.array): An n-dimensional input array.

    Returns:
        y = (-1 / n) * sum(sin(5 * pi * x)^6)

    """

    return

def deb3(x):
    """Deb 3's function.

    It can be used with 'n' variables and has minimum at 5^n.
    Also, it is expected to be within [-1, 1] bounds.

    Args:
        x (np.array): An n-dimensional input array.

    Returns:
        y = (-1 / n) * sum(sin(5 * pi * (x^(3/4) - 0.05))^6)

    """

    return

def exponential(x):
    """Exponential's function.

    It can be used with 'n' variables and has minimum at -1.
    Also, it is expected to be within [-1, 1] bounds.

    Args:
        x (np.array): An n-dimensional input array.

    Returns:
        y = -exp(-0.5 * sum(x^2))

    """

    # Calculating Sphere's function
    s = sphere(x)

    return -np.exp(-0.5 * s)

def griewank(x):
    """Griewank's function.

    It can be used with 'n' variables and has minimum at 0.
    Also, it is expected to be within [-100, 100] bounds.

    Args:
        x (np.array): An n-dimensional input array.

    Returns:
        y = 1 + sum(x^2 / 4000) - prod(cos(x / sqrt(i)))

    """

    return

def rastringin(x):
    """Rastringin's function.

    It can be used with 'n' variables and has minimum at 0.
    Also, it is expected to be within [-5.12, 5.12] bounds.

    Args:
        x (np.array): An n-dimensional input array.

    Returns:
        y = A * n + sum(x^2 - A * cos(2 * pi * x))

    """

    # Declaring constant
    A = 10

    # Declaring Rastringin's function
    y = (x ** 2) - (A * np.cos(2 * np.pi * x))

    return A * x.shape[0] + np.sum(y)

def salomon(x):
    """Salomon's function.

    It can be used with 'n' variables and has minimum at 0.
    Also, it is expected to be within [-100, 100] bounds.

    Args:
        x (np.array): An n-dimensional input array.

    Returns:
        y = 1 - cos(2 * pi * sqrt(sum(x^2))) + 0.1 * sqrt(sum(x^2))

    """

    # Calculating Sphere's function
    s = sphere(x)

    return 1 - np.cos(2 * np.pi * np.sqrt(s)) + 0.1 * np.sqrt(s)

def schwefel(x):
    """Schwefel's function.

    It can be used with 'n' variables and has minimum at 0.
    Also, it is expected to be within [-500, 500] bounds.

    Args:
        x (np.array): An n-dimensional input array.

    Returns:
        y = 418.9829 * n - sum(x * sin(sqrt(fabs(x))))

    """

    # Declaring Schwefel's function
    y = x * np.sin(np.sqrt(np.fabs(x)))

    return 418.9829 * x.shape[0] - np.sum(y)

def sphere(x):
    """Sphere's function.

    It can be used with 'n' variables and has minimum at 0.
    Also, it is expected to be within [-5.12, 5.12] bounds.

    Args:
        x (np.array): An n-dimensional input array.

    Returns:
        y = sum(x^2)

    """

    # Declaring Sphere's function
    y = x ** 2

    return np.sum(y)


##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
##                          GMM algorithm for the illustration example
## %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

#%% import
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs

#%% generate data
n_samples = 1500
X, _ = make_blobs(n_samples=n_samples, random_state=100)

plt.figure()
plt.scatter(X[:,0], X[:,1])

rotation_matrix = [[0.60, -0.70], [-0.5, 0.7]]
X_transformed = np.dot(X, rotation_matrix)

plt.figure()
plt.scatter(X_transformed[:,0], X_transformed[:,1])

#%% fit GMM model
from sklearn.mixture import GaussianMixture

gmm = GaussianMixture(n_components = 3, random_state = 100)
cluster_label = gmm.fit_predict(X_transformed)

plt.figure()
plt.scatter(X_transformed[:, 0], X_transformed[:, 1], c = cluster_label, s=20, cmap='viridis')
plt.xlabel('Variable 1')
plt.ylabel('Variable 2')

cluster_centers = gmm.means_ # cluster centers
cluster_plot_labels = ['Cluster ' + str(i+1) for i in range(gmm.n_components)]
for i in range(gmm.n_components):
    plt.scatter(cluster_centers[i, 0], cluster_centers[i, 1], c='red', s=20, marker = '*', alpha=0.5)
    plt.annotate(cluster_plot_labels[i], (cluster_centers[i,0], cluster_centers[i,1]))

#%% membership probabilities
probs = gmm.predict_proba(X_transformed[1069,np.newaxis]) # predict_proba requires 2D array
print('Posterior probablities of clusters 1, 2, 3 for the data-point: ', probs[-1,:])

#%% posterior probability calculation
x = X_transformed[1069,np.newaxis]

import scipy.stats
g1 = scipy.stats.multivariate_normal(gmm.means_[0,:], gmm.covariances_[0,:]).pdf(x)
g2 = scipy.stats.multivariate_normal(gmm.means_[1,:], gmm.covariances_[1,:]).pdf(x)
g3 = scipy.stats.multivariate_normal(gmm.means_[2,:], gmm.covariances_[2,:]).pdf(x)
print('Local component densities: ', g1, g2, g3)

den = gmm.weights_[0]*g1 + gmm.weights_[1]*g2 + gmm.weights_[2]*g3
posterior_prob_cluster1 = gmm.weights_[0]*g1/den
posterior_prob_cluster2 = gmm.weights_[1]*g2/den
posterior_prob_cluster3 = gmm.weights_[2]*g3/den
print('Posterior probabilities: ', posterior_prob_cluster1, posterior_prob_cluster2, posterior_prob_cluster3)

#%% finding # of components via BIC method
BICs = []
lowestBIC = np.inf
for n_cluster in range(1, 10):
    gmm = GaussianMixture(n_components = n_cluster, random_state = 100)
    gmm.fit(X_transformed)
    BIC = gmm.bic(X_transformed)
    BICs.append(BIC)

    if BIC < lowestBIC:
        optimal_n_cluster = n_cluster
        lowestBIC = BIC

plt.figure()
plt.plot(range(1,10), BICs, marker='o')
plt.scatter(optimal_n_cluster, lowestBIC, c='red', marker='*', s=1000)
plt.xlabel('Number of clusters')
plt.ylabel('BIC')
plt.show()

#%% finding # of components via FJ algorithm
from gmm_mml import GmmMml
gmmFJ = GmmMml(plots=False)
gmmFJ.fit(X_transformed)
cluster_label = gmmFJ.predict(X_transformed)

plt.figure()
plt.scatter(X_transformed[:, 0], X_transformed[:, 1], c = cluster_label, s=20, cmap='viridis')
plt.xlabel('Variable 1')
plt.ylabel('Variable 2')

clusters = np.unique(cluster_label)
print(clusters)


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

"""
http://www.scipy.org/Cookbook/Least_Squares_Circle
"""

from numpy import *

# Coordinates of the 2D points

# x = r_[  9, 35, -13,  10,  23,   0]
# y = r_[ 34, 10,   6, -14,  27, -10]

x = r_[36, 36, 19, 18, 33, 26]
y = r_[14, 10, 28, 31, 18, 26]

# R0 = 25
# nb_pts = 8
# dR = 2
# angle =9*pi/5
# x = (10 + R0*cos(theta0) + dR*random.normal(size=nb_pts)).round()
# y = (10 + R0*sin(theta0) + dR*random.normal(size=nb_pts)).round()

# == METHOD 1 ==
method_1 = 'algebraic'

# coordinates of the barycenter
x_m = mean(x)
y_m = mean(y)

# calculation of the reduced coordinates
u = x - x_m
v = y - y_m

# linear system defining the center in reduced coordinates (uc, vc):
#    Suu * uc +  Suv * vc = (Suuu + Suvv)/2
#    Suv * uc +  Svv * vc = (Suuv + Svvv)/2

Suv  = sum(u*v)
Suu  = sum(u**2)
Svv  = sum(v**2)
Suuv = sum(u**2 * v)
Suvv = sum(u * v**2)
Suuu = sum(u**3)
Svvv = sum(v**3)

# Solving the linear system
A = array([ [ Suu, Suv ], [Suv, Svv]])
B = array([ Suuu + Suvv, Svvv + Suuv ])/2.0
uc, vc = linalg.solve(A, B)

xc_1 = x_m + uc
yc_1 = y_m + vc

# Calculation of all distances from the center (xc_1, yc_1)
Ri_1     = sqrt((x-xc_1)**2 + (y-yc_1)**2)
R_1      = mean(Ri_1)
residu_1 = sum((Ri_1-R_1)**2)
residu2_1= sum((Ri_1**2-R_1**2)**2)

# Decorator to count functions calls
import functools
def countcalls(fn):
    "decorator function count function calls "

    @functools.wraps(fn)
    def wrapped(*args):
        wrapped.ncalls +=1
        return fn(*args)

    wrapped.ncalls = 0
    return wrapped

#  == METHOD 2 ==
from scipy      import optimize

method_2  = "leastsq"

def calc_R(c):
    """ calculate the distance of each 2D points from the center c=(xc, yc) """
    return sqrt((x-c[0])**2 + (y-c[1])**2)

@countcalls
def f_2(c):
    """ calculate the algebraic distance between the 2D points and the mean circle centered at c=(xc, yc) """
    Ri = calc_R(c)
    return Ri - Ri.mean()

center_estimate = x_m, y_m
center_2, ier = optimize.leastsq(f_2, center_estimate)

xc_2, yc_2 = center_2
Ri_2       = calc_R(center_2)
R_2        = Ri_2.mean()
residu_2   = sum((Ri_2 - R_2)**2)
residu2_2  = sum((Ri_2**2-R_2**2)**2)
ncalls_2   = f_2.ncalls

# == METHOD 3 ==
from scipy      import  odr

method_3  = "odr"

@countcalls
def f_3(beta, x):
    """ implicit function of the circle """
    xc, yc, r = beta
    return (x[0]-xc)**2 + (x[1]-yc)**2 -r**2

def calc_estimate(data):
    """ Return a first estimation on the parameter from the data  """
    xc0, yc0 = data.x.mean(axis=1)
    r0 = sqrt((data.x[0]-xc0)**2 +(data.x[1] -yc0)**2).mean()
    return xc0, yc0, r0

# for implicit function :
#       data.x contains both coordinates of the points
#       data.y is the dimensionality of the response
lsc_data  = odr.Data(row_stack([x, y]), y=1)
lsc_model = odr.Model(f_3, implicit=True, estimate=calc_estimate)
lsc_odr   = odr.ODR(lsc_data, lsc_model)
lsc_out   = lsc_odr.run()

xc_3, yc_3, R_3 = lsc_out.beta
Ri_3       = calc_R([xc_3, yc_3])
residu_3   = sum((Ri_3 - R_3)**2)
residu2_3  = sum((Ri_3**2-R_3**2)**2)
ncalls_3   = f_3.ncalls

print 'lsc_out.sum_square = ',lsc_out.sum_square

# == METHOD 4 ==

method_4  = "odr with jacobian"

@countcalls
def f_4(beta, x):
    """ implicit function of the circle """
    xc, yc, r = beta
    xi, yi    = x

    return (xi-xc)**2 + (yi-yc)**2 -r**2

@countcalls
def jacb(beta, x):
    """ Jacobian function with respect to the parameters beta.
    return df/dbeta
    """
    xc, yc, r = beta
    xi, yi    = x

    df_db    = empty((beta.size, x.shape[1]))
    df_db[0] =  2*(xc-xi)                     # d_f/dxc
    df_db[1] =  2*(yc-yi)                     # d_f/dyc
    df_db[2] = -2*r                           # d_f/dr

    return df_db

@countcalls
def jacd(beta, x):
    """ Jacobian function with respect to the input x.
    return df/dx
    """
    xc, yc, r = beta
    xi, yi    = x

    df_dx    = empty_like(x)
    df_dx[0] =  2*(xi-xc)                     # d_f/dxi
    df_dx[1] =  2*(yi-yc)                     # d_f/dyi

    return df_dx

def calc_estimate(data):
    """ Return a first estimation on the parameter from the data  """
    xc0, yc0 = data.x.mean(axis=1)
    r0 = sqrt((data.x[0]-xc0)**2 +(data.x[1] -yc0)**2).mean()
    return xc0, yc0, r0

# for implicit function :
#       data.x contains both coordinates of the points
#       data.y is the dimensionality of the response
lsc_data  = odr.Data(row_stack([x, y]), y=1)
lsc_model = odr.Model(f_4, implicit=True, estimate=calc_estimate, fjacd=jacd, fjacb=jacb)
lsc_odr   = odr.ODR(lsc_data, lsc_model)
lsc_odr.set_job(deriv=3)                    # use user derivatives function without checking
lsc_out   = lsc_odr.run()

xc_4, yc_4, R_4 = lsc_out.beta
Ri_4       = calc_R([xc_4, yc_4])
residu_4   = sum((Ri_4 - R_4)**2)
residu2_4  = sum((Ri_4**2-R_4**2)**2)
ncalls_4   = f_4.ncalls

print "Method 4 :"
print "Functions calls : f_4=%d jacb=%d jacd=%d" % (f_4.ncalls, jacb.ncalls, jacd.ncalls)

# Summary
fmt = '%-18s %10.5f %10.5f %10.5f %10d %10.6f %10.6f %10.2f'
print ('\n%-18s' +' %10s'*7) % tuple('METHOD Xc Yc Rc nb_calls std(Ri) residu residu2'.split())
print '-'*(18 +7*(10+1))
print  fmt % (method_1, xc_1, yc_1, R_1,        1, Ri_1.std(), residu_1, residu2_1)
print  fmt % (method_2, xc_2, yc_2, R_2, ncalls_2, Ri_2.std(), residu_2, residu2_2)
print  fmt % (method_3, xc_3, yc_3, R_3, ncalls_3, Ri_3.std(), residu_3, residu2_3)
print  fmt % (method_4, xc_4, yc_4, R_4, ncalls_4, Ri_4.std(), residu_4, residu2_4)

# plotting functions

from matplotlib import pyplot as p, cm

def plot_all(residu2=False, basename='circle'):
    """ Draw data points, best fit circles and center for the three methods,
    and adds the iso contours corresponding to the fiel residu or residu2
    """

    f = p.figure(figsize=(6.5, 4.5), dpi=90, facecolor='white')
    p.axis('equal')

    p.plot(x, y, 'ro', label='data', ms=9, mec='b', mew=1)

    theta_fit = linspace(-pi, pi, 180)

    x_fit1 = xc_1 + R_1*cos(theta_fit)
    y_fit1 = yc_1 + R_1*sin(theta_fit)
    p.plot(x_fit1, y_fit1, 'b-' , label=method_1, lw=2)

    x_fit2 = xc_2 + R_2*cos(theta_fit)
    y_fit2 = yc_2 + R_2*sin(theta_fit)
    p.plot(x_fit2, y_fit2, 'k--', label=method_2, lw=2)

    x_fit3 = xc_3 + R_3*cos(theta_fit)
    y_fit3 = yc_3 + R_3*sin(theta_fit)
    p.plot(x_fit3, y_fit3, 'r-.', label=method_3, lw=2)

    p.plot([xc_1], [yc_1], 'bD', mec='y', mew=1)
    p.plot([xc_2], [yc_2], 'gD', mec='r', mew=1)
    p.plot([xc_3], [yc_3], 'kD', mec='w', mew=1)

    # draw
    p.xlabel('x')
    p.ylabel('y')
    p.legend(loc='best',labelspacing=0.1)

    # plot the residu fields
    nb_pts = 100

    p.draw()
    xmin, xmax = p.xlim()
    ymin, ymax = p.ylim()

    vmin = min(xmin, ymin)
    vmax = max(xmax, ymax)

    xg, yg = ogrid[vmin:vmax:nb_pts*1j, vmin:vmax:nb_pts*1j]
    xg = xg[..., newaxis]
    yg = yg[..., newaxis]

    Rig    = sqrt( (xg - x)**2 + (yg - y)**2 )
    Rig_m  = Rig.mean(axis=2)[..., newaxis]

    if residu2 : residu = sum( (Rig**2 - Rig_m**2)**2 ,axis=2)
    else       : residu = sum( (Rig-Rig_m)**2 ,axis=2)

    lvl = exp(linspace(log(residu.min()), log(residu.max()), 15))

    p.contourf(xg.flat, yg.flat, residu.T, lvl, alpha=0.75, cmap=cm.Purples_r)
    cbar = p.colorbar(format='%.f')

    if residu2 : cbar.set_label('Residu_2')
    else       : cbar.set_label('Residu')

    p.xlim(xmin=vmin, xmax=vmax)
    p.ylim(ymin=vmin, ymax=vmax)

    p.grid()
    p.title('Leasts Squares Circle')
    p.savefig('%s_residu%d.png' % (basename, 2 if residu2 else 1))

plot_all(residu2=False, basename='circle')
plot_all(residu2=True , basename='circle')

p.show()
# vim: set et sts=4 sw=4:


""" Module to compute projections on the positive simplex or the L1-ball

A positive simplex is a set X = { \mathbf{x} | \sum_i x_i = s, x_i \geq 0 }

The (unit) L1-ball is the set X = { \mathbf{x} | || x ||_1 \leq 1 }

Adrien Gaidon - INRIA - 2011
"""

import numpy as np

def euclidean_proj_simplex(v, s=1):
    """ Compute the Euclidean projection on a positive simplex

    Solves the optimisation problem (using the algorithm from [1]):

        min_w 0.5 * || w - v ||_2^2 , s.t. \sum_i w_i = s, w_i >= 0

    Parameters
    ----------
    v: (n,) numpy array,
       n-dimensional vector to project

    s: int, optional, default: 1,
       radius of the simplex

    Returns
    -------
    w: (n,) numpy array,
       Euclidean projection of v on the simplex

    Notes
    -----
    The complexity of this algorithm is in O(n log(n)) as it involves sorting v.
    Better alternatives exist for high-dimensional sparse vectors (cf. [1])
    However, this implementation still easily scales to millions of dimensions.

    References
    ----------
    [1] Efficient Projections onto the .1-Ball for Learning in High Dimensions
        John Duchi, Shai Shalev-Shwartz, Yoram Singer, and Tushar Chandra.
        International Conference on Machine Learning (ICML 2008)
        http://www.cs.berkeley.edu/~jduchi/projects/DuchiSiShCh08.pdf
    """
    assert s > 0, "Radius s must be strictly positive (%d <= 0)" % s
    n, = v.shape  # will raise ValueError if v is not 1-D
    # check if we are already on the simplex
    if v.sum() == s and np.alltrue(v >= 0):
        # best projection: itself!
        return v
    # get the array of cumulative sums of a sorted (decreasing) copy of v
    u = np.sort(v)[::-1]
    cssv = np.cumsum(u)
    # get the number of > 0 components of the optimal solution
    rho = np.nonzero(u * np.arange(1, n + 1) > (cssv - s))[0][-1]
    # compute the Lagrange multiplier associated to the simplex constraint
    theta = (cssv[rho] - s) / (rho + 1.0)
    # compute the projection by thresholding v using theta
    w = (v - theta).clip(min=0)
    return w

def euclidean_proj_l1ball(v, s=1):
    """ Compute the Euclidean projection on a L1-ball

    Solves the optimisation problem (using the algorithm from [1]):

        min_w 0.5 * || w - v ||_2^2 , s.t. || w ||_1 <= s

    Parameters
    ----------
    v: (n,) numpy array,
       n-dimensional vector to project

    s: int, optional, default: 1,
       radius of the L1-ball

    Returns
    -------
    w: (n,) numpy array,
       Euclidean projection of v on the L1-ball of radius s

    Notes
    -----
    Solves the problem by a reduction to the positive simplex case

    See also
    --------
    euclidean_proj_simplex
    """
    assert s > 0, "Radius s must be strictly positive (%d <= 0)" % s
    n, = v.shape  # will raise ValueError if v is not 1-D
    # compute the vector of absolute values
    u = np.abs(v)
    # check if v is already a solution
    if u.sum() <= s:
        # L1-norm is <= s
        return v
    # v is not already a solution: optimum lies on the boundary (norm == s)
    # project *u* on the simplex
    w = euclidean_proj_simplex(u, s=s)
    # compute the solution to the original problem on v
    w *= np.sign(v)
    return w


import numpy as np

def mean_squared_error(y, t):
    return 0.5 * np.sum((y - t) ** 2)

def cross_entropy_error(y, t):
    if y.dim == 1:
        y = y.reshape(1, y.size)
        t = t.reshape(1, t.size)

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

def cross_entropy_error_one_hot(y, t):
    if y.dim == 1:
        y = y.reshape(1, y.size)
        t = t.reshape(1, t.size)
    delta = 1e-7
    return -np.sum(t * np.log(y + delta))


"""
This is a code to find the linear independent linear combinations of columns of a matrix, which
are linearly dependent columns (). The intended use of the code is to find redundant combinations of features
from the data
"""

import numpy as np

from sympy import Matrix

def find_symbolic_dependent_columns(x):
    """
    Find linearly dependent columns using symbolic calculations.
    :param x: The input numpy array
    :return: The linear combination matrix (Null Space of MAtrix).
    """
    x = Matrix(x)
    return(x.nullspace())

def find_numerically(x, tol = np.finfo(np.float).eps):
    """
    Find numerically using SVD decomposition. The returned solution will be nullspace
    of the matrix.
    :param x: The input numpy array
    :param tol: Tolerance varaibles less than tol are floored to zero.
    :return: The linear combination matrix (Null Space of the Matrix).
    """
    u, s, v = np.linalg.svd(x, full_matrices = True)
    zero_eigs = (np.abs(s) < tol)
    null_space = np.compress(zero_eigs, v, axis = 0).T
    return(null_space)

def find_dependent_rational_basis(x):
    """
    Find linearly dependent columns similar to MATLAB null(x, 'r').
    :param x: The input numpy array
    :return: The linear combination matrix (Null Space of Matrix).
    """
    m, n = x.shape
    x = Matrix(x)
    R = x.rref()
    r = len(R[1])
    nopiv = np.arange(0, n)
    p = np.array(R[1])
    a = np.array(R[0])
    nopiv = np.delete(nopiv, p, axis = 0)
    Z = np.zeros([n, n-r])
    if n > r:
        Z[nopiv, :] = np.eye(n-r, n-r)
        if r > 0:
            Z[p, :] = -a[0:r, nopiv]
    return(Z)

if __name__ == '__main__':
    """
    Simple use case.
    """
    print(' Define Matrix ')

    A = np.array([[2, 4, 1, 3], [-1, -2, 1, 0], [0, 0, 4, 4], [3, 6, 2, 5]])

    print(A)

    print(' Output Matrix ')

    U = find_symbolic_dependent_columns(A)

    print(U)

    print(' Using Numerical Approximation')

    V = find_numerically(A)

    print(V)

    print(' Matlab N null(x, 'r') ')

    W = find_dependent_rational_basis(A)

    print(W)


import numpy as np

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

class WolfeQuapp():
  dimension = 2

  minima = (np.array([-1.174,  1.477 ]),
            np.array([-0.831, -1.366 ]),
            np.array([ 1.124, -1.486 ]))
  maxima = (np.array([ 0.100,  0.050 ]),)
  saddle = (np.array([-1.013, -0.036 ]),
            np.array([ 0.093,  0.174 ]),
            np.array([-0.208, -1.407 ]))

  grid_min = np.array([-2.5, -2.5])
  grid_max = np.array([ 2.5,  2.5])
  extent = np.array([grid_min[0], grid_max[0], grid_min[1], grid_max[1]])

  def potential(self, x, y):
    return x**4 + y**4 - 2.0*x**2 - 4.0*y**2 + x*y + 0.3*x + 0.1*y

  def mesh(self):
    grid_x = np.linspace(self.grid_min[0], self.grid_max[0], 200)
    grid_y = np.linspace(self.grid_min[1], self.grid_max[1], 200)
    x, y = np.meshgrid(grid_x, grid_y)
    z = self.potential(x.flatten(), y.flatten())
    return z.reshape(200, 200)

  def eval(self, position):
    assert len(position) == self.dimension
    x, y = position
    potential = x**4 + y**4 - 2.0*x**2 - 4.0*y**2 + x*y + 0.3*x + 0.1*y
    force = np.zeros(self.dimension)
    force[0] = -(4.0*x**3 - 4.0*x + y + 0.3)
    force[1] = -(4.0*y**3 - 8.0*y + x + 0.1)
    return potential, force

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

class MuellerBrown():
  dimension = 2

  A = np.array([-200.0, -100.0, -175.0, 15.0])
  a = np.array([  -1.0,   -1.0,   -6.5,  0.7])
  b = np.array([   0.0,    0.0,   11.0,  0.6])
  c = np.array([ -10.0,  -10.0,   -6.5,  0.7])
  x0 = np.array([  1.0,    0.0,   -0.5, -1.0])
  y0 = np.array([  0.0,    0.5,    1.5,  1.0])
  minima = np.array([[-0.558, 1.442],
                     [ 0.623, 0.028],
                     [-0.050, 0.467]])
  saddle = np.array([[-0.822, 0.624],
                     [-0.212, 0.293]])

  grid_min = np.array([-2.0, -0.5])
  grid_max = np.array([ 1.5,  2.5])
  extent = np.array([grid_min[0], grid_max[0], grid_min[1], grid_max[1]])

  potential_scale = 0.2
  A *= potential_scale
  potential_shift = 30.331916979076915
  zmin = 0.0
  zmax = 300.0 * potential_scale

  def potential(self, x, y):
    potential = 0.0
    for i in range(4):
      potential += self.A[i] * np.exp(self.a[i]*(x-self.x0[i])**2 +
                                       self.b[i]*(x-self.x0[i])*(y-self.y0[i]) +
                                       self.c[i]*(y-self.y0[i])**2)
    return potential + self.potential_shift

  def mesh(self):
    grid_x = np.linspace(self.grid_min[0], self.grid_max[0], 200)
    grid_y = np.linspace(self.grid_min[1], self.grid_max[1], 200)
    x, y = np.meshgrid(grid_x, grid_y)
    z = self.potential(x.flatten(), y.flatten())
    return z.reshape(200, 200)

  def eval(self, position):
    assert len(position) == self.dimension
    x, y = position
    potential = 0.0
    force = np.zeros(self.dimension)
    for i in range(4):
      tmp = np.exp(self.a[i]*(x-self.x0[i])**2 +
                   self.b[i]*(x-self.x0[i])*(y-self.y0[i]) +
                   self.c[i]*(y-self.y0[i])**2)
      potential += self.A[i] * tmp
      force[0] += -self.A[i] * (2.0 * self.a[i] * (x-self.x0[i]) +
                               self.b[i] * (y-self.y0[i])) * tmp
      force[1] += -self.A[i] * (self.b[i] * (x-self.x0[i]) + 2.0 * self.c[i] *
                               (y-self.y0[i])) * tmp
    return potential + self.potential_shift, force


import numpy as np

def Softmax(z):
	'''
	Softmax function - convert the output of a neural network to an
	array of probabilities.

	Inputs
	======
	z : float
		Output matrix, shape (m,k), where m is the number of samples and
		k is the number of output nodes.

	Returns
	=======
	s : float
		Softmax output - shape (m,k).
	'''
	return (np.exp(z).T/np.sum(np.exp(z),axis=1)).T


#
#	root-bisection.py
#	Finding root using bisection method
#
#	Sparisoma Viridi | https://butiran.github.io/
#
#	Execute: py root-bisection.js
#
#	20210130
#	1735 Start this program from root-scanning.py and js codes.
#	1741 Use list and its append as described in [1].
#	1805 Test SHOW_PROGRESS, and ok.
#	20210210
#	0527 Typo node --> py.
#
#	References
#	1. pawan_asipu, cffjob, "append() and extend() in Python",
#	   GeeksforGeeks, 01 Apr 2020, url
#	   <https://www.geeksforgeeks.org/append-extend-python/>
#	   [20210130].
#	2. eyquem, pauloue, "Answer to 'Is there a standardized
#	   method to swap two variables in Python?'",
#	   StackOverflow, 22 Jan 2018, url
#	   https://stackoverflow.com/a/14836456 [20210130].
#

# Import necessary libraries
import numpy as np

# Define a test function
def test_function(x):
	y3 = 0.025 * x * x * x
	y2 = -0.2585 * x * x
	y1 = 0.243 * x
	y0 = 0.5265
	y = y3 + y2 + y1 + y0
	return y

# Define input
f = test_function
xbeg = 1
xend = 8
eps = 1E-6
Nstep = 0
maxstep = 40
n = 0

# Define default message and parameter
xroot = "not found"
SHOW_PROGRESS = True

# Do iteration
Nstep = 0
x = []
x.append(xbeg)
x.append(xend)
froot = np.abs(f(x[n+1]))

while n <= maxstep-3 and froot > eps:
	x.append(0.5*(x[n] + x[n+1]))

	fn1 = f(x[n+1])
	fn2 = f(x[n+2])
	c = fn1 * fn2
	if c > 0:
		x[n], x[n+1] = x[n+1], x[n]

	if SHOW_PROGRESS:
		if n == 0:
			fn = f(x[n])
			print("n\tx\tf(x)")
			print(n, x[n], fn, sep="\t")
			print(n+1, x[n+1], fn1, sep="\t")
		print(n+2, x[n+2], fn2, sep="\t")

	froot = np.abs(fn2)
	if froot < eps:
		xroot = x[n+2]

	n += 1

Nstep = n+2

if SHOW_PROGRESS:
	print()

# Display result
print("f(x)   0.025x^3 - 0.2585x^2 + 0.243x + 0.5265");
print("xbeg  ", xbeg, sep="")
print("xend  ", xend, sep="")
print("ε     ", eps, sep="")
print("Nstep ", Nstep, sep="")
print("xroot ", xroot, sep="")


# Copyright 2020 Jan Rodolf Espinas
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Riemann Integral: Intro to Numerical Analysis"""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

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

__version__ = '2.0.0'
__author__ = 'Jan Rodolf Espinas'

def get_delta_x(lower_bound, upper_bound, n):
    return (upper_bound-lower_bound) / n

def f(x):
    return x**2

def get_riemann_sum(x, delta_x):
    """
    Returns the riemann `sum` given a `function` and
    the input `x` and `delta_x`

    Parameters
    ----------
    x : list
        List of numbers returned by `np.linspace` given a lower
        and upper bound, and the number of intervals
    delta_x :
        The interval

    Returns
    -------
    float
       The integral sum
    """
    return sum(f(x)*delta_x)

def riemann_integral(lower_bound, upper_bound, subintervals):
    """
    Shows four plots of the riemann integral given
    by the `lower_bound`, `upper_bound`, and `subintervals`.

    Parameters
    ----------
    lower_bound: int
        Lower bound of the given interval
    upper_bound : int
        Upper bound of the given interval
    subintervals : list of int
        Number of rectangles to approximate the area under the graph
    """

    fig = plt.figure()
    for i in range(len(subintervals)):
        x = np.linspace(lower_bound, upper_bound,
                        subintervals[i], endpoint=False)
        delta_x = get_delta_x(lower_bound, upper_bound, subintervals[i])
        riemann_sum = get_riemann_sum(x, delta_x)
        y = f(x)
        dims = 221+i
        plt.subplot(dims)
        plt.plot(x, y, color='C0')
        plt.bar(
            x, y, color="C"+str(i),
            width=(upper_bound-lower_bound)/subintervals[i],
            alpha=0.2, align='edge', edgecolor="C"+str(i),
            label=f"{riemann_sum}")
        plt.title(f'N = {subintervals[i]}')
        plt.grid()
        plt.legend()

    fig.suptitle(r"Riemann Integral of $sin(x)$")
    plt.show()

def main():
    # Type in the command line:
    # python3 numerical_analysis/riemann_integral.py -lb 0 -ub 5 -sub 10 20 50 100

    parser = argparse.ArgumentParser(description="Riemann Integrals")
    parser.add_argument(
        '-lb',
        '--LOWER_BOUND',
        type=int,
        help='Lower Bound'
    )
    parser.add_argument(
        '-ub',
        '--UPPER_BOUND',
        type=int,
        help='Upper Bound'
    )
    parser.add_argument(
        '-sub',
        '--SUBINTERVALS',
        nargs='+',
        type=int,
        help='Subintervals'
    )
    args = vars(parser.parse_args())

    LOWER_BOUND = args['LOWER_BOUND']
    UPPER_BOUND = args['UPPER_BOUND']
    SUBINTERVALS = args['SUBINTERVALS']

    if len(SUBINTERVALS) == 4:
        riemann_integral(LOWER_BOUND, UPPER_BOUND, SUBINTERVALS)
    else:
        print("input only four subintervals")

if __name__ == '__main__':
    main()


# coding: utf-8

# ### DEMAPP07

# # Solve Cournot oligopoly model via collocation

# To illustrate implementation of the collocation method for implicit function problems, consider the example of Cournot oligopoly. In the standard microeconomic model of the firm, the firm maximizes profit by equating marginal revenue to marginal cost (MC). An oligopolistic firm, recognizing that its actions affect price, takes the marginal revenue to be $p + q\frac{dp}{dq}$, where $p$ is price, $q$ is quantity produced, and $\frac{dp}{dq}$ is the marginal impact of output on market price. The Cournot assumption is that the firm acts as if any change in its output will be unmatched by its competitors. This implies that
#
# \begin{equation}
#     \frac{dp}{dq} = \frac{1}{D'(p)}
# \end{equation}
#
# where $D(p)$ is the market demand curve.
#
# Suppose we wish to derive the effective supply function for the firm, which specifies
# the quantity $q = S(p)$ it will supply at any price. The firm's effective supply function is
# characterized by the functional equation
#
# \begin{equation}
#     p + \frac{S(p)}{D'(p)} - MC(S(p)) = 0
# \end{equation}
#
# for all positive prices $p$. In simple cases, this function can be found explicitly.  However,
# in more complicated cases, no explicit solution exists.

# In[1]:

import numpy as np
import matplotlib.pyplot as plt
from compecon import BasisChebyshev, NLP, demo

# ### Model parameters
#
# Here, the demand elasticity and the marginal cost function parameter are

# In[2]:

alpha, eta = 1.0, 3.5

# In[3]:

D = lambda p: p**(-eta)

# ### Approximation structure
#
# A degree-25 Chebychev basis on the interval [0.5, 3.0] is selected; also, the associated collocation nodes `p` are computed.

# In[4]:

n, a, b =  25, 0.5, 2.0
S = BasisChebyshev(n, a, b, labels=['price'], y=np.ones(n))
p = S.nodes

# In[5]:

S2 = BasisChebyshev(n, a, b, labels=['price'], l=['supply'])
S2.y = np.ones_like(p)

# ### Residual function
#
# Suppose, for example, that
#
# \begin{equation}
#     D(p) = p^{-\eta} \quad\text{and}\quad MC(q) = \alpha\sqrt{q} + q^2
# \end{equation}
#
# Then the functional equation to be solved for S(p),
#
# \begin{equation}
#  \left[p - \frac{S(p)p^{\eta+1}}{\eta}\right] -\left[\alpha\sqrt{S(p)} + S(p)^2\right] = 0
# \end{equation}
#
# has no known closed-form solution.

# In[6]:

def resid(c):
    S.c = c  # update interpolation coefficients
    q = S(p) # compute quantity supplied at price nodes
    return p - q * (p ** (eta+1) / eta) - alpha * np.sqrt(q) - q ** 2

# Notice that `resid` only takes one argument. The other parameters (`Q`, `p`, `eta`, `alpha`) should be declared as such in the main script, were Python's scoping rules will find them.

# ### Solve for effective supply function
#
# Class `NLP` defines nonlinear problems. It can be used to solve `resid` by Broyden's method.

# In[7]:

cournot = NLP(resid)
S.c = cournot.broyden(S.c, tol=1e-12)

# ### Plot demand and effective supply for m=5 firms

# In[8]:

prices = np.linspace(a, b, 501)
fig1 = demo.figure('Cournot Effective Firm Supply Function',
            'Quantity', 'Price', [0, 4], [0.5, 2])
plt.plot(5 * S(prices), prices, D(prices), prices)
plt.legend(('Supply','Demand'))

# ### Plot residual
#
# Notice that `resid` does not take explicit parameters, so to evaluate it when prices are `prices` we need to assign `p = prices`.

# In order to assess the quality of the approximation, one plots the residual function over the approximation domain. Here, the residual function is plotted by computing the residual at a refined grid of 501 equally spaced points.

# In[9]:

p = prices
fig2 = demo.figure('Residual Function for Cournot Problem',
            'Quantity', 'Residual')
plt.hlines(0, a, b, 'k', '--', lw=2)
plt.plot(prices, resid(S.c))

# ### Plot demand and effective supply for m=1, 3, 5, 10, 15, 20 firms

# In[10]:

fig3 = demo.figure('Industry Supply and Demand Functions',
            'Quantity', 'Price', [0, 12], figsize=[9,4])

lcolor = [z['color']  for z in plt.rcParams['axes.prop_cycle']]

for i, m in enumerate([1, 3, 5, 10, 15, 20]):
    plt.plot(m*S(prices), prices) # supply
    demo.annotate(m*S(1.2)-0.25,1.4-i/12,f'm={m:d}',color=lcolor[i],ms=0,fs=12)

plt.plot(D(prices), prices, linewidth=4, color='grey') # demand
demo.annotate(10,0.5,'demand',color='grey', ms=0, fs=12)

# ### Plot equilibrium price as a function of number of firms m

# In[14]:

pp = (b + a) / 2
dp = (b - a) / 2
m  = np.arange(1, 26)
for i in range(50):
    dp /= 2
    pp = pp - np.sign(S(pp) * m - pp ** (-eta)) * dp

fig4 = demo.figure('Cournot Equilibrium Price as Function of Industry Size',
            'Number of Firms', 'Price')
plt.plot(m, pp)

# In[12]:

demo.savefig([fig1,fig2,fig3,fig4])


import numpy as np
import sympy as sp
from sympy.core import S, Dummy
from sympy.functions.special.gamma_functions import gamma
from sympy.polys.orthopolys import (legendre_poly, laguerre_poly,
                                    hermite_poly, jacobi_poly)
from sympy.polys.rootoftools import RootOf

def gauss_laguerre(n, n_digits):
    r"""
    Computes the Gauss-Laguerre quadrature [1]_ points and weights.

    The Gauss-Laguerre quadrature approximates the integral:

    .. math::
        \int_0^{\infty} e^{-x} f(x)\,dx \approx \sum_{i=1}^n w_i f(x_i)

    The nodes `x_i` of an order `n` quadrature rule are the roots of `L_n`
    and the weights `w_i` are given by:

    .. math::
        w_i = \frac{x_i}{(n+1)^2 \left(L_{n+1}(x_i)\right)^2}

    Parameters
    ==========

    n : the order of quadrature

    n_digits : number of significant digits of the points and weights to return

    Returns
    =======

    (x, w) : the ``x`` and ``w`` are lists of points and weights as Floats.
             The points `x_i` and weights `w_i` are returned as ``(x, w)``
             tuple of lists.

    Examples
    ========

    >>> from sympy.integrals.quadrature import gauss_laguerre
    >>> x, w = gauss_laguerre(3, 5)
    >>> x
    [0.41577, 2.2943, 6.2899]
    >>> w
    [0.71109, 0.27852, 0.010389]
    >>> x, w = gauss_laguerre(6, 5)
    >>> x
    [0.22285, 1.1889, 2.9927, 5.7751, 9.8375, 15.983]
    >>> w
    [0.45896, 0.417, 0.11337, 0.010399, 0.00026102, 8.9855e-7]

    See Also
    ========

    gauss_legendre, gauss_gen_laguerre, gauss_hermite, gauss_chebyshev_t, gauss_chebyshev_u, gauss_jacobi, gauss_lobatto

    References
    ==========

    .. [1] https://en.wikipedia.org/wiki/Gauss%E2%80%93Laguerre_quadrature
    .. [2] http://people.sc.fsu.edu/~jburkardt/cpp_src/laguerre_rule/laguerre_rule.html
    """
    x = Dummy("x")
    p = laguerre_poly(n, x, polys=True)
    p1 = laguerre_poly(n+1, x, polys=True)
    xi = []
    w = []
    for r in p.real_roots():
        if isinstance(r, RootOf):
            r = r.eval_rational(S(1)/10**(n_digits+2))
        xi.append(r.n(n_digits))
        w.append((r/((n+1)**2 * p1.subs(x, r)**2)).n(n_digits))
    return xi, w

digits = 36
npoints = list(range(1,17))

for n in npoints:
    xi, wi = gauss_laguerre(n, digits)

    print('\nN = %3d'%(n))
    for i in range(0,n):
        print('%3d %40.36f %40.36f'%(i+1,xi[i],wi[i]))


import numpy as np

def Identity(X):
    """
    Identity fuction is the basic activation function
    It return the same input value as output.

    Parameters:
    - X: int ,-Inf to +Inf

    Returns:
    X , -Inf to +Inf
    """
    return X

def BinaryStep(X):
    """
    BinaryStep fuction is the basic activation function
    It return 0 for non positive value  and 1 for all the positive

    Parameters:
    - X: int -Inf to +Inf

     Returns:
     int (0 OR 1)
    """
    return 0 if X < 0 else 1

def Linear(X, constant=1):
    return constant*X

def dLinear(constant=1):
    return constant

def Sigmoid(X):
    res = 1 / (1 + np.exp(-X))
    return res

def dSigmoid(X):
    return Sigmoid(X) * (1-Sigmoid(X))

def Tanh(X):
    return np.tanh(X)

def dTanh(X):
    return 1 - np.power(np.tanh(X), 2)

def ReLu(X):
    return np.maximum(0, X)

def dReLu(X):
    return 1 if X > 0 else 0

def Leaky_ReLu(X, factor=0.01):
    return np.maximum(factor*X, X)

def dLeaky_ReLu(X, factor=0.01):
    return 1 if X > 0 else factor

# TODO: d/dX

def Softmax(X):
    exp = np.exp(X)
    exp_sum = np.sum(np.exp(X))
    res = exp/exp_sum
    return res

def StableSoftmax(X):
    """A stable implementation of the softmax function which prevents division by a large number (overflow) """
    shift = X - np.max(X)
    exp = np.exp(shift)
    return exp/np.sum(exp)

def dSoftmax(X):
    """Derivation of the softmax activation function. Derived from the iterative implementation which uses jacobians """
    s = Softmax(X)
    s = s.reshape(-1,1)
    return np.diagflat(s) - np.dot(s, s.T)

def GeLu(X):
    res = 0.5 * X * (1 + np.tanh(np.sqrt(2 / np.pi) *
                                 (X + 0.044715 * np.power(X, 3))))
    return res


#!/usr/bin/python

"""
Misc Experiments:
+ graphing techniques
+ Maths Equations
"""
# PYLINT: ENTIRE SCOPE
# pylint: disable=missing-function-docstring
# pylint: disable=use-list-literal

# IMPORTS
# Order: Std, 3rdParty, CustomLocal
import matplotlib.pyplot as plt
import numpy as np

DEF_ENCODING = 'utf-8'

# pylint: disable=too-many-arguments
def plot_2d_cartesian(
        x_list, y_list, title=None, xlabel=None, ylabel=None,
        figwidth=10, figheight=4, out_path=None, only_show=True
    ):
    fig = plt.figure()
    fig.set_figwidth(figwidth)
    fig.set_figheight(figheight)
    plt.title(title if title else '')
    plt.xlabel(xlabel if xlabel else '')
    plt.ylabel(ylabel if ylabel else '')
    plt.plot(x_list, y_list)
    if not only_show and out_path:
        plt.savefig(out_path)
    else:
        plt.show()
    # plt.savefig(out_path) if (out_path and not only_show) else plt.show()

# pylint: disable=too-many-locals
# pylint: disable=too-many-arguments
def plot_2d_cartesian_multiple(
        x_list, y_arrays, y_labels=None, title=None, xlabel=None, ylabel=None,
        figwidth=10, figheight=4, out_path=None, only_show=True
    ):
    fig = plt.figure()
    fig.set_figwidth(figwidth)
    fig.set_figheight(figheight)
    plt.title(title if title else '')
    plt.xlabel(xlabel if xlabel else '')
    plt.ylabel(ylabel if ylabel else '')
    y_colours = { 0: 'red', 1: 'green', 2: 'blue', 3: 'orange', 4: 'purple'}
    for index, y_list in enumerate(y_arrays):
        p_colour = y_colours.get(index) if index < len(y_arrays) else y_colours.get(0)
        y_label = str(y_labels[index]) if (y_labels and index < len(y_arrays)) else 'default'
        plt.plot(x_list, y_list, color=p_colour, label=y_label)
    plt.legend()
    if not only_show and out_path:
        plt.savefig(out_path)
    else:
        plt.show()

def plot_single_line_graph_2d(x_list, y_arrays, index=0):
    h_prefix = 'Experiment: FootBall FreeKick as a MATHS Equation'
    heading = f'{h_prefix}: y = d(-a(x+b)^2+c): y_index: {index}'
    graph_fpath = f'./data/football_freekick_{index}.png'
    x_desc = 'Length on FootBallPitch, metres'
    y_desc = 'Height off Ground, metres'
    fwidth = 10
    fheight = 4
    plot_2d_cartesian(
        x_list, y_arrays[index], title=heading, xlabel=x_desc, ylabel=y_desc,
        figwidth=fwidth, figheight=fheight, out_path=graph_fpath,
        only_show=False
    )

def plot_multi_line_graph_2d(x_list, y_arrays, y_legends=None):
    heading = 'Experiment: FootBall FreeKick as a MATHS Equation: y = d(-a(x+b)^2+c): multiple values of c'
    graph_fpath = './data/football_freekick.png'
    x_desc = 'Length on FootBallPitch, metres'
    y_desc = 'Height off Ground, metres'
    fwidth = 10
    fheight = 4
    plot_2d_cartesian_multiple(
        x_list, y_arrays, y_labels=y_legends, title=heading, xlabel=x_desc, ylabel=y_desc,
        figwidth=fwidth, figheight=fheight, out_path=graph_fpath,
        only_show=False
    )

def main():
    """ Misc Experiments, testing modules """

    # Graph a FootBall FreeKick: As a Quadratic Equation:
    # y = d(-a(x + b)^2 + c)
    # where a < 1.0, b ~= 10m, c ~=3m, d ~=1/40

    # xData
    length_to_goal = 30
    x_list = list(np.arange(0, length_to_goal+1, 1))
    print(f'DEBUG: x_list: array: {x_list}')

    # yInfo
    # Freekick Dimensions: wall: 2.0 - 2.5m, goal: 1.8 - 2.2m
    # pylint: disable=invalid-name
    input_data = {
        "a_possibles": [0.3, 0.4, 0.5, 0.6, 0.7],
        "b_possibles": [-24, -22, -20, -18, -16],
        "c_possibles": [135, 140, 142, 145, 150],
        "d_possibles": [0.020, 0.021, 0.022, 0.023, 0.024]
    }
    a = 0.36
    b = -20.0
    c = 142
    d = 0.020
    dpi = 3

    # Experiment with ranges, identify most realistic/True
    y_arrays = list()
    y_varlist = input_data.get('c_possibles')
    print(f'DEBUG: default variables: a: {a}, b: {b}, c: {c}, d: {d}')
    for c in y_varlist:
        y_list = [round((d * (-a * (x_val + b)**2 + c)), dpi) for x_val in x_list]
        print(f'DEBUG: c: {c} y_list: array: {y_list}')
        y_arrays.append(y_list)

    # Plot: Cartesian, Line: Multiple
    med = int((len(y_arrays) - 1) / 2)
    plot_single_line_graph_2d(x_list, y_arrays, index=med)

    # Plot: Cartesian, Line: Med(ian)
    plot_multi_line_graph_2d(x_list, y_arrays, y_legends=y_varlist)

if __name__ == '__main__':
    main()


import numpy as np
import time as time
import matplotlib.pyplot as plt
import matplotlib as mpl

def Function(x,y):
    z = (x-10)**2 + (y-20)**2
    return(z)

def PSO(iterations,swarm_size,particle_best_XY,global_best_XY,\
        particle_XY,particle_velocity,global_best_value):
    best_value = []
    locBest = []
    iteration_value_best = []
    locList_best = []
    iteration_value = []
    locList = []
    for i in range(iterations):
        for j in range(swarm_size):
            for k in range(2): n
                u = np.random.rand(2)
                error_particle_best = particle_best_XY[j,k] - particle_XY[j,k]
                error_global_best = global_best_XY[k] - particle_XY[j,k]
                v_new = inertia*particle_velocity[j,k] + \
                    local_weight*u[0]*error_particle_best + \
                    global_weight*u[1]*error_global_best
                if v_new < -max_velocity:
                    v_new = -max_velocity
                elif v_new > max_velocity:
                    v_new = max_velocity
                particle_XY[j,k] = particle_XY[j,k] + v_new*step_size
                particle_velocity[j,k] = v_new
            v = Function(particle_XY[j,0],particle_XY[j,1])
            if v < particle_best_value[j]:
                particle_best_value[j]=v
                particle_best_XY[j,:] = particle_XY[j,:].copy()
            if v < global_best_value:
                global_best_value=v
                global_best_XY = particle_XY[j,:].copy()
        print('x='+'%.2f' % global_best_XY[0]+', y='+'%.2f' % global_best_XY[1])
        best_value.append(global_best_value.copy())
        locBest.append(global_best_XY.copy())
        iteration_value.append(v)
        locList.append(particle_XY.copy())
        v = Function(particle_XY[:,0].copy(),particle_XY[:,1].copy())
        iteration_value_best.append(np.min(v))
        locList_best.append(particle_XY[np.argmin(v),:])
    return locList,locBest

def plot_PSO_result(locList,locBest):
    plt.figure(figsize=(5,5))
    plt.grid('on')
    plt.rc('axes', axisbelow=True)
    plt.scatter(10,20,100,marker='*',facecolors='k', edgecolors='k')
    for i in range(len(locList)):
        plt.scatter(locList[i][:,0],locList[i][:,1],10,marker='x')
        plt.scatter(locBest[i][0],locBest[i][1],50,marker='o',\
                    facecolors='none',edgecolors='k',linewidths=0.4)
        plt.text(locBest[i][0]+0.1,locBest[i][1]+0.1,str(i),fontsize=8)
    plt.xlim(-1,15)
    plt.ylim(-1,23)
    plt.xlabel('$x$')
    plt.ylabel('$y$')
    plt.title('Particle Swarm Optimization')
    plt.savefig('results',dpi=300)
    plt.show()

if __name__ == "__main__":
    swarm_size = 5
    iterations = 26
    inertia = 0.5
    local_weight = 2
    global_weight =  2
    max_velocity = 1
    step_size = 1
    particle_XY = np.random.rand(swarm_size,2)-0.5
    particle_velocity = np.random.rand(swarm_size,2)
    particle_best_value = Function(particle_XY[:,0],particle_XY[:,1])
    particle_best_XY = np.copy(particle_XY)
    global_best_value = np.min(particle_best_value)
    global_best_XY = particle_XY[np.argmin(particle_best_value)].copy()
    locList,locBest = PSO(iterations,swarm_size,particle_best_XY,\
                          global_best_XY,particle_XY,particle_velocity,global_best_value)
    plot_PSO_result(locList,locBest)


# -*-coding= utf-8 -*-
import numpy as np
import matplotlib.pyplot as plt
import math
from scipy.integrate import odeint
import numpy as np

def func(y, t):
    return y-2*t*y

def forward_Euler(x0,y0,N,h):
	# Forward Euler/Explicit time-forward
	x=np.zeros((N+1,1))
	y=np.zeros((N+1,1))
	y[0]=y0
	x[0]=x0
	for i in range(1,N+1):
		x[i]=x0+i*h#here,x==t
		y[i]=y[i-1]+func(y[i-1],x[i-1])*h
	return y

def back_Euler(x0,y0,N,h):
	# Backward Euler/Implicit time-forward
	#预报-校正法
	x=np.zeros((N+1,1))
	y=np.zeros((N+1,1))
	y_=np.zeros((N+1,1))
	x[0]=x0
	y[0]=y0
	y_[0]=y0
	for i in range(1,N+1):
		x[i]=x0+i*h#here,x==t
		y_[i]=y_[i-1]+func(y_[i-1],x[i-1])*h
		y[i]=y[i-1]+func(y_[i],x[i])*h
	return y
if __name__=='__main__':
	# 初始条件
	x0=0
	y0=1
	# x的范围
	xn=2
	# 精度调节
	h=0.01
	N=int((xn-x0)/h)
	#-----------------------------
	# 生成自变量t
	t=np.zeros((N+1,1))
	#----------------------------
	# Explicit solution
	for ii in range(1,N+1):
		t[ii]=x0+ii*h
	t=t.flatten()
	YS=odeint(func,y0=1,t=t)
	#-----------------------------
	y_back=back_Euler(x0,y0,N,h)
	#-----------------------------
	y_for=forward_Euler(x0,y0,N,h)
	# draw
	plt.plot(t,y_for, label='Euler-forward')
	plt.plot(t,y_back, label='Euler-backward')
	plt.plot(t, YS, label='Explicit')
	plt.legend()
	plt.show()


import numpy as np
import matplotlib.pyplot as plt

N_0 = int(input('Give initial population size N_0: '))
r   = float(input('Give net growth rate r: '))
dt  = float(input('Give time step size: '))
N_t = int(input('Give number of steps: '))

t = np.linspace(0, N_t*dt, N_t+1)
N = np.zeros(N_t+1)

N[0] = N_0
for n in range(N_t):
    N[n+1] = N[n] + r*dt*N[n]

numerical_sol = 'bo' if N_t < 70 else 'b-'
plt.plot(t, N, numerical_sol, t, N_0*np.exp(r*t), 'r-')
plt.legend(['numerical', 'exact'], loc='upper left')
plt.xlabel('t'); plt.ylabel('N(t)')
filestem = 'growth1_{:d}steps'.format(N_t)
plt.savefig('{:s}.png'.format(filestem))
plt.savefig('{:s}.pdf'.format(filestem))


import math
import numpy as np

class variable:

    def __init__(self,val,der=1):
        """
            Initialize a variable object
            with a specified value and derivative.
            Expect scalar for val. Expect scalar
            or a numpy array for der.
            If no derivative is specified,
            a seed of 1 is assumed.
        """

        self._val = val
        assert isinstance(der, (np.ndarray, float, int)), "der must be a scalar or a numpy array"
        self._der = der

    @property
    def val(self):
        return self._val

    @property
    def der(self):
        return self._der

    def __repr__(self):
        """
            Define representation of variable object:
        """
        return "awesomediff.variable(val={},der={})".format(self.val,self.der)

    def __neg__(self):
        """
            Overload negation.
            Returns a variable object with:
            val : negated value.
            der : negated derivative.
        """
        return variable(val=-self.val,der=-self.der)

    def __add__(self,other):
        """
            Overload addition.
            Returns a variable object with:
            val : sum of values.
            der : sum of derivatives.
        """
        self_val = self.val
        self_der = self.der
        try:
            # Assume other object is a variable:
            other_val = other.val
            other_der = other.der
        except:
            # If not, use this value and derivative 0.
            try:
                float(other)
            except:
                raise ValueError("{} is not a number.".format(other))
            other_val = other
            other_der = 0  # Derivative of a constant is zero.
        # Calculate new values (simple summation):
        new_val = self_val + other_val
        new_der = self_der + other_der
        # Return variable with new value and derivative:
        return variable(val=new_val,der=new_der)

    def __radd__(self,other):
        """
            Overload reverse addition by calling __add__().
        """
        return self.__add__(other)

    def __mul__(self,other):
        """
            Overload multiplication.
            Returns a variable object with:
            val : product of values.
            der : result of product rule
        """
        self_val = self.val
        self_der = self.der
        try:
            # Assume other object is a variable:
            other_val = other.val
            other_der = other.der
        except:
            # If not, uses this value and derivative 0.
            try:
                float(other)
            except:
                raise ValueError("{} is not a number.".format(other))
            other_val = other
            other_der = 0  # Derivative of a constant is zero.
        # Calculate new values (applying product rule):
        new_val = self_val * other_val
        new_der = (self_der * other_val) + (self_val * other_der)
        # Return variable with new value and derivative:
        return variable(val=new_val,der=new_der)

    def __rmul__(self,other):
        """
            Overload reverse multiplication
            Calls __mul__.
        """
        return self.__mul__(other)

    def __sub__(self,other):
        """
            Overload subtraction.
            Implemented using negation and addition.
        """
        return self.__add__(-other)

    def __rsub__(self,other):
        """
            Overload reverse subtraction.
            Implemented using negation and addition.
        """
        return self.__neg__().__add__(other)

    def __truediv__(self, other):
        try:
            # assume other is an instance variable
            new_val = self.val / other.val
            new_der = (self.der * other.val - self.val * other.der) / other.val ** 2
        except:
            # assume in the form of variable/scaler
            try:
                float(other)
            except:
                raise ValueError("{} is not a number or instance variable.".format(other))

            if float(other) == 0:
                raise ZeroDivisionError('Cannot perform division by zero')
            new_val = self.val / float(other)
            new_der = self.der / float(other)

        return variable(val=new_val, der=new_der)

    def __rtruediv__(self, other):
        new_val = other / self.val
        new_der = -other * self.val ** (-2)  # other*self.pow(-1)
        return variable(val=new_val, der=new_der)

    def __eq__(self, other):
        """
            Overload equal
            Check if the thing compared to is a variable and has the same vale
        """
        return isinstance(other, variable) and self.val == other.val

    def __ne__(self, other):
        """
            Overload not equal
            Check if the thing compared to is a variable and does not have the same vale
        """
        return not isinstance(other, variable) or not (self.val == other.val)

    def __lt__(self, other):
        """
            Overload less than
        """
        try:
            return self.val<other.val
        except:
            raise AttributeError("Can only compare varibles.")

    def __gt__(self, other):
        """
            Overload greater than
        """
        try:
            return self.val>other.val
        except:
            raise AttributeError("Can only compare varibles.")

    def __le__(self, other):
        """
            Overload less than or equal to
        """
        try:
            return self.val<=other.val
        except:
            raise AttributeError("Can only compare varibles.")

    def __ge__(self,other):
        """
            Overload greater than or equal to
        """
        try:
            return self.val>=other.val
        except:
            raise AttributeError("Can only compare varibles.")

    def __pow__(self, other):
        try:
            # check whether other is a number
            new_val = self.val ** other
        except:
            raise ValueError("{} must be a number.".format(other))
        new_der = other * self.val ** (other - 1) * self.der
        return variable(val=new_val, der=new_der)

    def __rpow__(self, other):
        try:
            new_val = other** self.val
        except:
            raise ValueError("{} must be a number.".format(other))
        new_der = other**self.val * np.log(other)
        return variable(val=new_val, der=new_der)

def _build_jacobian(outputs):
    """
    INPUT:
        outputs: a list of awesomediff.variable objects
    OUTPUT:
        returns n x m jacobian matrix where n is the number of functions
        and m is the total number of variables

    EXAMPLE:
    outputs = [awesomediff.variable(val=5, der=[4]), awesomediff.variable
    (val=0.5, der=[0.5])]

    ## _build_jacobian(outputs)
    [[4]
     [0.25]]

    """
    n = len(outputs) # get number of functions
    m = len(outputs[0].der) # get number of variables
    jacobian = np.zeros((n,m))
    for i, output in enumerate(outputs):
         jacobian[i,:] = output.der

    return jacobian

def evaluate(func,vals,seed=None):
    """
        A wapper function that evaluates a user-defined function
        using awesomediff.variable objects.
        INPUTS:
            func: A user-defined function of n variables and m functions
                that will be evaluated to find the value and derivative
                at a specified point.
                The user-defined function may take one or more variables
                as arguments and may return one or more function outputs (as a list).
                Functions may include basic operations (+,*,etc),
                as well as any special functions supported by awesomediff.

            vals: A scalar (for univariate function) or a list of scalars
                (for multivariate function) at which to evaluate the function
                and its derivative.

            seed: A scalar (for univariate function) or a list of lists (for multivariate
                function) containing seed values for each variable. The lengths of the
                outer list and inner list must equal the number of arguments taken by `func`
                (i.e. the number of variables). Defaults to a seed of 1 for each
                variable if no seed value is provided.

                EXAMPLE:
                To set seed of variables x, y, z at 1, 2, and 3, respectively, user
                passes the following list of lists as seed:
                [[1,0,0],[0,2,0],[0,0,3]]
                The length of outer list and the lengths of each of the inner lists
                must be equal to the total number of variables (in this example, 3)
        ...
        RETURNS:
            output_value: value of function at a specified point. A scalar for
            a function, a vector of scalars for a vector function

            jacobian: the jacobian of function. A vector of scalar or scalars
            for univariate and multivariate functions, respectively. A matrix of
            scalars for univariate and multivariate vector functions
        ...
        EXAMPLE:
        ## def parametric_ellipse(a,b,t):
                x = a * ad.cos(t)
                y = b * ad.sin(t)
                return [x, y]
        ## output_value, jacobian = ad.evaluate(func=parametric_ellipse,vals=[4,2,0])

        ## output_value
        np.array([4, 0])    # [a*cos(t), b*sin(t)]

        ## jacobian
        np.array([[1,0,0],[0,0,4]]) #[[cos(t), 0, -a*sin(t)],[0 , sin(t), a*cos(t)]]
    """

    ## check user input for vals and convert it to numpy array
    # user input for vals will be a scalar for univariate function and
    # a list of scalars for multivariate function
    try:
        float(vals) # if vals is a scalar
        vals = np.array([vals])
    except:
        if isinstance(vals, list): # if vals is a list
            vals = np.array(vals)

    ## get number of values that were passed as inputs
    num_vars = len(vals)

    ## check user input for seed
    # user input for seed will be a scalar for univariate function and
    # a list of scalars for multivariate function

    # if user doesn't pass in value for seed argument, create seed with value of 1
    if seed == None:
        if num_vars == 1: #if univariate function
            seed = np.array([1])
        else: #if multivariate function
            seed_matrix = np.identity(num_vars)

    #if user passes in value for seed argument
    else:
        try:
            float(seed) # if seed is a scalar
            seed = np.array([seed])
        except:
            if isinstance(seed, list): # if seed is a list
                # check length of outer list
                assert len(seed) == num_vars, "length of outer list must equal number of variables"

                # check length of inner list
                for s in seed:
                    try:
                        len(s)
                    except: # seed for univariate function given as a list
                        raise ValueError("seed for univariate function should be given as a scalar")
                    assert len(s) == num_vars, "length of inner list must equal number of variables"

                seed_matrix = np.array(seed)

            else: # if seed is not provided as a scalar or a list
                raise ValueError("seed must be provided as a scalar or a list")

    ## evaluate the user-defined function passed in

    # instantiate awesomediff.variable objects
    if num_vars == 1: # if univariate function
        var = variable(val=vals[0], der=seed)
        inputs = [var]
    else: # if multivariate function
        inputs = []
        for i,v in enumerate(vals):
            var = variable(val=v,der=seed_matrix[i,:])
            inputs.append(var)

    # pass awesomediff.variable objects into user-defined function
    # outputs will be an awesomediff.variable object or a list of
    # awesomediff.variable objects storing values and derivatives of functions
    try:
        outputs = func(*inputs)
    except Exception as e:
        raise RuntimeError("function evaluation failed with the following error: {}".format(e))

    # create output_value and jacobian
    try: # if a vector-function
        len(outputs)
        output_value = np.zeros(len(outputs))
        for i,output in enumerate(outputs):
            output_value[i] = output.val
        jacobian = _build_jacobian(outputs)

    except: # if not a vector function
        output_value = outputs.val
        jacobian = outputs.der

    return output_value, jacobian


import numpy as np
import math

def trapezoidal(n,f):
    sum = .5*(f(0.) + f(1.))
    for k in range (1,n):
        sum += f(1.*k/n)
    return sum/n

def romberg(n0,steps,order,quadrature,f):
    res = np.zeros((steps,steps))
    for i in range(0,steps):
        n = n0 * 1<<i
        res[i,0] = quadrature(n,f)
        for j in range(1,i+1):
            res[i,j] = res[i,j-1] + \
            (res[i,j-1]-res[i-1,j-1])/(2**(order*j)-1.)
    return res

def func(x):
    return np.sin(np.pi*x)

initial = 2
steps = 5
exact = 2./np.pi

result = romberg(initial,steps,2,trapezoidal,func)
print(result)

logerror = np.zeros((steps,steps))

print("Fehler")
for k in range (0,steps):
    print ("Spalte ", k)
    for i in range (k,steps):
        e = abs(exact-result[i,k])
        print ("Zeile ", i, " Fehler ", e, "\tLog ", math.log2(e))
        logerror[i,k] = math.log2(e)

print("Experimentelle Ordnungen")
for k in range (0,steps):
    print ("Spalte ", k)
    for i in range (k+1,steps):
        p = logerror[i-1,k]-logerror[i,k]
        print (p)

diff = np.zeros((steps,steps))

print("Intrinsische Ordnungen")
for k in range (0,steps):
    print ("Spalte ", k)
    for i in range (k+1,steps):
        diff[i,k] = result[i,k] - result[i-1,k]


import numpy as np

def generate_target():
    # Generate the target function f
    div_points = np.random.uniform(low=-1, high=1, size=(2, 2))
    w1 = (div_points[1, 1] - div_points[0, 1])/(div_points[1, 0] - div_points[0, 0])
    w0 = div_points[0, 1] - div_points[0, 0]*w1
    w = np.array([w0, w1, -1])
    return w

def generate_sample(num_points, w):
    # Generate the test points and classify
    test_points = np.ones([num_points, 4])
    test_points[:, 1:3] = np.random.uniform(low=-1, high=1, size=(num_points, 2))
    test_points[:, 3] = np.sign(np.dot(test_points[:, 0:3], w))
    return test_points

def log_regression(training, g_init=np.zeros(3), tol=1e-6, max_iter=10**4, eta=0.1):
    d_E = lambda W, x_n, y_n: (-y_n * x_n)/(1+np.exp(y_n * W.dot(x_n)))

    g = np.copy(g_init)
    w = np.zeros(3)
    old_w = np.copy(w)
    iters = 0
    n_points, n_cols = training.shape
    y = training[:, -1]
    X = training[:, 0:n_cols-1]
    error = tol+1

    while True:
        old = np.copy(g)
        for i in np.random.permutation(n_points):
            xn = X[i]
            yn = y[i]
            g += eta*(yn*xn)/(1 + np.exp(yn*np.dot(xn, g)))
        iters += 1
        error = np.linalg.norm(g - old)
        error1 = np.linalg.norm(old_w - w)
        if error < tol:
            break
        old_w = np.copy(w)

    return g, iters

NTRIALS = 10
NPOINTS = 100
MCPOINTS = 10**6
mcdata = np.ones([MCPOINTS, 3])
mcdata[:, 1:3] = np.random.random([MCPOINTS, 2])
e_out = np.zeros(NTRIALS)
iters = np.zeros(NTRIALS)
for i in range(0, NTRIALS):
    w = generate_target()
    training = generate_sample(NPOINTS, w)
    g, iters[i] = log_regression(training, tol=0.01)
    g = -g/g[2]
    e_out[i] = np.mean(np.log(1+np.exp(-np.sign(np.dot(mcdata,w))*np.dot(mcdata, g))))

print(np.mean(e_out))
print(np.mean(iters))

# perfect_error = np.mean(np.log(1+np.exp(-np.sign(np.dot(mcdata,np.array([0.5,0.5,-1])))*np.dot(mcdata,np.array([0.5,0.5,-1])))))
# print(perfect_error)


import numpy as np

def waverage(x,sigx):
    # Weighted average
    # Bryan Miller
    # 2014-06-10
    # References: http://en.wikipedia.org/wiki/Weighted_arithmetic_mean
    # http://stats.stackexchange.com/questions/47325/bias-correction-in-weighted-variance

    ax = np.array(x)
    asigx = np.array(sigx)

    w = 1./asigx**2
    xw = ax*w
    sumw = np.sum(w)
    sumwsq = np.sum((w**2))
    sumxw = np.sum(xw)

    # Weighted average
    mean = sumxw/sumw
    # Standard deviation of the mean (weighted)
    sigmean = 1./np.sqrt(sumw)
    # Unbiased estimator of the weighted population variance
    sigpop = np.sqrt(sumw*(np.sum(w*(x-mean)**2))/(sumw**2 - sumwsq))
    # Variance in the weighted mean (account for error underestimate)
    # sigwm = np.sqrt(sigmean*(np.sum(w*(x-mean)**2))/(len(ax) - 1.))

    return mean, sigmean, sigpop


# Perform the necessary imports
import matplotlib.pyplot as plt
from scipy.stats import pearsonr

# Assign the 0th column of grains: width
width = grains[:,0]

# Assign the 1st column of grains: length
length = grains[:,1]

# Scatter plot width vs length
plt.scatter(width, length)
plt.axis('equal')
plt.show()

# Calculate the Pearson correlation
correlation, pvalue = pearsonr(width, length)

# Display the correlation
print(correlation)

# Import PCA
from sklearn.decomposition import PCA

# Create PCA instance: model
model = PCA()

# Apply the fit_transform method of model to grains: pca_features
pca_features = model.fit_transform(grains)

# Assign 0th column of pca_features: xs
xs = pca_features[:,0]

# Assign 1st column of pca_features: ys
ys = pca_features[:,1]

# Scatter plot xs vs ys
plt.scatter(xs, ys)
plt.axis('equal')
plt.show()

# Calculate the Pearson correlation of xs and ys
correlation, pvalue = pearsonr(xs, ys)

# Display the correlation
print(correlation)

# Make a scatter plot of the untransformed points
plt.scatter(grains[:,0], grains[:,1])

# Create a PCA instance: model
model = PCA()

# Fit model to points
model.fit(grains)

# Get the mean of the grain samples: mean
mean = model.mean_

# Get the first principal component: first_pc
first_pc = model.components_[0,:]

# Plot first_pc as an arrow, starting at mean
plt.arrow(mean[0], mean[1], first_pc[0], first_pc[1], color='red', width=0.01)

# Keep axes on same scale
plt.axis('equal')
plt.show()

# Perform the necessary imports
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import make_pipeline
import matplotlib.pyplot as plt

# Create scaler: scaler
scaler = StandardScaler()

# Create a PCA instance: pca
pca = PCA()

# Create pipeline: pipeline
pipeline = make_pipeline(scaler, pca)

# Fit the pipeline to 'samples'
pipeline.fit(samples)

# Plot the explained variances
features = range(pca.n_components_)
plt.bar(features, pca.explained_variance_)
plt.xlabel('PCA feature')
plt.ylabel('variance')
plt.xticks(features)
plt.show()

# Import PCA
from sklearn.decomposition import PCA

# Create a PCA model with 2 components: pca
pca = PCA(n_components=2)

# Fit the PCA instance to the scaled samples
pca.fit(scaled_samples)

# Transform the scaled samples: pca_features
pca_features = pca.transform(scaled_samples)

# Print the shape of pca_features
print(pca_features.shape)

# Import TfidfVectorizer
from sklearn.feature_extraction.text import TfidfVectorizer

# Create a TfidfVectorizer: tfidf
tfidf = TfidfVectorizer()

# Apply fit_transform to document: csr_mat
csr_mat = tfidf.fit_transform(documents)

# Print result of toarray() method
print(csr_mat.toarray())

# Get the words: words
words = tfidf.get_feature_names()

# Print words
print(words)

# Perform the necessary imports
from sklearn.decomposition import TruncatedSVD
from sklearn.cluster import KMeans
from sklearn.pipeline import make_pipeline

# Create a TruncatedSVD instance: svd
svd = TruncatedSVD(n_components=50)

# Create a KMeans instance: kmeans
kmeans = KMeans(n_clusters=6)

# Create a pipeline: pipeline
pipeline = make_pipeline(svd,kmeans)

# Import pandas
import pandas as pd

# Fit the pipeline to articles
pipeline.fit(articles)

# Calculate the cluster labels: labels
labels = pipeline.predict(articles)

# Create a DataFrame aligning labels and titles: df
df = pd.DataFrame({'label': labels, 'article': titles})

# Display df sorted by cluster label
print(df.sort_values(by="label"))


#
# 《孫子算經》(https://zh.wikipedia.org/wiki/孫子算經)
# 有物不知其數，三三數之剩二，五五數之剩三，七七數之剩二。問物幾何？
#
# Chinese remainder theorem(https://en.wikipedia.org/wiki/Chinese_remainder_theorem)
# There are certain things whose number is unknown.
# If we count them by threes, we have two left over;
# by fives, we have three left over;
# and by sevens, two are left over.
# How many things are there?
#
# Here is the equations:
# x % 3 = 2
# x % 5 = 3
# x % 7 = 2

import sympy as sp

import deco
from deco.solver import Problem, Variable, Constraint
from deco.solver import deSolve

x = sp.symbols("x")

variables = [Variable(x, 0, 105)]
constraints = [
    Constraint(sp.Eq(x%3, 2, evaluate=False)),
    Constraint(sp.Eq(x%5, 3, evaluate=False)),
    Constraint(sp.Eq(x%7, 2, evaluate=False)),
    Constraint(sp.Eq(x%1, 0, evaluate=False)),
    Constraint(x>=0),
    Constraint(x<105),
    ]
objective = sp.numbers.Zero()
problem = Problem(variables, constraints, objective)
solution = deSolve(problem, seed=64, verbose=True)

print()
print("The number is {0}.".format(int(solution[0]+0.5)))
print()


import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
#Define plot axes.
fig,ax = plt.subplots(1,1,figsize=(10,8))
#Not declaring this way raises an error for streamplot but not quiver.
x,y = np.meshgrid( np.linspace(0,5,20),np.linspace(0,5,20) )

#Define function: Using lambda seems quite efficient.
# For dx/dt = x(1-x); p 35 Strogatz.
#Note that the x = x[0], y = dx/dt is in terms of x[1]
f = lambda x : [x[0], x[1]*(1- x[1])]
#Apply the function to the axes.
U,V = f([x,y])
#Both ways work/
# U = x
# V = y*(1-y)
#Plot the curve.
ax.streamplot(x,y,U,V, color='r',linewidth=.5)
ax.set_title('Phase and Trajectory plot')
ax.set_xlabel('x')
ax.set_ylabel('xdot')
#Make a new function also to integrate
def odef(vect,t):
    x =vect
    return x*(1-x)

#Calculate a trajectory with a starting point.
number_of_points = 200
t = np.linspace(0,5,number_of_points)
y0 = [.2,1,5]#[(0,2.5),(2,1),(3,1.2)]
N = len(y0)
tt = odeint(odef,y0,t)

#Plot a trajectory
ax.plot(t, tt[:,0],'g', lw=1)
ax.plot(t, tt[:,1],'b',lw=1)
ax.plot(t, tt[:,2],'k',lw=1)
#print(yint)
plt.show()


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

datos = pd.read_csv('USArrests.csv')
columnas = ['Murder', 'Assault', 'UrbanPop','Rape']
datos2 = datos[columnas]
datos2 = (datos2 - datos2.mean())/datos2.std()

cov_matrix = np.cov(datos2.T)

values, vectors = np.linalg.eig(cov_matrix)

vector_A = vectors[:,0]
vector_B = vectors[:,1]

plt.figure(figsize=(12,12))
datos = np.array(datos)

for i in range(len(datos)):
    ciudades = datos[:,0][i]
    v = np.array(datos2.iloc[i])
    x = np.dot(vector_A, v)
    y = np.dot(vector_B, v)
    plt.text(x,y, ciudades, fontsize=10, color='blue')
    plt.scatter(x, -y, s=0.001)

for j in range(len(columnas)):
    plt.arrow(0.0, 0.0, 2.5*vector_A[j], 2.5*vector_B[j], color='red', head_width=0.1)
    plt.text(2.75*vector_A[j], 2.75*vector_B[j], columnas[j], color='red')
plt.ylim(-3,3)
plt.xlabel('Primera Componente Principal')
plt.ylabel('Segunda Componente Principal')
plt.savefig('arrestos.png', bbox_inches='tight')

values2 = values*25
y = [values2[0]]
for i in values2[1:]:
    y.append(y[-1]+i)
x = range(1,5)
plt.figure()
plt.plot(x,y)
plt.scatter(x,y)
plt.grid()
plt.ylim(0,100)
plt.xlabel('Número de autovalores')
plt.ylabel('Porcentaje de varianza explicada')
plt.savefig('varianza_arrestos.png')

datos = pd.read_csv('Cars93.csv')
columnas = ['MPG.city', 'MPG.highway', 'EngineSize', 'Horsepower', 'RPM', 'Rev.per.mile',
          'Fuel.tank.capacity', 'Length', 'Width', 'Turn.circle', 'Weight']
datos2 = datos[columnas]
datos2 = (datos2 - datos2.mean())/datos2.std()

cov_matrix = np.cov(datos2.T)
values, vectors = np.linalg.eig(cov_matrix)

vector_A = vectors[:,0]
vector_B = vectors[:,1]

plt.figure(figsize=(12,12))
datos = np.array(datos)

for i in range(len(datos)):
    model = datos[:,2][i]
    v = np.array(datos2.iloc[i])
    x = np.dot(vector_A, v)
    y = np.dot(vector_B, v)
    plt.text(x,-y, model, fontsize=10, color='blue')
    plt.scatter(x, y, s=0.001)

for j in range(len(columnas)):
    plt.arrow(0.0, 0.0, 2.5*vector_A[j], -2.5*vector_B[j], color='red', head_width=0.1)
    plt.text(2.75*vector_A[j], -2.75*vector_B[j], columnas[j], color='red')
plt.ylim(-3,3)
plt.xlabel('Primera Componente Principal')
plt.ylabel('Segunda Componente Principal')
plt.savefig('cars.png', bbox_inches='tight')

values2 = values*9.09
y = [values2[0]]
for i in values2[1:]:
    y.append(y[-1]+i)
x = range(1,12)
plt.figure()
plt.plot(x,y)
plt.scatter(x,y)
plt.grid()
plt.ylim(0,100)
plt.xlabel('Número de autovalores')
plt.ylabel('Porcentaje de varianza explicada')
plt.savefig('varianza_cars.png')