#Nabin Chapagain
#1001551151

#k_means(<data_file>, <K>, <initialization>)

# Importing all needed libraries
import numpy as np
import math
import sys
import random
import matplotlib.pyplot as plt

fname = sys.argv[1]
k = int(sys.argv[2])
initialization = sys.argv[3]

if(initialization == "round_robin" or initialization == "random"):
    k = k
else:
    print("wrong input for initialization!!! Try again with round_robin or random")
    exit(0)

file_mat_raw = np.loadtxt(fname)
dim = file_mat_raw.ndim
no_row = len(file_mat_raw)
no_col = 1
if(dim != 1):
    no_col =len(file_mat_raw[0])

b = np.random.randint(1,k+1, size = no_row )

if(initialization == 'round_robin'):
    for i in range(no_row):
        if((i+1)%k == 0):
            b[i] = k
        else:
            b[i] = (i+1)%k

file_mat = np.column_stack((file_mat_raw,b))

#now I have read the file and assigned a column to store the value of assigned cluster, I will proceed to compute the means
#It might be better to use recursion for this case

poss_clusters = np.arange(1,k+1)

centers = np.zeros([k, no_col])
dist = np.zeros([k, 1])

counter = 1
while(counter > 0):
    counter = 0
    for i in range(k):
        dummy_var = np.mean(file_mat[:][file_mat[:,-1]==i+1], axis=0)
        centers[i] = dummy_var[0:no_col]

    #now need to calculate euclidean distance for each point in individual rows from each of the centers
    for i in range(no_row):
        for j in range(k):
            dist[j] = np.linalg.norm(file_mat_raw[i] - centers[j])

        supposed_cluster = np.argmin(dist)+1
        if(file_mat[i,-1] != supposed_cluster):
            file_mat[i,-1] = supposed_cluster
            counter += 1

if(no_col == 1):
    for i in range(no_row):
        print('%10.4f --> cluster %d\n'% (file_mat[i,0], file_mat[i,-1]))
if(no_col == 2):
    for i in range(no_row):
        print('(%10.4f, %10.4f) --> cluster %d\n'% (file_mat[i,0], file_mat[i,1], file_mat[i,-1]))

#colors = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf']
if(no_col == 2):
    fig = plt.figure( figsize=(3, 3) \
                    , dpi= 100 \
                    , facecolor='w' \
                    , edgecolor='w' \
                    ) # create figure object

for i in range(k):
    choice = file_mat_raw[:][file_mat[:,-1] == i+1]
    if(no_col == 2):
        plt.scatter(choice[:,0],choice[:,1])

        plt.scatter(centers[:,0],centers[:,1], c= 'k')
if(no_col == 2):
    plt.show()


# -*- coding: utf-8 -*-
"""
Create the Farey FInite Fractal as a sampling pattern for MRI

All figures and code pertaining to the display, saving and generation of fractals,
are covered under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0
International Public License: http://creativecommons.org/licenses/by-nc-sa/4.0/.
For publication and commercial use of this content, please obtain a suitable license
from Shekhar S. Chandra.
"""
from __future__ import print_function    # (at top of module)
import _libpath #add custom libs
import finitetransform.numbertheory as nt #local modules
import finitetransform.mojette as mojette
import finitetransform.radon as radon
import finitetransform.imageio as imageio #local module
import finitetransform.farey as farey #local module
import numpy as np

#parameters
N = 16
M = 2*N
K = 1
twoQuads = True
print("N:", N, "M:", M)
#p = nt.nearestPrime(M)
#print("p:", p)
#pDash = nt.nearestPrime(N)
#print("p':", pDash)
#angles = mojette.angleSet_Finite(pDash, 2)
angles, lengths = mojette.angleSet_Symmetric(N,N,1,True,K) #here
#getProjectionCoordinates
perpAngle = farey.farey(1,0)
angles.append(perpAngle)
print("Number of Angles:", len(angles))
print("angles:", angles)

#powerSpect = np.zeros((p,p))
powerSpect = np.zeros((M,M))

#np.set_printoptions(threshold=np.nan)

#compute lines
print("Computing Finite lines...")
centered = True
lines = []
mValues = []
pValues = []
qValues = []
for angle in angles:
    #m, inv = farey.toFinite(angle, p)
    #u, v = radon.getSliceCoordinates2(m, powerSpect, centered, p)
    m, p, q, inv = farey.toFinite(angle, M)
    u, v = radon.getSliceCoordinates2(m, powerSpect, centered, M)
    lines.append((u,v))
    mValues.append(m)
    pValues.append(p)
    qValues.append(q)

    #second quadrant
    if twoQuads:
        #if m != 0 and m != p: #dont repeat these
        if m != 0 and m != M: #dont repeat these
            #m = p-m
            #u, v = radon.getSliceCoordinates2(m, powerSpect, centered, p)
            m = M-m
            z = M-2*z
            u, v = radon.getSliceCoordinates2(m, powerSpect, centered, M)
            lines.append((u,v))
            w, y = radon.getSliceCoordinates2(z, powerSpect, centered, 1024)
            lines.append((w,y))
            mValues.append(m)

mu = len(lines)
print("Number of lines:", len(lines))
#print("Proportion of p:", len(lines)/float(p))
#print("Proportion of 2D space:", 2.0-len(lines)/float(p))
print("Proportion of M:", len(lines)/float(M))
print("Proportion of 2D space:", 2.0-len(lines)/float(M))
print(mValues)
print(pValues)
print(qValues)

#plot slices responsible for reconstruction
import matplotlib.pyplot as plt
from matplotlib.pyplot import cm

fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(16, 8))

plt.gray()
plt.tight_layout()

maxLines = len(lines)
#maxLines = 12
ax[0].imshow(powerSpect)
ax[1].imshow(powerSpect)
#color=iter(cm.rainbow(np.linspace(0,1,len(lines))))
color=iter(cm.jet(np.linspace(0,1,maxLines+1)))
fareyImage = np.zeros_like(powerSpect)
for i, line in enumerate(lines):
    u, v = line
    c=next(color)
    ax[0].plot(u, v, '.', c=c)
    ax[1].plot(u, v, '.r',markersize=1)
    fareyImage[u,v] = 255
    if i == maxLines:
        break
#ax[0].set_title('Sampling (colour per line) for prime size:'+str(p))
#ax[1].set_title('Sampling (same colour per line) for prime size:'+str(p))
ax[0].set_title('Sampling (colour per line) for dyadic size:'+str(M))
ax[1].set_title('Sampling (same colour per line) for dyadic size:'+str(M))
#ax[0].set_xlim([0,M])
#ax[0].set_ylim([0,M])
#ax[1].set_xlim([0,M])
#ax[1].set_ylim([0,M])

#imageio.imsave("farey_image_"+str(p)+"_"+str(K)+".png", fareyImage)
imageio.imsave("farey_image_"+str(M)+"_"+str(K)+".png", fareyImage)

plt.show()

fig,
plt.plot(pValues, qValues, 'ro')
plt.show()


import numpy as np

def accuracy_score(y_true, y_pred):
    """
    Classification performance metric that computes the accuracy of y_true
    and y_pred.
    :param numpy.array y_true: array-like of shape (n_samples,) Ground truth correct labels.
    :param numpy.array y_pred: array-like of shape (n_samples,) Estimated target values.
    :returns: C (float) Accuracy score.
    """
    correct = 0
    for true, pred in zip(y_true, y_pred):
        if true == pred:
            correct += 1
    accuracy = correct / len(y_true)
    return accuracy

def mse(y_true, y_pred, squared=True):
    """
    Mean squared error regression loss function.
    Parameters
    :param numpy.array y_true: array-like of shape (n_samples,)
        Ground truth (correct) target values.
    :param numpy.array y_pred: array-like of shape (n_samples,)
        Estimated target values.
    :param bool squared: If True returns MSE, if False returns RMSE. Default=True
    :returns: loss (float) A non-negative floating point value (the best value is 0.0).
    """
    y_true = np.array(y_true)
    y_pred = np.array(y_pred)
    errors = np.average((y_true - y_pred) ** 2, axis=0)
    if not squared:
        errors = np.sqrt(errors)
    return np.average(errors)

def r2_score(y_true, y_pred):
    """
    R^2 regression score function.
        R^2 = 1 - SS_res / SS_tot
    where SS_res is the residual sum of squares and SS_tot is the total
    sum of squares.
    :param numpy.array y_true : array-like of shape (n_samples,) Ground truth (correct) target values.
    :param numpy.array y_pred : array-like of shape (n_samples,) Estimated target values.
    :returns: score (float) R^2 score.
    """
    # Residual sum of squares.
    numerator = ((y_true - y_pred) ** 2).sum(axis=0)
    # Total sum of squares.
    denominator = ((y_true - np.average(y_true, axis=0)) ** 2).sum(axis=0)
    # R^2.
    score = 1 - numerator / denominator
    return score

def mse_prime(y_true, y_pred):
    return 2*(y_pred-y_true)/y_true.size

def cross_entropy(y_true, y_pred):
    return -(y_true * np.log(y_pred)).sum()

def cross_entropy_prime(y_true, y_pred):
    return y_pred - y_true


'''

'''
import numpy as np

def check_orientation(origin, points):
    '''
    *origin* is a point inside a (convex) shape
    Meaning of orientation:
    - look from origin to the triangle plane
    - return True if the triangle points are oriented counter-clockwise, returns True (orientation is suitable for FBEM)
    :origin: a reference point to check orinetation
    :points: coordinates of a triangle: array of 3 points, each is a 3D point
    '''
    origin = np.array(origin)
    [p1, p2, p3] = [np.array(point) for point in points]
    v12 = p1 - p2
    v32 = p3 - p2
    normal = np.cross(v12, v32)
    orientation = p1 + p2 + p3 - 3 * origin
    sign = np.dot(orientation, normal)
    if sign > 0:
        return True
    elif sign < 0:
        return False
    else:
        raise ValueError("Origin is in the triagnle plane")

def orientate(origin, points, triangle):
    """
    Check orientation, fix it if it is wrong.
    """
    if not check_orientation(origin, points):
        triangle = (triangle[0], triangle[2], triangle[1])
    return triangle

def orientateTriangulation(origin, points, triangulation):
    '''
    Fix orientation in triangles in a triangulation array (array of triangle indices).
    '''
    triangulationH = []
    for tri in triangulation:
        triH = orientate(origin, [points[tri[0]], points[tri[1]], points[tri[2]]], tri)
        triangulationH.append(triH)
    return triangulationH

if __name__ == '__main__':
    # Tests

    origin = np.array([0,0,1])
    points = np.array([[1,0,0], [0,1,0], [0,0,0]])
    print(check_orientation(origin, points)) # OK: True


import math
from math import ceil
import numpy as np

def cartesian_product(*arrays) -> np.ndarray:
    """
    Computes the cartesian product of given arrays fast.

    :param arrays: arrays to compute the cartesian product of.

    :return: the cartesian product of the given arrays.
    :rtype: numpy.ndarray
    """
    la = len(arrays)
    dtype = np.result_type(*arrays)
    arr = np.empty([len(a) for a in arrays] + [la], dtype=dtype)
    for i, a in enumerate(np.ix_(*arrays)):
        arr[..., i] = a
    return arr.reshape(-1, la)

def multiply_point(point: tuple[float, ...], coef: float) -> tuple[float, ...]:
    """
    Multiples each value in a given tuple by a coefficient.

    :param point: the point to multiply.
    :type point: tuple[float, ...]

    :param coef: the coefficient to multiply the points by.
    :type coef: float

    :return: the tuple, where each element is multiplied by the coefficient.
    :rtype: tuple[float]
    """

    return tuple(p * coef for p in point)

def add_points(points: list[tuple[float, ...]], coefs=None) -> tuple[float, ...]:
    """
    Adds values in tuples (for adding coordinates).

    :param points: list of tuples to add together.
    :type points: list[tuple[float, ...]]

    :param coefs: coefficients before the tuples (all 1's by default).
    :type coefs: list[float]

    :raises:
        AssertionError: if the number of tuples and coefficients are not equal.
    :raises:
        AssertionError: if the number of values is not equal in all tuples.

    :return: the sum of tuples.
    :rtype: tuple[float, ...]
    """

    if coefs != None:
        assert len(points) == len(coefs), "Number of points and number of coefficients must be equal."
    else:
        coefs = [1] * len(points)

    tuple_length = len(points[0])
    assert all(len(p) == tuple_length for p in points), "Number of values should be equal for all points."

    points_t = [
        tuple([points[p][i] * coefs[p] for p in range(len(points))]) for i in range(tuple_length)
    ]
    return tuple(map(sum, points_t))

def point_ceil(p: tuple[float, ...]) -> tuple[int, ...]:
    """
    Computes the ceiling of a tuple.

    :param p: a tuple.
    :type p: tuple[float, ...]

    :return: tuple of ceilings of all values in the given tuple.
    :rtype: tuple[int, ...]
    """

    return tuple(ceil(i) for i in p)

def euclidian_dist(p1: tuple[float, float], p2=(0, 0)) -> float:
    """
    Calculates the Euclidian distance between two points.

    :param p1: coordinates of point 1.
    :type p1: tuple[float, float]

    :param p2: coordinates of point 2.
    :type p2: tuple[float, float]

    :return: the Euclidean distance between two 2D points.
    :rtype: float
    """

    return math.sqrt(
        pow(p1[0] - p2[0], 2) + pow(p1[1] - p2[1], 2)
    )


# -*- coding: utf-8 -*-
"""
Title: Iris Dataset exploration using Linear Regressio
"""
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import math
import scipy
import scipy.stats

from matplotlib import style
import matplotlib.patches as mpatches
from sklearn import preprocessing, cross_validation, svm
from sklearn.preprocessing import StandardScaler
from sklearn.utils import shuffle
from sklearn.cluster import KMeans

style.use('ggplot')

FILE_NAME = "res/iris_missing.csv"

def covarience_matrix(X):
    #standardizing data
    X_std = StandardScaler().fit_transform(X)

    #sample means of feature columns' of dataset
    mean_vec = np.mean(X_std, axis=0)
    #covariance matrix
    cov_mat = (X_std - mean_vec).T.dot((X_std - mean_vec)) / (X_std.shape[0]-1)
    #if right handside is ( Xstd - mean(Xstd) )^T . ( Xstd - mean(Xstd) )
    #simplyfying X^T.X / ( n - 1 )
    cov_mat = np.cov(X_std.T)
    return cov_mat

def max_min_bi_corel(X):
    a = covarience_matrix(X)
    a[a>=1] = 0
    maxcor = np.argwhere(a.max() == a)[0] # reverse 1

    b = covarience_matrix(X)
    mincor = np.argwhere(b.min() == b)[0] # reverse 1

    return maxcor,mincor

def main():
    ## loading the data
    data = pd.read_csv(FILE_NAME, header=None, index_col=0, names = ["sepal_width", "sepal_length", "petal_width", "petal_length", "Class"] )
    #data.reset_index(inplace=True)

    # Create an array of three colours, one for each species.
    colors = np.array(['red', 'green', 'blue','yellow','violet'])
    labelss = np.array(['Setosa', 'Versicolor', 'Virginica','W','Y'])

    #0,1,2 labels for selecting color by index
    data.loc[ data['Class']=='Iris-setosa', 'Class'] = 0
    data.loc[ data['Class']=='Iris-versicolor', 'Class'] = 1
    data.loc[ data['Class']=='Iris-virginica', 'Class'] = 2

    #def handle_missing_values()
    #data.fillna(0, inplace=True)
    #data = data.apply(lambda x: x.fillna(x.mean()),axis=0)
    data = data.apply(lambda x: x.fillna(x.median()),axis=0)

    ## Rounding label column to nearest integer
    data['Class'].round(0)
    ## Eliminating 000 after decimal from modified label column
    data.Class = data.Class.astype(int)

    #data = shuffle(data)

    x = data.iloc[:,:-1]
    y = data['Class']

    print("Covariance Matrix =")
    print(covarience_matrix(x))

    maxcor,mincor = max_min_bi_corel(x)
    print("Most Colinearity %s"%maxcor)
    print("Least Colinearity %s"%mincor)

    #12x7 unit plot
    plt.figure('Unsupervised Clustering - KMeans',figsize=(12,7))

    #nrows=1, ncols=2, plot_number=1
    plt.subplot(2, 2, 1)
    plt.scatter(x[data.columns[mincor[0]]], x[data.columns[mincor[1]]], c=colors[y], s=40)
    plt.title('%s vs %s[Lowest Colinear]'%(data.columns[mincor[0]],data.columns[mincor[1]]))

    #nrows=1, ncols=2, plot_number=2
    plt.subplot(2, 2, 2)
    plt.scatter(x[data.columns[maxcor[0]]], x[data.columns[maxcor[1]]], c=colors[y], s=40)
    plt.title('%s vs %s[Highest Colinear]'%(data.columns[maxcor[0]],data.columns[maxcor[1]]))

    clu = KMeans(n_clusters=3)
    clu.fit(x)

    print("For actual labels,where")
    count=0
    for c in labelss:
        print("Label=%s -> Species = %s"%(count,c))
        count+=1

    print("Actual labels %s" % y.tolist())

    # The fudge to reorder the cluster ids.
    #predictedY = np.choose(clu.labels_, [1, 0, 2]).astype(np.int64)
    predictedY = clu.labels_
    print("Clustered groups %s" % predictedY)

    # Plot the classifications that we saw earlier between Petal Length and Petal Width
    plt.subplot(2, 2, 3)
    plt.scatter(x['petal_length'], x['petal_width'], label = labelss[y], c=colors[y], s=40) #colormap
    plt.title('Actual Classes')

    color_patch = []
    for c in range(len(colors)):
        color_patch.append(mpatches.Patch(color=colors[c], label=labelss[c]))
        plt.legend(handles=color_patch)

    # Plot the classifications according to the model
    plt.subplot(2, 2, 4)
    plt.scatter(x['petal_length'], x['petal_width'], c=colors[predictedY], s=40) #colormap
    plt.title("Model's predicted classes[Clusters without label]")

    plt.tight_layout()
    plt.show()

    '''
    accuracy = clf.score(X_test, y_test)
    print("Test Score %s" %accuracy)

    predict = clf.predict(XP)
    print(yP,np.round( np.array(predict)))
    prediction_score = ( sum( yP==np.round( np.array(predict) ) ) / len(yP) ) * 100
    print("Prediction score %s" %prediction_score)
    '''

if __name__ == '__main__':
    main()


import numpy as np
import math

a = np.arange(12).reshape(3,4)
print a

# sum over the first axis (rows), so this gives the sum in each column
print a.sum(axis=0)

# sum over all elements
print a.sum()

# find the minimum and maximum element
print a.min(), a.max()

print " "

# universal functions
b = a*math.pi/12.0
print b

c = np.cos(b)
print c

print " "

# add two arrays
d = b + c
print d


import numpy as np
import scipy.misc
import matplotlib.pyplot as plt

plt.rc("font", size=16, family="serif", serif="Computer Sans")
plt.rc("text", usetex=True)

N = 5
x = np.arange(0, N + 1)

theta = np.array([0.3, 0.5, 0.8])
colors = ['b', 'r', 'g']

i = 0
for th in theta:
	p = scipy.misc.comb(N, x)*th**x*(1. - th)**(N - x)
	p /= p.sum()
	plt.plot(x, p, 'o-', color=colors[i], markersize=10,
		label='$\\theta = {val}$'.format(val=th))
	i += 1

plt.xlabel('Possible Data $x$')
plt.ylabel('Probability')
plt.ylim([-0.1, 1.])
plt.xlim([-0.5, 5.5])
plt.legend(numpoints=1, loc='upper center')
plt.savefig('binomial.pdf', bbox_inches='tight')
#plt.show()

x = 2
theta = np.linspace(0., 1., 1001)
p = theta**x*(1. - theta)**(N - x)
p /= np.trapz(p, x=theta)
plt.plot(theta, np.ones(p.shape), 'g--', linewidth=2, label='Prior $p(\\theta)$')
plt.plot(theta, p, 'b', linewidth=2, label='Posterior $p(\\theta|x)$')
plt.xlabel('Possible Values $\\theta$')
plt.ylabel('Probability Density')
plt.legend()
plt.savefig('bus_inference.pdf', bbox_inches='tight')
#plt.show()

prior1 = np.ones(theta.shape)
prior2 = (theta + 0.001)**(-0.5)*(1. - theta + 0.001)**(-0.5); prior2 /= np.trapz(prior2, x=theta)
prior3 = theta**100*(1. - theta)**100; prior3 /= np.trapz(prior3, x=theta)
post1 = prior1*theta**x*(1. - theta)**(N - x); post1 /= np.trapz(post1, x=theta)
post2 = prior2*theta**x*(1. - theta)**(N - x); post2 /= np.trapz(post2, x=theta)
post3 = prior3*theta**x*(1. - theta)**(N - x); post3 /= np.trapz(post3, x=theta)
plt.plot(theta, prior1, 'b--', linewidth=2, label='Prior 1')
plt.plot(theta, prior2, 'r--', linewidth=2, label='Prior 2')
plt.plot(theta, prior3, 'g--', linewidth=2, label='Prior 3')
plt.plot(theta, post1, 'b', linewidth=2)
plt.plot(theta, post2, 'r', linewidth=2)
plt.plot(theta, post3, 'g', linewidth=2)
plt.legend()
plt.xlabel('Possible Values $\\theta$')
plt.title('Three Priors, Three Posteriors')
plt.ylabel('Probability Density')
plt.savefig('three_priors.pdf', bbox_inches='tight')
#plt.show()

N = 1000
x = 500
prior1 = np.ones(theta.shape)
prior2 = (theta + 0.001)**(-0.5)*(1. - theta + 0.001)**(-0.5); prior2 /= np.trapz(prior2, x=theta)
prior3 = theta**100*(1. - theta)**100; prior3 /= np.trapz(prior3, x=theta)
post1 = prior1*theta**x*(1. - theta)**(N - x); post1 /= np.trapz(post1, x=theta)
post2 = prior2*theta**x*(1. - theta)**(N - x); post2 /= np.trapz(post2, x=theta)
post3 = prior3*theta**x*(1. - theta)**(N - x); post3 /= np.trapz(post3, x=theta)
plt.plot(theta, prior1, 'b--', linewidth=2, label='Prior 1')
plt.plot(theta, prior2, 'r--', linewidth=2, label='Prior 2')
plt.plot(theta, prior3, 'g--', linewidth=2, label='Prior 3')
plt.plot(theta, post1, 'b', linewidth=2, alpha=0.5)
plt.plot(theta, post2, 'r', linewidth=2, alpha=0.5)
plt.plot(theta, post3, 'g', linewidth=2, alpha=0.5)
plt.xlabel('Possible Values $\\theta$')
plt.ylabel('Probability Density')
plt.title('Lots of Data')
plt.xlim([0.4, 0.6])
plt.legend()
plt.savefig('lots_of_data.pdf', bbox_inches='tight')
#plt.show()


#!/usr/bin/python
# encoding: utf-8

"""
@author: Ian
@contact:yongguiluo@hotmail.com
@file: permutation_combination.py
@time: 2019/3/23 13:27
排列组合
"""
from scipy.special import comb, perm
from itertools import combinations, permutations

def permutation(n, m):
    """
    n中选择m个数进行排列
    先总结出递推公式
    :param n:
    :param m:
    :return:
    """
    return 1 if m == 0 else permutation(n, m - 1) * (n - m + 1)

if __name__ == "__main__":
    print(permutation(5, 4))#120
    print(perm(5, 4))
    print(comb(5, 4))
    #调用 itertools 获取排列组合的全部情况数
    print(list(permutations([1, 2, 3], 2)))
    print(list(combinations([1, 2, 3], 2)))


import math
import sympy as sym

print("BOUNDING PHASE METHOD")
x = sym.Symbol('x')

### Function ###

f = x**2 - 5*x + x**2

################

def substitute(k):
    return (f.subs(x,k))

while(1):
    delta = float(input("Enter the delta value : "))
    x_o = 0.6 #initial guess
    x_minus_delta = x_o - delta
    x_plus_delta = x_o + delta

    f_minus_delta = substitute(x_minus_delta)
    f_plus_delta = substitute(x_plus_delta)
    f_o = substitute(x_o)
    print("x_minus_delta = {}  x = {}  x_plus_delta = {}".format(x_minus_delta,x_o,x_plus_delta))
    print("f(x-$) = {}  f(x) = {}  f(x+$) = {}".format(f_minus_delta,f_o,f_plus_delta))

    if(f_minus_delta>=f_o and f_o>=f_plus_delta):
        delta = delta
        break
    elif(f_minus_delta<=f_o and f_o<=f_plus_delta):
        delta = -delta
        break
    else:
        continue

a = []
a.append(x_o)
k = 0
f_o_plus_1 = f_o - 1
while(f_o_plus_1 < f_o):
    x_o_plus_1 = x_o + (2**k)*delta
    a.append(x_o_plus_1)
    k = k + 1
    f_o_plus_1 = substitute(x_o_plus_1)
    f_o = substitute(x_o)
    print("step :", k)
    print("x_o = {} , x_o_plus_1 = {}".format(x_o,x_o_plus_1))
    print("f_o = {}  f_o_plus_1 = {}".format(f_o,f_o_plus_1))
    x_o = x_o_plus_1

print("( {} , {}  )".format(a[-3],x_o_plus_1))


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Fri Oct  5 17:33:27 2018

@author: shivam
"""

"""
Numpy contd
Datatypes
"""

import numpy as np

x = np.array([1, 2])   # Let numpy choose the datatype
print(x.dtype)         # Prints "int64"

x = np.array([1.0, 2.0])   # Let numpy choose the datatype
print(x.dtype)             # Prints "float64"

x = np.array([1, 2], dtype=np.int64)   # Force a particular datatype
print(x.dtype, x.shape)       # Prints "int64"

"""

Array Math
    Element wise operations.
"""
x = np.array([[1,2],[3,4]], dtype=np.float64)
y = np.array([[5,6],[7,8]], dtype=np.float64)

# Elementwise sum; both produce the array
# [[ 6.0  8.0]
#  [10.0 12.0]]
print(x + y)
print(np.add(x, y))

# Elementwise difference; both produce the array
# [[-4.0 -4.0]
#  [-4.0 -4.0]]
print(x - y)
print(np.subtract(x, y))

# Elementwise product; both produce the array
# [[ 5.0 12.0]
#  [21.0 32.0]]
print(x * y)
print(np.multiply(x, y))

# Elementwise division; both produce the array
# [[ 0.2         0.33333333]
#  [ 0.42857143  0.5       ]]
print(x / y)
print(np.divide(x, y))

# Elementwise square root; produces the array
# [[ 1.          1.41421356]
#  [ 1.73205081  2.        ]]
print(np.sqrt(x))

"""
dot is available both as a function in the numpy module and as an instance method of array objects
"""

x = np.array([[1,2],[3,4]])
y = np.array([[5,6],[7,8]])

v = np.array([9,10])
w = np.array([11, 12])

# Inner product of vectors; both produce 219
print(v.dot(w))
print(np.dot(v, w))

# Matrix / vector product; both produce the rank 1 array [29 67]
print(x.dot(v))
print(np.dot(x, v))

# Matrix / matrix product; both produce the rank 2 array
# [[19 22]
#  [43 50]]
print(x.dot(y))
print(np.dot(x, y))

"""
Numpy provides many useful functions for performing computations on arrays; one of the most useful is sum
"""
x = np.array([[1,2],[3,4]])

print(np.sum(x))  # Compute sum of all elements; prints "10"
print(np.sum(x, axis=0))  # Compute sum of each column; prints "[4 6]"
print(np.sum(x, axis=1))  # Compute sum of each row; prints "[3 7]"

"""
Transpose of the matrix
"""
x = np.array([[1,2], [3,4]])
print(x)    # Prints "[[1 2]
            #          [3 4]]"
print(x.T)  # Prints "[[1 3]
            #          [2 4]]"

# Note that taking the transpose of a rank 1 array does nothing:
v = np.array([1,2,3])
print(v)    # Prints "[1 2 3]"
print(v.T)  # Prints "[1 2 3]"


# coding: utf-8
# Released under the MIT licence https://opensource.org/licenses/mit-license.php
# Copyright © 2021 Kazuki Akimoto. All right reserved.

import numpy as np

# もとの行列を表示
def desplay_matrix(mat):
	print('行列は')
	print(mat)
	print('________________')

# 転置行列
def transpose_matrix(mat):
	print('転置行列は')
	print(mat.T)
	print('________________')

# 逆行列
def inverse_matrix(mat):
	print('逆行列は')
	try:
		print(np.linalg.inv(mat))
	except np.linalg.LinAlgError:
		print('エラー：この行列には逆行列が存在しません')
	print('________________')

#行列式
def determinant(mat):
	print('行列式は')
	print(np.linalg.det(mat))
	print('________________')

#固有値、固有ベクトル
def eigenvalue(mat):
	print('固有値・固有ベクトルは')
	w, v = np.linalg.eig(mat)
	print('固有値 :{}, 固有ベクトル:{}'.format(w[0],v[0]))
	print('固有値 :{}, 固有ベクトル:{}'.format(w[1],v[1]))
	print('________________')


import numpy as np

def build_sine_table(f_sine, samp_freq, data_type):
    """
    :param f_sine: Modulate frequency for voice effect in Hz.
    :param samp_freq: Sampling frequency in Hz
    :param data_type: Data type of sinusoid table. Must be signed integer type.
    :return:
    """

    if data_type is np.int16 or np.int32:
        MAX_SINE = np.iinfo(data_type).max
    else:
        raise ValueError("Data type must be signed integer.")

    # periods
    samp_per = 1./samp_freq
    sine_per = 1./f_sine

    # compute time instances
    t_vals = np.arange(0, sine_per, samp_per)
    LOOKUP_SIZE = len(t_vals)
    n_vals = np.arange(LOOKUP_SIZE)

    # compute the sine table
    w_mod = 2*np.pi*f_sine/samp_freq
    SINE_TABLE = np.sin(w_mod*n_vals) * MAX_SINE

    return SINE_TABLE, MAX_SINE, LOOKUP_SIZE


import jax.numpy as jnp
from jax import custom_jvp,jit
from jax.scipy.stats import norm,t
from jax.scipy.special import ndtri

### Functions for Clayton copula ###
#Calculate bivariate normal copula log H_uv and log c_uv
@jit
def clayton_logdistribution_logdensity(u,v,a):
    #clip to prevent 0s and 1s in CDF
    eps = 1e-6
    u = jnp.clip(u,eps,1-eps)
    v = jnp.clip(v,eps,1-eps)

    #initialize useful terms
    u_ = 1-u
    v_ = 1-v
    k = (a+1)/a
    denom = u_**(-1/a) + v_**(-1/a)-1

    #compute log cop density and conditional cdf
    logcop_dens = jnp.log(k) - k*(jnp.log(u_) + jnp.log(v_)) -(a+2)*jnp.log(denom)
    log1cop_dist = jnp.clip(-k*jnp.log(v_) - (a+1)*jnp.log(denom),jnp.log(eps),jnp.log(1-eps))
    logcop_dist = jnp.log1p(-jnp.exp(log1cop_dist))

    return logcop_dist,logcop_dens
### ###

### Functions for Gaussian Copula ###
@custom_jvp #forward diff (define jvp for faster derivatives)
def ndtri_(u):
    return ndtri(u)
@ndtri_.defjvp
def f_jvp(primals, tangents):
    u, = primals
    u_dot, = tangents
    primal_out = ndtri_(u)
    tangent_out = (1/norm.pdf(primal_out))*u_dot
    return primal_out, tangent_out
ndtri_ = jit(ndtri_)

@custom_jvp #forward diff (define jvp for faster derivatives)
def norm_logcdf(z):
    return norm.logcdf(z)
@norm_logcdf.defjvp
def f_jvp(primals, tangents):
    z, = primals
    z_dot, = tangents
    primal_out = norm_logcdf(z)
    tangent_out = jnp.exp(norm.logpdf(z)-primal_out)*z_dot
    return primal_out, tangent_out
norm_logcdf = jit(norm_logcdf)

@jit #Calculate normal copula cdf and logpdf for f32
def norm_copula_logdistribution_logdensity(u,v,rho):
    #clip to prevent 0s and 1s in CDF, needed for numerical stability in high d.
    eps = 1e-6
    u = jnp.clip(u,eps,1-eps)
    v = jnp.clip(v,eps,1-eps)

    #for reverse mode
    pu = ndtri_(u)
    pv = ndtri_(v)
    z = (pu - rho*pv)/jnp.sqrt(1- rho**2)

    logcop_dist = norm_logcdf(z)
    logcop_dist = jnp.clip(logcop_dist,jnp.log(eps),jnp.log(1-eps))
    logcop_dens = -0.5*jnp.log(1-rho**2) + (0.5/(1-rho**2))*(-(rho**2)*(pu**2 + pv**2)+ 2*rho*pu*pv)

    return logcop_dist,logcop_dens


#!/usr/bin/python

import numpy as np

# Construct an array by executing a function over each coordinate.

def f(x, y):
    return 2*x + y + 1

a = np.fromfunction(f, (5, 4), dtype=int)
print(a)

# anonymous functoin
b = np.fromfunction(lambda x, y: 2*x + y, (2, 2))
print(b)


#!/usr/bin/env python
"""
Written by: CAPT Stu Blair
Date: 12 Oct
Purpose: simple Fourier-Bessel series expansion to a function

This alternative implementation uses the more general jv function

"""
import numpy as np
import matplotlib.pyplot as plt
import scipy.integrate as integrate
from scipy.special import jn_zeros
from scipy.special import jv

def f_exp(x):
    return x;

def FB_exp(x,cn,ev,N):
    ret_val = 0.;
    for i in range(N):
        ret_val += cn[i]*jv(1,x*ev[i]);
    return ret_val;

# describe discrete domain
Nx = 1000;
a = 0.; b = 3.;
X = np.linspace(a,b,Nx);

# get eigenvalues
N = 35; # number of ev's.

# get N roots of J_1
k = jn_zeros(1,N);
# compute eigenvalues
ev = k/b;
# allocate an array for expansion coefficients
cn = np.zeros_like(ev);
for n in range(N):
    # compute all of the expansion coefficients
    num, err = integrate.quad(lambda x: f_exp(x)*jv(1,ev[n]*x)*x,a,b);
    denom, err = integrate.quad(lambda x: jv(1,ev[n]*x)*jv(1,ev[n]*x)*x,a,b);
    cn[n] = num/denom;

# make a convenient function capturing the FB expansion
FB = lambda x: FB_exp(x,cn,ev,N);

plt.plot(X,f_exp(X),'-b',linewidth=2.0,label='f(x)')
plt.plot(X,FB(X),'-.r',linewidth=2.0,label='FB(x)')
plt.grid(True);
plt.xlabel('X',fontsize=14,fontweight='bold');
plt.title('Fourier-Bessel Expansion',fontsize=16,fontweight='bold')
plt.legend()


#! /usr/bin/env python3
"""Functions to optimize binning for histograms"""

import numpy as np
from math import ceil

def interquartile_range(data):
    """Calculate the interquartile range of a dataset"""
    q3, q1 = np.percentile(data, [75, 25])
    iqr = q3 -q1
    return iqr

def freedman_diaconis(data):
    """Calculate the bin width for a histogram."""
    n = len(data)
    iqr = interquartile_range(data)
    width = 2 * iqr / n**(1/3)
    return width

def bin_number(data):
    """Calculate the number of bins for a histogram"""
    width = freedman_diaconis(data)
    number = (np.max(data) - np.min(data)) / width
    return ceil(number)


import numpy as np

"""
Conversion between kappa and angular radius.

Based on Equation 11 in Soiaporn et al. 2013.
"""

def get_kappa(theta_p, p=0.68):
    """
    Calculate kappa corresponding to an angular radius theta_p.

    :param theta_p: Angular radius containing probability p [deg]
    :param p: Probability contained within radius theta_p
    :return kappa: Shape parameter of the vMF distribution
    """

    theta_p = np.deg2rad(theta_p)

    return -(2 / theta_p ** 2) * np.log(1 - p)

def get_theta_p(kappa, p=0.68):
    """
    Calculate theta_p corresponding to a vMF distribution
    of width kappa and containing probability p.

    :param kappa: Shape parameter of the vMF distribution
    :param p: Probability contained in radius theta_p
    :return theta_p: Angular radius containing probability p [deg]
    """

    theta_p = np.sqrt((-2 / kappa) * np.log(1 - p))

    return np.rad2deg(theta_p)


import lagmat
import numpy as np
import sklearn.base

def val_to_cont(val: np.array) -> np.array:
    """Convert values (e.g. prices) to continous returns, log
    differences, exponential growth rates

    Parameters:
    -----------
    x : ndarray (2D)
        Time series with the oldest observation in the first row
        and the latest observation in the last row.
        Values need to be ratio-scale, i.e. x>0

    Returns:
    --------
    ret : ndarray (2D)
        continous returns, log differences, exponential growth rates.
        The first row will be nan, i.e. r[0,;]=np.nan

    Alternative:
    ------------
        def val_to_cont(val):
            y = np.empty(shape=x.shape)
            y[0, :] = np.nan
            y[1:, :] = np.log(x[1:, :] / x[:-1, :])
            return y
    """
    return np.log(val / lagmat.lagmat(val, lags=[1]))

def cont_to_val(ret: np.array, initial: float = 1.0) -> np.array:
    """Convert growth rates, log differences, continous returns
    into values or prices

    Returns:
    --------
    ret : ndarray (2D)
        continous returns, log differences, exponential growth rates.

    initial: int or list/tupel/array
        Start values to compound the growth rates from

    Returns:
    --------
    x : ndarray (2D)
        Time series with the oldest observation in the first row
        and the latest observation in the last row.
    """
    z = np.exp(ret)
    z[0, :] = initial
    return np.cumprod(z, axis=0)

class Cont(sklearn.base.BaseEstimator, sklearn.base.TransformerMixin):
    def __init__(self, initial: float = None, trimnan: bool = True):
        self.initial = initial
        self.trimnan = trimnan

    def fit(self, X: np.array, y=None):
        # store the starting values
        if self.initial is None:
            if len(X.shape) == 1:
                self.initial = X[0]
            else:
                self.initial = X[0, :]
        # done
        return self

    def transform(self, X: np.array, copy=None) -> np.array:
        if self.trimnan:
            return lagmat.chopnan(val_to_cont(X), nchop=1)
        else:
            return val_to_cont(X)

    def inverse_transform(self, Z: np.array, initial: float = None,
                          copy=None) -> np.array:
        # Use the requested initial value, or use the fitted initial values
        if initial is None:
            initial = self.initial
        # Multiply initial values repeatly with growth rates
        if self.trimnan:
            return cont_to_val(
                np.r_[np.zeros(shape=(1, Z.shape[1])), Z],
                initial=initial)
        else:
            return cont_to_val(Z, initial=initial)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sat Feb  9 17:53:39 2019

@author: alankar
"""

import numpy as np
import matplotlib.pyplot as plt
from scipy.special.orthogonal import p_roots #Legendre Polynomial roots
from scipy import constants

def gauss_quad(func,a,b,n,*args):#Legendre
    [x,w] = p_roots(n+1)
    I_G = 0.5*(b-a)*np.sum(w*func(0.5*(b-a)*x+0.5*(b+a),*args))
    return I_G

V = 1000*1e-6 #m^3
rho = 6.022e28 #m^-3
thetaD = 428  #K

def CV(T):
    N = 50
    f = lambda x:(x**4*np.exp(x))/(np.exp(x)-1)**2
    return 9*V*rho*constants.k*(T/thetaD)**3*gauss_quad(f,0,thetaD/T,N)

Temperature = np.linspace(5,500,1000)
Heat_cap = np.array([CV(T) for T in Temperature])
plt.figure(figsize=(13,10))
plt.plot(Temperature,Heat_cap)
plt.grid()
plt.title(r'Debye Heat capacity $C_V(T)$ in a solid',size=25,y=1.02)
plt.xlabel(r'$T$',size=22)
plt.ylabel(r'$C_V(T)$',size=22)
plt.tick_params(axis='both', which='major', labelsize=15)
plt.tick_params(axis='both', which='minor', labelsize=12)
plt.savefig('9.png')
plt.show()


#!/usr/bin/env python3

from numpy import *
from math import sqrt

from rigid_transform_3D import rigid_transform_3D

# Test with random data

# Random rotation and translation
R = mat(random.rand(3,3))
t = mat(random.rand(3,1))

# make R a proper rotation matrix, force orthonormal
U, S, Vt = linalg.svd(R)
R = U*Vt

# remove reflection
if linalg.det(R) < 0:
   Vt[2,:] *= -1
   R = U*Vt

# number of points
n = 10

# A = mat(random.rand(3, n));
A = array(random.rand(3, n));
B = R*A + tile(t, (1, n))

# Recover R and t
ret_R, ret_t = rigid_transform_3D(A, B)

# Compare the recovered R and t with the original
B2 = (ret_R*A) + tile(ret_t, (1, n))

# Find the root mean squared error
err = B2 - B
err = multiply(err, err)
err = sum(err)
rmse = sqrt(err/n);

print("Points A")
print(A)
print("")

print("Points B")
print(B)
print("")

print("Ground truth rotation")
print(R)

print("Recovered rotation")
print(ret_R)
print("")

print("Ground truth translation")
print(t)

print("Recovered translation")
print(ret_t)
print("")

print("RMSE:", rmse)

if rmse < 1e-5:
    print("Everything looks good!\n");
else:
    print("Hmm something doesn't look right ...\n");


'''
ANKIT KHANDELWAL
15863

Exercise 12a
'''

import math

import matplotlib.pyplot as plt
import numpy as np

theta = np.linspace(0, 2 * np.pi, 5000)
x = []
y = []
for i in theta:
    x.append(2 * math.cos(i) + math.cos(2 * i))
    y.append(2 * math.sin(i) - math.sin(2 * i))
plt.xlabel('X')
plt.ylabel('Y')
plt.title('Deltoid Curve')
plt.plot(x, y)
plt.show()

Ankit Khandelwal_HW1/Exercise 12/exercise 12a.py


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

'''
an example of a genetic algorithm optimizing the parameters of a linear equation to find the
line of best fit for given points

there are only two parameters that are being optimized, but is easily scaleable;
    slope(flaot): between -10 and 10 --- this may need to be changed if the best fit line has a more extreme slope

    y-int(flaot): between -10 and 10 --- may also need to be changed depending on the location of the data

feel free to modify/add points or number of generations evolved

ethan gilmore
10/17/19
'''

x_points = [1, 1.5, 1.9, 2.1, 2.75, 4]
y_points = [5, 4.3, 2.4, 3.7, 2.5, 1]

'''
this is the structure for defining a set of parameters, or "gene_structure"

your parameters will be represented inside a dictionary with the keys named what the values represent
the value for each pair will be a 3-tuple

if you want your value to be a
    float: (float, min, max)
        float defines the type, but replace the min and the max fo set the bounds for the variable

    int: (int, min, max)
        int defines the type, replace min and max to set bounds

    list: (list, length, type)
        a list is a little different. the first element will be list to define it as a list
        second is the length, or number of things in the list
        third is the type of variable in the list - a float or an int

        example:
            {"my_list": (list, 10, (int, 1, 10))}
            this will create a paramter called my_list which is a list of length 10 filled with ints between 1 and 10
'''
parameters = {"slope": (float, -10, 10), "y-int": (float, -10, 10)}

'''
this is the structure for a fitness function

a fitness function is what determines how good a set of parameters (reffered to as an organism) is.
your fitness function should consist of;

Args:
    parameters / genes(dict): the actual values of an organism, modeled to your predefined structure

Returns:
    (int or float): returns a value specifying how good a set of paramters performed

    keep in mind that organisms (sets of parameters) with the HIGHEST RETURN VALUE when passed through
    this function are the ones kept and chosen to reproduce
'''

def loss(parameters):
    mean_squared_error = 0
    #find the total error of the line and the points
    for i, x in enumerate(x_points):
        #find the error between the actual y and the y of the function built with slope and y-int
        error = y_points[i] - (x * parameters['slope'] + parameters['y-int'])
        #decrease the mean squared error, because i want the set of parameters with the least difference to be greater
        #i.e. those with a greater error will be have a more negative fitness score
        mean_squared_error -= error**2
    return mean_squared_error

#create a population of size 20 with the paremeters and loss function we created
pop = genetic.Population(20, parameters, loss)
[pop.evolve() for i in range(10000)]

#set the slope and y-int to the organism with the best fitness
slope = pop.organisms[-1]['slope']
y_int = pop.organisms[-1]['y-int']

#used to plot points and the corrosponding line of best fit
plt.plot(x_points, y_points, 'ro')
x = np.linspace(-5,5,100)
y = slope*x+y_int
plt.plot(x, y)
plt.show()


#!/usr/bin/env
# -*- coding: utf-8 -*-
# Copyright (C) Victor M. Mendiola Lau - All Rights Reserved
# Unauthorized copying of this file, via any medium is strictly prohibited
# Proprietary and confidential
# Written by Victor M. Mendiola Lau <ryuzakyl@gmail.com>, August 2016

from math import sqrt
import numpy as np
from scipy.stats.stats import pearsonr

def probabilistic_pearsonr(x, y):
    """Computes the pearson coefficient as a probability value.

    Args:
        x (list): The first vector.
        y (list): The second vector.

    Returns:
        float: The pearson probability value between vectors x and y.

    """

    # computing the correlation value
    value = pearsonr(x, y)[0]       # getting only the first value of the tuple

    # moving value to interval [0, 2]
    value += 1.0

    # stretching value to the interval [0, 1]
    return 0.5 * value

def dis_pearsonr(x, y):
    """Computes the pearson coefficient as a dissimilarity value.

    Args:
        x (list): The first vector.
        y (list): The second vector.

    Returns:
        float: The pearson dissimilarity value between vectors x and y.

    """

    # computing the correlation value
    value = pearsonr(x, y)[0]       # getting only the first value of the tuple

    # setting dissimilarity value to the interval [0, 2]
    return 1 - value

def dissimilarity_pcc(x, y):
    """Computes a dissimilarity value based on a Pearson Correlation Coefficient.

    Args:
        x (list): The first vector.
        y (list): The second vector.

    Returns:
        float: The pearson correlation coefficient-based dissimilarity value between vectors x and y.

    """

    # getting the length of the vectors
    x_length = len(x)
    y_length = len(y)

    # validating parameters
    if x_length != y_length:
        raise Exception('Vectors with different sizes')

    # TODO: Here it is assumed that x and y are lists. Analyze the possibility for them to be tuples or numpy arrays

    # converting x and y to numpy arrays
    x_arr = np.array(x, np.float32)
    y_arr = np.array(y, np.float32)

    # computing vectors means and centered vectors
    x_mean = np.mean(x_arr)
    x_cent = x - x_mean
    y_mean = np.mean(y_arr)
    y_cent = y - y_mean

    num = np.dot(x_cent, y_cent)
    den = sqrt(np.dot(x_cent, x_cent) * np.dot(y_cent, y_cent))

    return 1 - num/den


# evolution strategy (mu + lambda) of the ackley objective function
from numpy import asarray
from numpy import exp
from numpy import sqrt
from numpy import cos
from numpy import e
from numpy import pi
from numpy import argsort
from numpy.random import randn
from numpy.random import rand
from numpy.random import seed

# objective function
def objective(v):
	x, y = v
	return -20.0 * exp(-0.2 * sqrt(0.5 * (x**2 + y**2))) - exp(0.5 * (cos(2 * pi * x) + cos(2 * pi * y))) + e + 20

# check if a point is within the bounds of the search
def in_bounds(point, bounds):
	# enumerate all dimensions of the point
	for d in range(len(bounds)):
		# check if out of bounds for this dimension
		if point[d] < bounds[d, 0] or point[d] > bounds[d, 1]:
			return False
	return True

# evolution strategy (mu + lambda) algorithm
def es_plus(objective, bounds, n_iter, step_size, mu, lam):
	best, best_eval = None, 1e+10
	# calculate the number of children per parent
	n_children = int(lam / mu)
	# initial population
	population = list()
	for _ in range(lam):
		candidate = None
		while candidate is None or not in_bounds(candidate, bounds):
			candidate = bounds[:, 0] + rand(len(bounds)) * (bounds[:, 1] - bounds[:, 0])
		population.append(candidate)
	# perform the search
	for epoch in range(n_iter):
		# evaluate fitness for the population
		scores = [objective(c) for c in population]
		# rank scores in ascending order
		ranks = argsort(argsort(scores))
		# select the indexes for the top mu ranked solutions
		selected = [i for i,_ in enumerate(ranks) if ranks[i] < mu]
		# create children from parents
		children = list()
		for i in selected:
			# check if this parent is the best solution ever seen
			if scores[i] < best_eval:
				best, best_eval = population[i], scores[i]
				print('%d, Best: f(%s) = %.5f' % (epoch, best, best_eval))
			# keep the parent
			children.append(population[i])
			# create children for parent
			for _ in range(n_children):
				child = None
				while child is None or not in_bounds(child, bounds):
					child = population[i] + randn(len(bounds)) * step_size
				children.append(child)
		# replace population with children
		population = children
	return [best, best_eval]

# seed the pseudorandom number generator
seed(1)
# define range for input
bounds = asarray([[-5.0, 5.0], [-5.0, 5.0]])
# define the total iterations
n_iter = 5000
# define the maximum step size
step_size = 0.15
# number of parents selected
mu = 20
# the number of children generated by parents
lam = 100
# perform the evolution strategy (mu + lambda) search
best, score = es_plus(objective, bounds, n_iter, step_size, mu, lam)
print('Done!')
print('f(%s) = %f' % (best, score))


import numpy as np

def get_indices(N, n_batches, split_ratio):
    """Generates splits of indices from 0 to N-1 into uniformly distributed\
       batches. Each batch is defined by 3 indices [i, j, k] where\
       (j-i) = (1/split_ratio)*(k-j). The first batch starts with i = 0,\
       the last one ends with k = N - 1.
    Args:
        N (int): total counts
        n_batches (int): number of splits
        split_ratio (float): split ratio, defines position of j in [i, j, k].
    Returns:
        generator for batch indices [i, j, k]
        ---------------------------------------
        Assume inds(n)[i] = inds(n-1)[i] + a, where a = const and i = 0,1,2
        from this and the fact that K(n_batches) = N-1 we can find that a = (N - 1 - k0)/(n_batches-1)
        Next, find j0 = k0 /(split_ratio+1)
        Assuming that j1 = k0 we get that j1 = j0 + a = k0, where j0,a are already found before.
        Finally, from that equation we get k0 = ((N-1)*(split_ratio+1))/(split_ratio*n_batches+1)
    """
    #inds = np.array([0, 0, 0])
    k0 = ((N-1)*(split_ratio+1))/(split_ratio*n_batches+1)
    j0 = k0 /(split_ratio+1)
    i0 = 0
    inds = np.array([i0, j0, k0])
    a = (N - 1 - k0)/(n_batches-1)
    inds -= a
    for i in range(n_batches):
        inds += a
        yield [int(round(inds[0])),int(round(inds[1])),int(round(inds[2]))]

def main():
    for inds in get_indices(100, 5, 0.25):
        print(inds)
    # expected result:
    # [0, 44, 55]
    # [11, 55, 66]
    # [22, 66, 77]
    # [33, 77, 88]
    # [44, 88, 99]

if __name__ == "__main__":
    main()


import copy
import numpy as np

# INPUTS
iters = 10
# data = [[-1,-1, 1],[1,0,-1],[-1,1.5,1]]
# data = [[-1,-1, 1],[1,0,-1],[-1,10,1]]
# data = [[-4,2, 1],[-2,1,1],[-1,-1,-1],[2,2,-1],[1,-2,-1]]
data = [(0,0,-1), (2,0,-1), (3,0,-1), (0,2,-1), (2,2,-1), (5,1,1), (5,2,1), (2,4,1), (4,4,1), (5,5,1)]

# SEPARATE DEPENDENT & INDEPENDENT
X = np.array( [ d[:-1] for d in data ] )
Y = np.array( [ d[-1] for d in data ] )

# INITIALIZE WEIGHTS & BIASES
theta = np.zeros(  ( len(data[0])-1 )  )
theta_0 = 0

# PERCEPTRON ALGORITHM
def perceptron(X, Y, theta, string, theta_0=0, iters=20):
    cntr = 0
    for iter_num in range(iters):
        print("ITER ", cntr)
        for i in range(len(Y)):
            theta0_before = copy.deepcopy(theta_0)
            theta_before = copy.deepcopy(theta)
            pred = (  theta.T @ X[i] + theta_0)
            loss = ( Y[i] * pred )
            if loss <= 0:
                theta = theta + Y[i] * X[i]
                theta_0 += Y[i]
            if theta0_before != theta_0:
                print(i, " :  MISTAKE!!")
            print("********* EPOCH COMPLETE ************")
        cntr += 1
    print("======================================================")
    print()
    print()
    return theta, theta_0

def d_hinge_loss(x, y, pred, theta):
    loss = max(1 - ( y * pred ), 0)
    if loss <= 0:
        d = theta
    else:
        d = -y*x - theta

    return d

def reg_perceptron(X, Y, theta, string, theta_0=0, iters=20):
    cntr = 0
    for iter_num in range(iters):
        print("ITER ", cntr)
        for i in range(len(Y)):
            pred = (  theta.T @ X[i] + theta_0)
            d = d_hinge_loss(x=X[i], y=Y[i], pred=pred, theta=theta)
            theta = theta - d
            theta_0 += Y[i]
            print("Updated: ", theta, "  |  ", theta_0)

            print("********* EPOCH COMPLETE ************")
        cntr += 1
    print("======================================================")
    print()
    print()
    return theta, theta_0

# a1, a2 = reg_perceptron(X=X, Y=Y, theta=np.zeros(  ( len(data[0])-1 )  ), string="CASE 1")
# print(a1, a2)

# a1, a2 = perceptron(X=X, Y=Y, theta=np.zeros(  ( len(data[0])-1 )  ), string="CASE 1")
# b1, b2 = perceptron(X=[X[1],X[2],X[0]], Y=[Y[1],Y[2],Y[0]], theta=np.zeros(  ( len(data[0])-1 )  ), string="CASE 2")
# c1, c2 = perceptron(X=[X[2],X[0],X[1]], Y=[Y[2],Y[0],Y[1]], theta=np.zeros(  ( len(data[0])-1 )  ), string="CASE 3")

# print(a1, a2)
# print(b1)
# print(c1)
# print(a2,b2,c2)
# print(a2)


# -*- coding: utf-8 -*-
"""
Created on Mon Oct  7 10:13:51 2019

@author: hamil
"""

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

#Plot the function to determine what the finction looks like to helps estimate a value
Eb = np.arange(0,10, 0.1)
y = (np.sqrt(10 - Eb)*np.tan(np.sqrt(10-Eb)) - np.sqrt(Eb))

plt.plot(Eb, y)
plt.ylim(-50,50)
plt.title("Even function with binding potential of 10")
plt.grid()
plt.show()

#Now use the Bisection method to determine where F(Eb) = 0
def funct(Eb):
    return (np.sqrt(10 - Eb)*np.tan(np.sqrt(10-Eb)) - np.sqrt(Eb))

guess = optimize.bisect(funct, 8, 9)
print("Guess for the Bisection Method:", guess)

#Now use the Newton / Raphson Method to determine where F(Eb) = 0
x0 = 8.5

newguess = optimize.newton(funct, x0)
print("Guess for the Newton/Raphson Method:", newguess)

#When looking at the two results, there are quite similar to 10**-8 decimal place.
#Then the question would be which is more accurate, both are precise to 10**-8.

#Now we can check the values returned for each method within our function

test1 = funct(guess)
test2 = funct(newguess)
print("The f(Eb) values for the Bisection method result and the Newton/Raphson method:", test1,test2)

#Based on the values determined by the two different methods, the second method, Newton/Raphson
#is more precise. This would be due to the fact that the result is two orders of magnitude smaller
#(closer to zero).

#Show that the equation is the alternative form for the original equation
y2 = ((np.sqrt(Eb)*(1/np.tan(np.sqrt(10-Eb))))-(np.sqrt(10-Eb)))
plt.plot(Eb,y)
plt.plot(Eb,y2)
plt.ylim(-50,50)
plt.title("Both functions with binding potential of 10")
plt.grid()
plt.show()
#This equation seems to be a mirror of the first equation. This equation also does not extend deeply
#into negative values. I believe that the root is equal or relatively close to being
#equal to the original equation.

def funct2(Eb):
    return ((np.sqrt(Eb)*(1/np.tan(np.sqrt(10-Eb))))-(np.sqrt(10-Eb)))

guess3 = optimize.bisect(funct2, 8,9)
guess4 = optimize.newton(funct2, x0)
print("Guess for the Bisection and Newton/Raphson methods for equation two:", guess3, guess4)

#Now to change the value of 10 to 20 and 30 within the functions
y3 = (np.sqrt(20 - Eb)*np.tan(np.sqrt(20-Eb)) - np.sqrt(Eb))
y4 = (np.sqrt(Eb)*(1/np.tan(np.sqrt(20-Eb))))-(np.sqrt(20-Eb))

plt.plot(Eb,y3)
plt.plot(Eb, y4)
plt.title("Functions with binding potential of 20")
plt.grid()
plt.show()

y5 = (np.sqrt(30 - Eb)*np.tan(np.sqrt(30-Eb)) - np.sqrt(Eb))
y6 = (np.sqrt(Eb)*(1/np.tan(np.sqrt(30-Eb))))-(np.sqrt(30-Eb))

plt.plot(Eb,y5)
plt.plot(Eb, y6)
plt.title("Functions with binding potential of 30")
plt.xlim(5,10)
plt.grid()
plt.show()

#When you change the binding potential to 20, is really shows how the mirror each other.
#Once you change the value to 30, the even function actually goes to zero and the other
#function significantly peaks at around 8.

#Now to find the roots for each new value
def funct3(Eb):
    return (np.sqrt(20 - Eb)*np.tan(np.sqrt(20-Eb)) - np.sqrt(Eb))
#redo functions then use methods to find roots to compare
def funct4(Eb):
    return (np.sqrt(30 - Eb)*np.tan(np.sqrt(30-Eb)) - np.sqrt(Eb))

x1 = 6
guess5 = optimize.bisect(funct3,5,7)
guess6 = optimize.newton(funct3, x1)
print("Guess for bisection and Newton Methods with binding potential set to 20:", guess5, guess6)

guess7 = optimize.bisect(funct4,8,15)
guess8 = optimize.newton(funct4, x0)
print("Guess for bisection and Newton Methods with binding potential set to 30:", guess5, guess6)
test3 = funct3(guess5)
test4 = funct3(guess6)
test5 = funct4(guess7)
test6 = funct4(guess8)
print("The y values for the function with binding potential of 20:", test3, test4)
print("The y values for the function with binding potential of 30:", test5, test6)

#When looking at the root values for the function with the two different binding potentials,
#it seems the binding potential at 30 is more unrealistic and the values of the root does not make
#too much sense. I would say the best binding potential would be between 10 and 20. The values for
#for the function are very close again, this time to the 10*-10. WHen looking at the values for f(Eb),
#the bisection method seems to be better for the binding potential set to 20, since it is positive.
#the function with binding potential set to 30 seems to be fairly off due to the fact that the
#f(Eb) values are both negative for both methods. With that being said over all (All functions) the Newton/Raphson
#method seems to be more precise.

#Now to try another method to find the roots and test the precision
#Lets use Ridder's method and compare to the others:
guesses = optimize.ridder(funct,8,9)
print("This is the guess for the Ridder Method:", guesses)
print("again the bisection and Newtons/Raphson:", guess, newguess)

#Now to check the precision of all three together
test9 = funct(guesses)
print("Respective precisions for Bisection, Newton/Raphson, Ridder:", test1,test2,test9)

#It seems the precision for the bisection and the ridder are on the same scale and the precision for the
#Newton/Raphson is better. This makes sense with the similarities between the bisection method and the
#ridder method. But the ridder tends to run faster than the bisection. This method uses the false position method
#a trial and error method but tends to have a better constraint on the tolarance. This method also determines that
#convergance is guarunteed such as the bisection method.


"""Poisson Distribution
=============================
Contains the concrete definition of PoissonDistribution.

Example:
    Creating the distribution::

        dist = PoissonDistribution(5)

"""

from __future__ import annotations

from gsf.core.mathematics.distributions.random_distribution import RandomDistribution
import numpy as np

class PoissonDistribution(RandomDistribution):
    """Poisson Distribution

    Draw samples from a Poisson distribution."""

    __mean: float
    """Mean of the distribution."""

    def __init__(self, mean: float):
        """Creates a poisson distribution

        Args:
            mean (float): Mean of the distribution.
        """
        self.__mean = mean

    def generate(self) -> int:
        """Generates a value following the distribution"""
        return np.random.poisson(self.__mean)

    def generate_list(self, size: int) -> np.ndarray:
        """Generates a ndarray of values following the distribution

        Args:
            size (int): Size of the list
        """
        return np.random.poisson(self.__mean, size)

    def evaluate(self) -> int:
        """Evaluates the expression"""
        return self.generate()

    def __str__(self):
        return super().__str__() + ".Poisson(" + str(self.__mean) + ")"


import numpy as np
import scipy.stats as spst

def ret2dva(r_um):
    """Converts retinal distances (um) to visual angles (deg)

    This function converts an eccentricity measurement on the retinal
    surface(in micrometers), measured from the optic axis, into degrees
    of visual angle.
    Source: Eq. A6 in Watson(2014), J Vis 14(7): 15, 1 - 17
    """
    sign = np.sign(r_um)
    r_mm = 1e-3 * np.abs(r_um)
    r_deg = 3.556 * r_mm + 0.05993 * r_mm ** 2 - 0.007358 * r_mm ** 3
    r_deg += 3.027e-4 * r_mm ** 4
    return sign * r_deg

def dva2ret(r_deg):
    """Converts visual angles (deg) into retinal distances (um)

    This function converts a retinal distancefrom the optic axis(um)
    into degrees of visual angle.
    Source: Eq. A5 in Watson(2014), J Vis 14(7): 15, 1 - 17
    """
    sign = np.sign(r_deg)
    r_deg = np.abs(r_deg)
    r_mm = 0.268 * r_deg + 3.427e-4 * r_deg ** 2 - 8.3309e-6 * r_deg ** 3
    r_um = 1e3 * r_mm
    return sign * r_um

def cart2pol(x, y):
    theta = np.arctan2(y, x)
    rho = np.hypot(x, y)
    return theta, rho

def pol2cart(theta, rho):
    x = rho * np.cos(theta)
    y = rho * np.sin(theta)
    return x, y

def angle_diff(angle1, angle2, lo=0, hi=2 * np.pi):
    """Returns the signed difference between two angles (rad)

    The difference is calculated as angle2 - angle1. The difference will thus
    be positive if angle2 > angle1.

    Parameters
    ----------
    angle1, angle2 : array_like
        Input arrays with circular data in the range [lo, hi]

    Returns
    -------
    The signed difference angle2 - angle1 in [lo, hi]
    """
    # https://stackoverflow.com/questions/1878907/
    #    the-smallest-difference-between-2-angles
    _, angle1 = spst.morestats._circfuncs_common(angle1, hi, lo)
    _, angle2 = spst.morestats._circfuncs_common(angle2, hi, lo)
    diff = np.arctan2(np.sin(angle2 - angle1), np.cos(angle2 - angle1))
    return diff * (hi - lo) / 2.0 / np.pi + lo

def circfve(r_true, r_pred, lo=0, hi=2 * np.pi):
    """Calculates the fraction of variance explained (FVE) for circular data

    Assumes circular data are in the range [lo, hi].
    Uses SciPy's circular stats functions.

    Parameters
    ----------
    r_true : array_like
        Circular data (ground-truth)
    r_pred : array_like
        Circular data (predicted)
    low : float or int, optional
        Low boundary for circular variance range.  Default is 0.
    high : float or int, optional
        High boundary for circular variance range.  Default is ``2*pi``.
    """
    r_true = np.asarray(r_true)
    r_pred = np.asarray(r_pred)
    r_mu_true = spst.circmean(r_true, low=lo, high=hi)
    var_err = spst.circvar(angle_diff(r_true, r_pred, lo=lo, hi=hi),
                           low=lo, high=hi)
    var_tot = spst.circvar(angle_diff(r_true, r_mu_true, lo=lo, hi=hi),
                           low=lo, high=hi)
    if np.isclose(var_err, 0) and np.isclose(var_tot, 0):
        return 1
    if np.isclose(var_tot, 0):
        return 0
    return (1 - var_err / var_tot)


# -----------------------------------------------------------------------------
# Author: Erik Rydow
# Email: erik.rydow@kcl.ac.uk
# Extended from code by Nicolas P. Rougier https://gist.github.com/rougier/e5eafc276a4e54f516ed5559df4242c0
#
# From https://en.wikipedia.org/wiki/Minkowski–Bouligand_dimension:
#
# In fractal geometry, the Minkowski–Bouligand dimension, also known as
# Minkowski dimension or box-counting dimension, is a way of determining the
# fractal dimension of a set S in a Euclidean space Rn, or more generally in a
# metric space (X, d).
# -----------------------------------------------------------------------------
import imageio
import numpy as np

def fractal_dimension(Z, threshold=0.8):
    """Returns box-counting dimension of a 2D array.

    Args:
        Z: 2D array to be analysed.
        threshold: Cutoff for converting values in Z to 1 and 0.

    Returns:
        The estimated box counting dimension.
    """

    # Only for 2d image
    assert(len(Z.shape) == 2)

    # From https://github.com/rougier/numpy-100 (#87)
    def boxcount(Z, k):
        S = np.add.reduceat(
            np.add.reduceat(Z, np.arange(0, Z.shape[0], k), axis=0),
                               np.arange(0, Z.shape[1], k), axis=1)

        # We count non-empty (0) and non-full boxes (k*k)
        return len(np.where((S > 0) & (S < k*k))[0])

    # Transform Z into a binary array
    Z = (Z < threshold)

    # Minimal dimension of image
    p = min(Z.shape)

    # Greatest power of 2 less than or equal to p
    n = 2**np.floor(np.log(p)/np.log(2))

    # Extract the exponent
    n = int(np.log(n)/np.log(2))

    # Build successive box sizes (from 2**n down to 2**1)
    sizes = 2**np.arange(n, 1, -1)

    # Actual box counting with decreasing size
    counts = []
    for size in sizes:
        counts.append(boxcount(Z, size))

    # Fit the successive log(sizes) with log (counts)
    coeffs = np.polyfit(np.log(sizes), np.log(counts), 1)
    return -coeffs[0]

I = imageio.imread("sierpinski.png", as_gray="True")/255.0    # Import the image in greyscale
print("Minkowski–Bouligand dimension (computed): ", fractal_dimension(I))
print("Haussdorf dimension (theoretical):        ", (np.log(3)/np.log(2)))


"""Module to calculate best path between multiple points, using simulated annealing algorithm

Functions:
distance -- cost function that calculates distance as the cost of a path
new_path -- path altering function that creates a new path
new_path_modified -- same as new_path but slightly modified
simulated_annealing_optimizer -- objective function that implements the simulated annealing algorithm
"""

import random
import numpy as np

def distance(coords):
    """Calculate the distance of a path between multiple points

    Arguments received:
    coords — list of coordinates, e.g. [(0,0), (10, 5), (10, 10)], representing a path

    Arguments returned:
    distance -- total distance as a float
    """
    distance = 0
    for p1, p2 in zip(coords[:-1], coords[1:]):
        distance += ((p2[0] - p1[0]) ** 2 + (p2[1] - p1[1]) ** 2) ** 0.5
    return distance

def new_path(existing_path):
    """Switch two random consecutive points on a path

    Arguments received:
    existing_path -- list of coordinates representing a path

    Arguments returned:
    path -- list of coordinates representing the mutated path
    """
    path = existing_path[:]
    point = random.randint(0, len(path)-2)  # randomly choose a point between 1st and 2nd-to-last points on path
    path[point+1], path[point] = path[point], path[point+1]  # switch this point with the next point
    return path

# Our simulated annealing function generated a reasonable solution but there were signs that the approach was
# limited by our function for creating new paths. Create a new function to generate paths in a different way.
# Does this improve the performance of the simulated annealing function? Answer in workspace.py, along with timer.

def new_path_modified(existing_path):
    """Switch two random points on a path

    Arguments received:
    existing_path -- list of coordinates representing a path

    Arguments returned:
    path -- list of coordinates representing the mutated path
    """
    path = existing_path[:]
    point = random.randint(0, len(path)-1)  # randomly choose any point on path
    point2 = random.randint(0, len(path)-1)  # randomly choose any other point on path
    while point2 == point:
        point2 = random.randint(0, len(path)-1)
    temp = path[point]  # temporary placeholder for 1st point
    path[point], path[point2] = path[point2], temp  # switch 1st point with 2nd point
    return path

def simulated_annealing_optimizer(starting_path, cost_func, new_path_func, start_temp, min_temp, steps):
    """Calculate the best path between multiple points using a simulated annealing algorithm

    The simulated annealing algorithm begins with a given path and calculates its cost.
    Each iteration generates a new path with two random consecutive points switched.
    If the new path has a lower cost, it is better and will replace the current path.
    If it has a higher cost, it is a worse path and may replace the current path, as
    decided by comparing a random number with an acceptance probability that depends on
    the temperature. The temperature decreases a bit in each iteration, giving worse paths
    a lesser chance of replacing the current path. Allowing worse paths at the beginning
    helps to avoid converging to a local minimum rather than the global minimum.

    Arugments received:
    starting_path -- list of coordinates representing a path
    cost_func -- function to calculate cost of a path
    new_path_func -- function to generate a new path with two random consecutive points switched
    start_temp -- maximum temperature
    min_temp -- minimum temperature
    steps -- number of iterations

    Arguments returned:
    current_path -- list of coordinates representing the best path
    current_cost -- cost of the best path
    history -- an array of objects, each object containing information about each tested path
    """
    current_path = starting_path[:]
    current_cost = cost_func(current_path)
    temp_factor = -np.log(start_temp / min_temp)
    history = []
    for s in range(0, steps):
        temp = start_temp * np.exp(temp_factor * s / steps)
        new_path = new_path_func(current_path)
        new_cost = cost_func(new_path)
        if (new_cost < current_cost) or (random.random() <= np.exp(-(new_cost - current_cost)/temp)):
            current_path = new_path
            current_cost = new_cost
        record = {'step': s, 'temperature': temp, 'current_cost': current_cost, }
        history.append(record)
    return (current_path, current_cost, history)


import numpy as np
import numpy.linalg as la
from numbers import Number
from scipy import stats

def sequ(n,d,lb=0,ub=1,method=None,randomized=True, random_state = 1, rng= None,return_likelihood = False):
    if rng is None:
        rng = np.random.RandomState(seed=random_state)
    if method is None:
        seq = np.zeros((n,d))
    elif method == "uniform":
        n0 = int(np.power(n,1/d))
        assert n == n0 **d, 'this method does not apply to n = %d'%n
        tmp_list = np.linspace(0,1,n0+1)
        tmp_list = (tmp_list[:-1]+tmp_list[1:])/2
        dim_grid_list = [list(tmp_list) for i in range(d)]
        seq = np.stack(np.meshgrid(*dim_grid_list)).T.reshape(n,d)
    elif method == "random":
        seq = rng.rand(n,d)

    if randomized and method!="random":
        seq += rng.rand(n,d)
        seq = np.mod(seq,1.0)
    seq = lb+seq*(ub-lb)
    if not return_likelihood:
        return seq
    else:
        if isinstance(ub-lb,Number):
            return seq, np.ones(n)/np.power(ub-lb,d)
        else:
            return seq, np.ones(n)/np.prod(ub-lb)

def generate_multivariate_normal(Z,mu,Sigma):
    C = la.cholesky(Sigma)
    X = Z@C.T + mu
    likelihood = np.exp(-np.sum(Z*Z,axis=1)/2)/np.power(2*np.pi,len(mu)/2)/np.sqrt(la.det(Sigma))
    return X,likelihood

def seqn(n,d,mu=0,Sigma=1,method=None,randomized=True, random_state = 1,rng=None,return_likelihood = False):
    if method != "random":
        seq = sequ(n,d,0,1,method,randomized,random_state,rng,False)
        seq = stats.norm.ppf(seq)
    else:
        if rng is None:
            rng = np.random.RandomState(seed=random_state)
        seq = rng.randn(n,d)

    if isinstance(mu,Number):
        mu = mu*np.ones(d)
    if isinstance(Sigma,Number):
        Sigma = np.diag(np.ones(d)*Sigma)

    if return_likelihood:
        return generate_multivariate_normal(seq, mu,Sigma)
    else:
        return generate_multivariate_normal(seq, mu,Sigma)[0]

class SeqGenerator:
    def __init__(self, method = None, randomized=True, seed = 1, rng = None):
        self.method = method
        self.randomized = randomized
        self.seed = seed
        if rng is None:
            self.rng = np.random.RandomState(seed=random_state)
        else:
            self.rng = rng
        self.cur_state = seed
    def rand(self,n,d, lb=0,ub=1,return_likelihood = False):
        res = sequ(n,d,lb=lb,ub=ub,method=self.method,randomized=self.randomized, random_state = self.cur_state, rng= self.rng,return_likelihood = return_likelihood)
        self.cur_state += n
        return res
    def randn(self,n,d,mu=0,Sigma=1,return_likelihood = False):
        res = seqn(n,d,mu=mu,Sigma=Sigma,method=self.method,randomized=self.randomized, random_state = self.cur_state,rng=self.rng,return_likelihood = return_likelihood)
        self.cur_state += n
        return res


# Linear autoencoder (ie PCA) applied to a 3d dataset projecting to 2d
#https://github.com/ageron/handson-ml2/blob/master/17_autoencoders_and_gans.ipynb

import superimport

import numpy as np
import matplotlib.pyplot as plt
import os
figdir = "../figures"
def save_fig(fname): plt.savefig(os.path.join(figdir, fname))

import tensorflow as tf
from tensorflow import keras

from sklearn.decomposition import PCA

from mpl_toolkits import mplot3d
from mpl_toolkits.mplot3d import Axes3D

np.random.seed(4)

def generate_3d_data(m, w1=0.1, w2=0.3, noise=0.1):
    angles = np.random.rand(m) * 3 * np.pi / 2 - 0.5
    data = np.empty((m, 3))
    data[:, 0] = np.cos(angles) + np.sin(angles)/2 + noise * np.random.randn(m) / 2
    data[:, 1] = np.sin(angles) * 0.7 + noise * np.random.randn(m) / 2
    data[:, 2] = data[:, 0] * w1 + data[:, 1] * w2 + noise * np.random.randn(m)
    return data

X_train = generate_3d_data(60)
X_train = X_train - X_train.mean(axis=0, keepdims=0)

np.random.seed(42)
tf.random.set_seed(42)

encoder = keras.models.Sequential([keras.layers.Dense(2, input_shape=[3])])
decoder = keras.models.Sequential([keras.layers.Dense(3, input_shape=[2])])
autoencoder = keras.models.Sequential([encoder, decoder])

autoencoder.compile(loss="mse", optimizer=keras.optimizers.SGD(lr=1.5))

history = autoencoder.fit(X_train, X_train, epochs=20)

codings = encoder.predict(X_train)

X = X_train
fig = plt.figure().gca(projection='3d')
fig.scatter(X[:,0], X[:,1], X[:,2], s=50, marker='o')
save_fig("linear-autoecoder-data3d.pdf")
plt.show()

fig = plt.figure(figsize=(4,3))
plt.plot(codings[:,0], codings[:, 1], "b.")
plt.xlabel("$z_1$", fontsize=18)
plt.ylabel("$z_2$", fontsize=18, rotation=0)
plt.grid(True)
save_fig("linear-autoencoder-embedding.pdf")
plt.show()

# PCA version

pca = PCA(n_components=2)
mu = np.mean(X_train, axis=0)
Xc = X_train - mu # center the data
pca.fit(Xc)
W = pca.components_.T # D*K
Z = np.dot(Xc, W) # N * K latent scores
Xrecon = np.dot(Z, W.T) + mu # N*D

fig = plt.figure(figsize=(4,3))
plt.plot(Z[:,0], Z[:, 1], "b.")
plt.xlabel("$z_1$", fontsize=18)
plt.ylabel("$z_2$", fontsize=18, rotation=0)
plt.grid(True)
save_fig("linear-autoencoder-pca.pdf")
plt.show()


"""Swap operator."""
from typing import List, Union

import numpy as np

from toqito.matrices import iden
from toqito.perms import swap

def swap_operator(dim: Union[List[int], int], is_sparse: bool = False) -> np.ndarray:
    r"""
    Produce a unitary operator that swaps two subsystems.

    Provides the unitary operator that swaps two copies of :code:`dim`-dimensional space. If the two
    subsystems are not of the same dimension, :code:`dim` should be a 1-by-2 vector containing the
    dimension of the subsystems.

    Examples
    ==========

    The :math:`2`-dimensional swap operator is given by the following matrix

    .. math::
        X_2 =
        \begin{pmatrix}
            1 & 0 & 0 & 0 \\
            0 & 0 & 1 & 0 \\
            0 & 1 & 0 & 0 \\
            0 & 0 & 0 & 1
        \end{pmatrix}

    Using :code:`toqito` we can obtain this matrix as follows.

    >>> from toqito.perms import swap_operator
    >>> swap_operator(2)
    [[1., 0., 0., 0.],
     [0., 0., 1., 0.],
     [0., 1., 0., 0.],
     [0., 0., 0., 1.]]

    The :math:`3`-dimensional operator may be obtained using :code:`toqito` as follows.

    >>> from toqito.perms import swap_operator
    >>> swap_operator(3)
    [[1., 0., 0., 0., 0., 0., 0., 0., 0.],
     [0., 0., 0., 1., 0., 0., 0., 0., 0.],
     [0., 0., 0., 0., 0., 0., 1., 0., 0.],
     [0., 1., 0., 0., 0., 0., 0., 0., 0.],
     [0., 0., 0., 0., 1., 0., 0., 0., 0.],
     [0., 0., 0., 0., 0., 0., 0., 1., 0.],
     [0., 0., 1., 0., 0., 0., 0., 0., 0.],
     [0., 0., 0., 0., 0., 1., 0., 0., 0.],
     [0., 0., 0., 0., 0., 0., 0., 0., 1.]]

    :param dim: The dimensions of the subsystems.
    :param is_sparse: Sparse if :code:`True` and non-sparse if :code:`False`.
    :return: The swap operator of dimension :code:`dim`.
    """
    # Allow the user to enter a single number for dimension.
    if isinstance(dim, int):
        dim = np.array([dim, dim])

    # Swap the rows of the identity appropriately.
    return swap(iden(int(np.prod(dim)), is_sparse), [1, 2], dim, True)


# **************************************************************************** #
#                                                                              #
#                                                         :::      ::::::::    #
#    variance.py                                        :+:      :+:    :+:    #
#                                                     +:+ +:+         +:+      #
#    By: ciglesia <ciglesia@student.42.fr>          +#+  +:+       +#+         #
#                                                 +#+#+#+#+#+   +#+            #
#    Created: 2020/11/22 23:53:26 by ciglesia          #+#    #+#              #
#    Updated: 2020/11/23 19:11:18 by ciglesia         ###   ########.fr        #
#                                                                              #
# **************************************************************************** #

import sys
from pathlib import Path
sys.path.append(str(Path(__file__).parent.parent.absolute()))
import ex00.sum as s
import ex01.mean as m

def variance(x):
    """
    Computes the variance of a non-empty numpy.ndarray, using a for-loop.
    Args:
    x: has to be an numpy.ndarray, a vector.
    Returns:
    The variance as a float.
    None if x is an empty numpy.ndarray.
    Raises:
    This function should not raise any Exception.
    """
    if (not s.elements(x)):
        return (None)
    mean = m.mean(x)
    return (s.sum_(x, lambda X: (X - mean)**2) / len(x))

if __name__ == "__main__":
    import numpy as np
    print("X = np.array([0, 15, -9, 7, 12, 3, -21])\nvariance(X)")
    X = np.array([0, 15, -9, 7, 12, 3, -21])
    print(variance(X))


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

def dt_x(c, x):
    return c * x

def simulate_prey_using_euler_method(c, x0, t, delta_t):
    x = x0
    for _ in np.arange(0, t, delta_t):
        x += dt_x(c, x) * delta_t
    return x

def simulate_prey_using_midpoint_method(c, x0, t, delta_t):
    x = x0
    for _ in np.arange(0, t, delta_t):
        dx_dt0 = c * x
        x05 = x + 0.5 * dx_dt0 * delta_t
        dx_dt05 = c * x05
        x += dx_dt05 * delta_t
    return x

def simulate_prey_using_analytical_method(c, x0, t):
    return x0 * np.exp(c * t)

def get_prey_euler_simulation_error(c, x0, t, delta_t):
    return simulate_prey_using_euler_method(
        c, x0, t, delta_t
    ) - simulate_prey_using_analytical_method(c, x0, t)

def get_prey_midpoint_simulation_error(c, x0, t, delta_t):
    return simulate_prey_using_midpoint_method(
        c, x0, t, delta_t
    ) - simulate_prey_using_analytical_method(c, x0, t)

def print_error(delta_t):
    c = 0.03
    x0 = 1000.0
    t = 20.0

    euler_error = get_prey_euler_simulation_error(c, x0, t, delta_t)
    print(f"Euler error with delta t = {delta_t}: {euler_error}")
    midpoint_error = get_prey_midpoint_simulation_error(c, x0, t, delta_t)
    print(f"Midpoint error with delta t = {delta_t}: {midpoint_error}")

if __name__ == "__main__":
    print_error(0.05)
    print_error(0.1)
    print_error(0.2)


"""The Gamma distribution."""
from equadratures.distributions.template import Distribution
import numpy as np
from scipy.stats import gamma
RECURRENCE_PDF_SAMPLES = 8000
class Gamma(Distribution):
    """
    The class defines a Gamma object. It is the child of Distribution.

    :param double shape:
		Shape parameter of the gamma distribution.
    :param double scale:
		Scale parameter of the gamma distribution.
    """
    def __init__(self, shape=None, scale=None):
        if shape is None:
            self.shape = 1.0
        else:
            self.shape = shape
        if scale is None:
            self.scale = 1.0
        else:
            self.scale = scale

        self.bounds = np.array([0.0, np.inf])
        if self.shape < 0 or self.scale < 0:
            raise ValueError('Invalid parameters in Gamma distribution. Shape and Scale should be positive.')
        self.parent = gamma(a=self.shape, scale=self.scale)
        self.mean, self.variance, self.skewness, self.kurtosis = self.parent.stats(moments='mvsk')
        self.x_range_for_pdf = np.linspace(0, self.scale*10, RECURRENCE_PDF_SAMPLES)

    def get_description(self):
        """
        A description of the gamma distribution.

        :param Gamma self:
            An instance of the Gamma class.
        :return:
            A string describing the gamma distribution.
        """
        text = "is a gamma distribution with a shape parameter of "+str(self.shape)+", and a scale parameter of "+str(self.scale)+"."
        return text

    def get_pdf(self, points=None):
        """
        A gamma probability density function.

        :param Gamma self:
            An instance of the Gamma class.
        :param matrix points:
            Matrix of points for defining the probability density function.
        :return:
            An array of N equidistant values over the support of the distribution.
        :return:
            Probability density values along the support of the Gamma distribution.
        """
        if points is not None:
            return self.parent.pdf(points)
        else:
            raise ValueError( 'Please digit an input for getPDF method')

    def get_cdf(self, points=None):
        """
        A gamma cumulative density function.

        :param Gamma self:
            An instance of the Gamma class.
        :param matrix points:
            Matrix of points for defining the gamma cumulative density function.
        :return:
            An array of N equidistant values over the support of the gamma distribution.
        :return:
            Cumulative density values along the support of the gamma distribution.
        """
        if points is not None:
            return self.parent.cdf(points)
        else:
            raise ValueError( 'Please digit an input for getCDF method')
    def get_icdf(self, xx):
        """
        A gamma inverse cumulative density function.

        :param gamma self:
            An instance of Gamma class.
        :param xx:
            An array of points at which the inverse of cumulative density function needs to be evaluated.
        :return:
            Inverse cumulative density function values of the Gamma distribution.
        """
        return self.parent.ppf(xx)
    def get_samples(self, m=None):
        """
         Generates samples from the Gamma distribution.

         :param Gamma self:
             An instance of the Gamma class.
         :param integer m:
             Number of random samples. If no value is provided, a default of     5e5 is assumed.
         :return:
             A N-by-1 vector that contains the samples.
        """
        if m is not None:
           number = m
        else:
           number = 500000
        return self.parent.rvs(size = number)


# Class A is wTx >0
# Class B is wTx <=0

import numpy
import matplotlib.pyplot as plt

samplesize = 50

# Generating All random data for class A and Class B
xclassA = numpy.random.uniform(-1,1, size=samplesize)
yclassA = numpy.random.uniform(-1,1, size=samplesize)
xclassB = numpy.random.uniform(-1,1, size=samplesize)
yclassB = numpy.random.uniform(-1,1, size=samplesize)
ones = numpy.ones(samplesize)
xyclassA = numpy.c_[xclassA, yclassA,ones]
xyclassB = numpy.c_[xclassB, yclassB,ones]

# Creating w list
wList = [[1, 1 ,0], [-1,-1,0],[0,0.5,0],[1,-1,5],[1.0,1.0,0.3]]

# Calculating the accuracy
overallAccuracy = []
for w in wList :
    correct = [0 ,0]
    for cord in xyclassA:
        if(numpy.dot(w,cord)>0):
            correct[0] = correct[0] + 1
    correct[0]= correct[0]*100/samplesize
    for cord in xyclassB:
        if(numpy.dot(w,cord)<=0):
            correct[1] = correct[1] + 1
    correct[1]= correct[1]*100/samplesize
    overallAccuracy.append(correct)

print(overallAccuracy)
x = numpy.linspace(-2,2,1000)
plt.subplot(2, 2, 1)
plt.scatter(xclassA, yclassA, label= "classA", color= "green", s=10)
plt.scatter(xclassB, yclassB, label= "classB", color= "blue", s=10)
plt.plot(x,-x,linestyle='solid',color = "black")
plt.title('for W = [1, 1, 0]')
plt.legend()

plt.subplot(2, 2, 2)
plt.scatter(xclassA, yclassA, label= "classA", color= "green", s=10)
plt.scatter(xclassB, yclassB, label= "classB", color= "blue", s=10)
plt.plot(x,x+5,linestyle='solid',color = "black")
plt.title('for W = [1, -1, 5]')
plt.legend()

plt.subplot(2, 2, 3)
plt.scatter(xclassA, yclassA, label= "classA", color= "green", s=10)
plt.scatter(xclassB, yclassB, label= "classB", color= "blue", s=10)
plt.plot(x,-x-0.3,linestyle='solid',color = "black")
plt.title('for W = [1.0, 1.0, 0.3]')

plt.xlabel('x - axis')
plt.ylabel('y - axis')
plt.show()


import numpy as np
from ..utils import check_features, check_target
from .linear_regression import LinearRegression

class RidgeRegression(LinearRegression):
    """Linear regression with l2 regularization.

    Attributes:
        learning_rate: Rate of update for gradient descent at
        each iteration. Not used for other solving methods (float).
        num_iterations: Number of iterations for gradient descent (int).
        save_cost: Whether to save or not the cost of each iteration.
        Only used for gradient descent (boolean).
        grad_descent_cost: List with the cost for each iteration when
        using gradient descent (list of floats).
        parameters: nd array with the model parameters (theta).
    """

    def __init__(self, regularization=0.1, solving_method='normal_equation',
                 learning_rate=0.01, num_iter=1000, save_cost=False):
        self.regularization = regularization
        self.solving_method = solving_method
        self.learning_rate = learning_rate
        self.num_iterations = num_iter
        self.save_cost = save_cost

        solvers = ['normal_equation', 'gradient_descent']
        if self.solving_method not in solvers:
            raise ValueError("solving_method must be one of: ", solvers)

    def fit(self, x, y):
        """Fit a ridge regression model to features x and target y.

        Arguments:
            x: Features - nd array with shape (m_samples, n_features).
            If you have a pandas Dataframe use df.values.
            y: Target values. Can be a one or two dimensional numpy
            array with shape (m_samples,) or (m_samples, 1)
        """
        check_features(x)
        check_target(y)
        x = np.insert(x, 0, 1, axis=1)  # add bias
        y = y.reshape(-1, 1) if y.ndim == 1 else y

        if self.solving_method == 'normal_equation':
            self.normal_equation(x, y)
        else:
            self.parameters = np.zeros(shape=(x.shape[1], 1))
            self.batch_gradient_descent(x, y)
        return self

    def normal_equation(self, x, y):
        """Normal equation for ridge: inv(X'*X + lambda*L) * X' * Y."""
        # L is the identity matrix with shape (n+1) and first cell zero.
        L = np.identity(x.shape[1])
        L[0][0] = 0
        inverse = np.linalg.pinv(x.T @ x + self.regularization*L)
        self.parameters = inverse @ x.T @ y

    def hypothesis(self, x):
        """Hypothesis for linear regression (ax + b)."""
        return x @ self.parameters

    def gradient_function(self, x, y, predictions=None):
        """Compute the gradient with the current parameters."""
        if predictions is None:
            predictions = self.hypothesis(x)
        penalty = self.regularization * np.sum(self.parameters[1:])
        return x.T @ (predictions - y) + penalty

    def cost_function(self, x, y, predictions=None):
        """Return the cost for the current parameters using MSE."""
        if predictions is None:
            predictions = self.hypothesis(x)
        squared_error = np.sum(np.square(predictions - y))
        penalty = self.regularization * np.sum(np.square(self.parameters))
        return (squared_error + penalty) / (2 * x.shape[0])


import pickle
import re
import pandas as pd
import numpy as np
import math
from statsmodels.tsa.stattools import adfuller, kpss
from arch.unitroot import PhillipsPerron

"""
Refs:
- https://www.machinelearningplus.com/time-series/time-series-analysis-python/
- https://machinelearningmastery.com/time-series-data-stationary-python/
- https://www.machinelearningplus.com/time-series/arima-model-time-series-forecasting-python/
"""

class TimeSeriesAnalysis:
    def __init__(self, series: pd.Series):
        self.original_series = series
        self.series = series

    def interpolate_ts(self, method: str):
        pass

    def test_stationarity(self, test: str, threshold=0.05, **kwargs):
        """
        Test for the stationarity of a given series around a deterministic trend.
        Interesting ref: https://stats.stackexchange.com/questions/88407/adf-test-pp-test-kpss-test-which-test-to-prefer

        :param test:    unit root test. The first three all start with the null of a unit root and have an
                        alternative of a stationary process. The last one, KPSS, has a null of a stationary process
                        with an alternative of a unit root.
                        - 'adf' for Augmented Dickey Fuller test,
                        - 'dfgls' for Elliott, Rothenberg and Stock’s GLS version of the Dickey-Fuller test
                        - 'pp' for Phillips–Perron test
                        - 'kpss' for Kwiatkowski–Phillips–Schmidt–Shin test,

        :param threshold:   confidence level for p_value. The p-value is the probability score based on which you can
                            decide whether to reject the null hypothesis or not.
                            If the p-value is less than a predefined alpha level (typically 0.05), we reject the null hypothesis.
        :param **kwargs:    Any additional arguments for the test in question i.e.
        :return: True if p-value below threshold (for DF and ADF) or above threshold (for KPSS), otherwise False.
        """
        if re.search('adf', test, re.IGNORECASE):
            test_statistic, p_value, n_lags_used, _, critical_values, _ = adfuller(self.series, **kwargs)
            return p_value < threshold
        elif re.search('kpss', test, re.IGNORECASE):
            test_statistic, p_value, n_lags_used, critical_values = kpss(self.series, **kwargs)
            return p_value > threshold  # for KPSS, series is NOT stationary if < threshold
        elif re.search('pp', test, re.IGNORECASE):
            result = PhillipsPerron(self.series)
            test_statistic, p_value, n_lags_used, critical_values = result.stat, result.pvalue, result.lags, result.critical_values
            return p_value < threshold
        else:
            raise Exception("Invalid `test`")

    def stationarize_ts(self, transform_fun, test_tup, n_thresh=10):
        """
        Making a time series stationary means to not make it a function of time, that is its mean and variance
        do not change over time.
        :param transform_fun: function to apply to time series.
            -   For **differentiation**, use `np.diff`. Preferably use `lambda x: np.diff(x, prepend=x[0])`
                to avoid losing data, since diff removes first element when differentiating,
                and need to prepend each time the first value.
            - For **log**, use `np.log`. To use different log bases, so use `lambda x: math.log(x, base)`
            -
        :param test_tup: tuple representing stationarity test and threshold
        :param n_thresh: max number of times to apply function before stopping
        :return:
        """

        def recursive_handler(n, *args):
            stationary = self.test_stationarity(test=test_tup[0], threshold=test_tup[1])
            if stationary or n == n_thresh:
                return args[0], n
            return recursive_handler(n + 1, transform_fun(*args))

        fun_applied_series, n = recursive_handler(0, self.series)
        print(f'function was applied {n} times.')
        self.series = pd.Series(index=self.series.index, data=fun_applied_series)
        return self.series, n

    def decompose_ts(self):
        pass

    def detrend_ts(self, method):
        """
        Remove the trend component from a time series.

        :param method:
            - Subtract the mean
            - Subtract the line of best fit from the time series, obtained from a linear regression model with
            the time steps as the predictor. For more complex trends, you may want to use quadratic terms (x^2) in the model.
            - Subtract the trend component obtained from time series decomposition we saw earlier.
            - Apply a filter like Baxter-King filter(statsmodels.tsa.filters.bkfilter) or the
            Hodrick-Prescott Filter (statsmodels.tsa.filters.hpfilter) to remove the moving average trend lines or the cyclical components.
        :return:
        """
        pass

if __name__ == '__main__':
    # with open('temp_prices.pkl', 'wb') as handle:
    #     data = YahooFinance(ticker='AAPL', period='YTD').convert_format('pandas')['Close']
    #     print(data)
    #     pickle.dump(data, handle, protocol=pickle.HIGHEST_PROTOCOL)

    with open('temp_prices.pkl', 'rb') as handle:
        data = pickle.load(handle)
        ts = TimeSeriesAnalysis(series=data)
        # print(ts.test_stationarity(test='adf'))
        print(ts.stationarize_ts(transform_fun=lambda x: np.diff(x, prepend=x[0]), test_tup=('pp', 0.05)))


import numpy as np

def quantile(x, q, weights=None):
    """
    Compute sample quantiles with support for weighted samples.
    Note
    ----
    When ``weights`` is ``None``, this method simply calls numpy's percentile
    function with the values of ``q`` multiplied by 100.
    Parameters
    ----------
    x : array_like[nsamples,]
       The samples.
    q : array_like[nquantiles,]
       The list of quantiles to compute. These should all be in the range
       ``[0, 1]``.
    weights : Optional[array_like[nsamples,]]
        An optional weight corresponding to each sample. These
    Returns
    -------
    quantiles : array_like[nquantiles,]
        The sample quantiles computed at ``q``.
    Raises
    ------
    ValueError
        For invalid quantiles; ``q`` not in ``[0, 1]`` or dimension mismatch
        between ``x`` and ``weights``.
    """
    x = np.atleast_1d(x)
    q = np.atleast_1d(q)

    if np.any(q < 0.0) or np.any(q > 1.0):
        raise ValueError("Quantiles must be between 0 and 1")

    if weights is None:
        return np.percentile(x, list(100.0 * q))
    else:
        weights = np.atleast_1d(weights)
        if len(x) != len(weights):
            raise ValueError("Dimension mismatch: len(weights) != len(x)")
        idx = np.argsort(x)
        sw = weights[idx]
        cdf = np.cumsum(sw)[:-1]
        cdf /= cdf[-1]
        cdf = np.append(0, cdf)
        return np.interp(q, cdf, x[idx]).tolist()


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

class Riemann_Sum_Approximation():
    """
    This object approximates the area of a quarter circle by a finite (=n) sum.
    Furthermore, it provides a method to plot what is going on.

    """

    def __init__(self, n=100):

        self.n = n

    def approximate_pi(self):
        """
        Function to approximate the integral of a quarter of the unit circle.

        """
        # divide in n sectors
        d = 1/self.n

        # function to approximate pi by summing the areas of the bars
        pi_app = 4*d*sum(math.sqrt(1 - x**2) for x in np.linspace(0,1,self.n + 1))

        # calcute the error
        error = round(100*abs(pi_app - np.pi)/np.pi,6)

        return 'Approximation of pi: {}, error: {}%'.format(pi_app, error)

    def bar_plot(self):
        """
        Function to plot a quarter of the unit circle and the approximation
        with n intervals.

        """

        d = 1/self.n

        seq = np.linspace(0, 0.5*np.pi, 25)

        u = np.cos(seq)
        v = np.sin(seq)

        fig, ax = plt.subplots(1)

        # for loop to create the bar plots
        for x in np.linspace(0,1,self.n + 1):
            ax.bar(x, math.sqrt(1 - x**2),
                   width=d,
                   alpha=0.2,
                   align='edge',
                   edgecolor='b',
                   color='g')

        ax.plot(u, v)

        ax.set_aspect(1)

        plt.xlim(-0.25,1.25)
        plt.ylim(-0.25,1.25)

        plt.grid(linestyle='--')

        plt.title('plot unit circle for pi approximation', fontsize=8)

        plt.show()


import math

import numpy as np

def vector_length(vector):
    return np.linalg.norm(vector)

def vectors_angle(v1, v2):
    return math.acos(np.dot(v1, v2) / (np.linalg.norm(v1) * np.linalg.norm(v2)))

def vectors_differ(v1, v2):
    return len(v1) != len(v2) or any([v1[i] != v2[i] for i in range(len(v1))])

def radians_to_degrees(radians):
    return 180.0 / math.pi * radians

def normalize_vector(vector):
    length = vector_length(vector)
    return tuple(float(x) / length for x in vector)

def points_to_vector(p1, p2):
    return p1[0] - p2[0], p1[1] - p2[1]

def sum_vectors(v1, v2):
    return tuple(v1[i] + v2[i] for i in range(len(v1)))


import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
import sys

def main():

    N = 50000
    uniform = np.random.randint(0,2**30,size=N)

    #Uniform
    a = 0;
    b = 1000;
    uniform_translated = uniform/2**30*b + a
    plt.hist(uniform_translated, bins=30, color = 'green', density=True, edgecolor='black', alpha = 0.4)
    plt.xlabel('Value')
    plt.ylabel('PDF')
    plt.show()
    print(" Mean is %.2f = (b-a)/2" % np.mean(uniform_translated))
    print()

    #Normal
    mu = 100000
    sigma = 100
    normal_distribution = np.zeros(N)
    for i in range(N):
        nones = bin(uniform[i]).count("1")
        std_ones = np.sqrt(30/4)
        mean_ones = 15
        normal_distribution[i] = nones*sigma/std_ones - mean_ones*sigma/std_ones + mu

    plt.hist(normal_distribution, bins=21, color = 'orange', density=True, edgecolor='black', alpha = 0.4)
    plt.xlabel('Value')
    plt.ylabel('PDF')
    plt.show()
    print(" Mean is %.2f (mu)" % np.mean(normal_distribution))
    print(" std is %.2f (sigma)" % np.std(normal_distribution))
    print()

    #Exponential
    rate = 1e-4
    exp_distribution = (-np.log2(uniform)+30)/rate*np.log(2)
    plt.hist(exp_distribution, bins=30, color = 'red', density=True, edgecolor='black', alpha = 0.4)
    plt.xlabel('Value')
    plt.ylabel('PDF')
    plt.show()
    print(" Mean is %.2f (1/lambda)" % np.mean(exp_distribution))
    print()

    #Gamma
    k = 10
    gamma_distribution = np.zeros(N)
    for i in range(N):
        value = 0
        for ki in range(k):
            value += exp_distribution[np.random.randint(0,N)]
        gamma_distribution[i] = value
    plt.hist(gamma_distribution, bins=30, color = 'blue', density=True, edgecolor='black', alpha = 0.4)
    plt.xlabel('Value')
    plt.ylabel('PDF')
    plt.show()
    print(" Mean is %.2f (k/lambda)" % np.mean(gamma_distribution))
    print()

    #arbitrary(quantile), beta distribution as example
    """
    We can apply the the quantile function (inverse CDF) of a probability
    distribution to the uniformly distributed value in order to get a
    variable with the specified distribution.
    """

    Nprecision = 100
    prob = np.arange(1,Nprecision)/Nprecision
    quantiles = (stats.beta.ppf(prob,0.5,0.5)*1e5).astype(int) #generating quantile function for Beta distribution
    print(list(quantiles))

    uniform = np.random.randint(0,Nprecision-1,size=N)
    beta_distribution = np.zeros(N)
    for i in range(N):
        beta_distribution[i] = quantiles[uniform[i]]

    plt.hist(beta_distribution, bins=20, color = 'purple', density=True, edgecolor='black', alpha = 0.4)
    plt.xlabel('Value')
    plt.ylabel('PDF')
    plt.show()

if __name__ == '__main__':
    plt.rcParams.update({'font.size': 16})
    main()

Arbitrarily distributed on-chain random variables/Plot_distributions.py


import numpy as np
import random
import matplotlib.pyplot as plt
try:
    from scipy.special import comb
except:
    from scipy.misc import comb

def bernstein_poly(i, n, t):
    """
     The Bernstein polynomial of n, i as a function of t
    """
    return comb(n, i) * ( t**(n-i) ) * (1 - t)**i

def bezier_curve(points, nTimes=1000):
    """
       Given a set of control points, return the
       bezier curve defined by the control points.
       Control points should be a list of lists, or list of tuples
       such as [ [1,1],
                 [2,3],
                 [4,5], ..[Xn, Yn] ]
        nTimes is the number of time steps, defaults to 1000
        See http://processingjs.nihongoresources.com/bezierinfo/
    """

    nPoints = len(points)
    xPoints = np.array([p[0] for p in points])
    yPoints = np.array([p[1] for p in points])

    t = np.linspace(0.0, 1.0, nTimes)

    polynomial_array = np.array([bernstein_poly(i, nPoints-1, t) for i in range(0, nPoints)])

    xvals = np.dot(xPoints, polynomial_array)
    yvals = np.dot(yPoints, polynomial_array)

    return xvals, yvals

def nonlinear_transformation(x, prob=0.5):
    if random.random() >= prob:
        return x
    points = [[0, 0], [random.random(), random.random()], [random.random(), random.random()], [1, 1]]
    xvals, yvals = bezier_curve(points, nTimes=100000)
    if random.random() < 0.5:
        # Half change to get flip
        xvals = np.sort(xvals)
    else:
        xvals, yvals = np.sort(xvals), np.sort(yvals)
    nonlinear_x = np.interp(x, xvals, yvals)
    return nonlinear_x