## 2. Geometric Intuition Of Vectors ##

import matplotlib.pyplot as plt
import numpy as np

# This code draws the x and y axis as lines.
plt.quiver(0, 0, 2, 3, angles = 'xy', scale_units='xy', scale = 1, color = 'blue')
plt.quiver(0, 0, -2, -3, angles = 'xy', scale_units='xy', scale = 1, color = 'blue')

plt.quiver(0, 0,1, 1, angles = 'xy', scale_units='xy', scale = 1, color = 'gold')
plt.quiver(0, 0, 2, 2, angles = 'xy', scale_units='xy', scale = 1, color = 'gold')

plt.axhline(0, c='black', lw=0.5)
plt.axvline(0, c='black', lw=0.5)
plt.xlim(-3,3)
plt.ylim(-4,4)

## 3. Vector Operations ##

# This code draws the x and y axis as lines.

plt.axhline(0, c='black', lw=0.5)
plt.axvline(0, c='black', lw=0.5)
plt.xlim(-4,4)
plt.ylim(-1,4)
plt.quiver(0,0,3,0,angles='xy', scale_units = 'xy',scale=1)
plt.quiver(3,0,0,3,angles='xy', scale_units = 'xy',scale=1)
plt.quiver(0,0,3,3,angles='xy', scale_units = 'xy',scale=1, color='green')

## 4. Scaling Vectors ##

# This code draws the x and y axis as lines.

plt.axhline(0, c='black', lw=0.5)
plt.axvline(0, c='black', lw=0.5)
plt.xlim(0,10)
plt.ylim(0,5)
plt.quiver(0,0,3,1, angles = 'xy', scale_units='xy', scale=1, color='blue')
plt.quiver(0,0,6,2, angles = 'xy', scale_units='xy', scale=1, color='green')
plt.quiver(0,0,9,3, angles = 'xy', scale_units='xy', scale=1, color='orange')

## 5. Vectors In NumPy ##

import numpy as np

vector_one = np.asarray([
    [1],
    [2],
    [1]
], dtype=np.float32)

vector_two = np.asarray([
    [3],
    [0],
    [1]
], dtype=np.float32)

vector_linear_combination = vector_one * 2 + vector_two * 5
print(vector_linear_combination)

## 7. Linear Combination ##

v = np.asarray([
    [3],
    [1]
], dtype=np.float32)

w = np.asarray([
    [1],
    [2]
], dtype=np.float32)

end_point = 2*v - 2*w

6. Machine Learning Introduction/linear-algebra-for-machine-learning/Vectors-161.py


import numpy as np

def l2_regularization(W, reg_strength):
    '''
    Computes L2 regularization loss on weights and its gradient

    Arguments:
      W, np array - weights
      reg_strength - float value

    Returns:
      loss, single value - l2 regularization loss
      gradient, np.array same shape as W - gradient of weight by l2 loss
    '''
    # TODO: Copy from previous assignment
    loss = reg_strength * np.sum(W ** 2)
    grad = 2 * reg_strength * W

    return loss, grad

def softmax(predictions):
        predictions -= np.max(predictions)
        probs = np.exp(predictions) / np.sum(np.exp(predictions), axis=1, keepdims=True)

        return probs

def softmax_with_cross_entropy(predictions, target_index):
    '''
    Computes softmax and cross-entropy loss for model predictions,
    including the gradient

    Arguments:
      predictions, np array, shape is either (N) or (batch_size, N) -
        classifier output
      target_index: np array of int, shape is (1) or (batch_size) -
        index of the true class for given sample(s)

    Returns:
      loss, single value - cross-entropy loss
      dprediction, np array same shape as predictions - gradient of predictions by loss value
    '''
    # TODO copy from the previous assignment
    preds = predictions.copy()
    probs = softmax(preds)

    loss = - np.log(probs[np.arange(len(probs)), target_index])
    loss = loss.mean()
    mask = np.zeros_like(predictions)

    # mask and dprediction for (N) shape predictions
    if predictions.shape == (len(predictions), ):
        mask[target_index] = 1
        dprediction = - (mask - probs)

    # mask and dprediction for (batch_size, N) shape predictions
    else:
        mask[np.arange(len(mask)), target_index] = 1
        dprediction = - (mask - probs) / (len(mask))

    return loss, dprediction

class Param:
    '''
    Trainable parameter of the model
    Captures both parameter value and the gradient
    '''
    def __init__(self, value):
        self.value = value
        self.grad = np.zeros_like(value)

class ReLULayer:
    def __init__(self):
        pass

    def forward(self, X):
        # TODO: Implement forward pass
        # Hint: you'll need to save some information about X
        # to use it later in the backward pass
        self.X = X
        result = X.copy()
        result[result < 0] = 0

        return result

    def backward(self, d_out):
        """
        Backward pass

        Arguments:
        d_out, np array (batch_size, num_features) - gradient
           of loss function with respect to output

        Returns:
        d_result: np array (batch_size, num_features) - gradient
          with respect to input
        """
        # TODO: Implement backward pass
        # Your final implementation shouldn't have any loops
        d_result = (self.X > 0) * d_out

        return d_result

    def params(self):
        # ReLU Doesn't have any parameters
        return {}

class FullyConnectedLayer:
    def __init__(self, n_input, n_output):
        self.W = Param(0.001 * np.random.randn(n_input, n_output))
        self.B = Param(0.001 * np.random.randn(1, n_output))
        self.X = None

    def forward(self, X):
        # TODO: Implement forward pass
        # Your final implementation shouldn't have any loops
        self.X = X
        W = self.W.value
        B = self.B.value
        result = np.dot(X, W) + B

        return result

    def backward(self, d_out):
        """
        Backward pass
        Computes gradient with respect to input and
        accumulates gradients within self.W and self.B

        Arguments:
        d_out, np array (batch_size, n_output) - gradient
           of loss function with respect to output

        Returns:
        d_result: np array (batch_size, n_input) - gradient
          with respect to input
        """
        # TODO: Implement backward pass
        # Compute both gradient with respect to input
        # and gradients with respect to W and B
        # Add gradients of W and B to their `grad` attribute

        # It should be pretty similar to linear classifier from
        # the previous assignment
        X = self.X
        W = self.W.value

        d_W = np.dot(X.T, d_out)
        d_B = np.dot(np.ones((X.shape[0], 1)).T, d_out)
        d_X = np.dot(d_out, W.T)

        self.W.grad += d_W
        self.B.grad += d_B

        return d_X

    def params(self):
        return {'W': self.W, 'B': self.B}

class ConvolutionalLayer:
    def __init__(self, in_channels, out_channels,
                 filter_size, padding):
        '''
        Initializes the layer

        Arguments:
        in_channels, int - number of input channels
        out_channels, int - number of output channels
        filter_size, int - size of the conv filter
        padding, int - number of 'pixels' to pad on each side
        '''

        self.filter_size = filter_size
        self.in_channels = in_channels
        self.out_channels = out_channels
        self.W = Param(
            np.random.randn(filter_size, filter_size,
                            in_channels, out_channels)
        )

        self.B = Param(np.zeros(out_channels))

        self.padding = padding

    def forward(self, X):
        padding = self.padding
        if padding > 0:
            X = np.insert(X, 0, np.zeros([ padding]), axis=2)
            X = np.insert(X, X.shape[2], np.zeros([ padding]), axis=2)
            X = np.insert(X, 0, np.zeros([ padding]), axis=1)
            X = np.insert(X, X.shape[1], np.zeros([ padding]), axis=1)

        self.X = X
        filter_size = self.filter_size
        out_channels = self.out_channels
        batch_size, height, width, in_channels = X.shape

        # TODO: Implement forward pass
        # Hint: setup variables that hold the result
        # and one x/y location at a time in the loop below

        out_height = height - (filter_size - 1)
        out_width = width - (filter_size - 1)
        result = np.zeros((batch_size, out_height, out_width, out_channels))

        W_reshaped = self.W.value.reshape((-1, out_channels))
        B = self.B.value

        # It's ok to use loops for going over width and height
        # but try to avoid having any other loops
        for y in range(out_height):
            for x in range(out_width):
                # TODO: Implement forward pass for specific location
                X_after_kernel = X[:, y:y+filter_size, x:x+filter_size, :]
                X_after_kernel = X_after_kernel.reshape((batch_size, -1))
                out = np.dot(X_after_kernel, W_reshaped) + B
                #print(np.dot(X_after_kernel, W_reshaped))
                #print(B)
                #print(out, out.shape)
                result[:, y, x, :] = out

        return result

    def backward(self, d_out):
        # Hint: Forward pass was reduced to matrix multiply
        # You already know how to backprop through that
        # when you implemented FullyConnectedLayer
        # Just do it the same number of times and accumulate gradients
        X = self.X
        d_X = np.zeros_like(X)

        padding = self.padding
        filter_size = self.filter_size
        batch_size, height, width, in_channels = X.shape
        _, out_height, out_width, out_channels = d_out.shape

        # TODO: Implement backward pass
        # Same as forward, setup variables of the right shape that
        # aggregate input gradient and fill them for every location
        # of the output
        self.W.grad = np.zeros_like(self.W.value)
        self.B.grad = np.zeros_like(self.B.value)

        W_reshaped = self.W.value.reshape((-1, out_channels))
        ###d_B = np.sum(d_out, (0, 1, 2))
        ###self.B.grad += d_B

        # Try to avoid having any other loops here too
        for y in range(out_height):
            for x in range(out_width):
                # TODO: Implement backward pass for specific location
                # Aggregate gradients for both the input and
                # the parameters (W and B)
                point = d_out[:, y, x, :]

                X_after_kernel = X[:, y:y+filter_size, x:x+filter_size, :]
                X_after_kernel_reshaped = X_after_kernel.reshape((batch_size, -1))

                d_W = np.dot(X_after_kernel_reshaped.T, point)
                d_W = d_W.reshape((filter_size, filter_size, in_channels, out_channels))

                d_B = np.dot(np.ones((batch_size, )).T, point)

                d_X_before_kernel = np.dot(point, W_reshaped.T)
                d_X_before_kernel = d_X_before_kernel.reshape((batch_size, filter_size, filter_size, in_channels))

                self.W.grad += d_W
                self.B.grad += d_B
                d_X[:, y:y+filter_size, x:x+filter_size, :] += d_X_before_kernel

        d_X = d_X[:, padding:height-padding, padding:width-padding, :]
        return d_X

    def params(self):
        return { 'W': self.W, 'B': self.B }

class MaxPoolingLayer:
    def __init__(self, pool_size, stride):
        '''
        Initializes the max pool

        Arguments:
        pool_size, int - area to pool
        stride, int - step size between pooling windows
        '''
        self.pool_size = pool_size
        self.stride = stride
        self.X = None

    def forward(self, X):
        # TODO: Implement maxpool forward pass
        # Hint: Similarly to Conv layer, loop on output x/y dimension
        pool_size = self.pool_size
        stride = self.stride
        self.X = X
        batch_size, height, width, in_channels = X.shape

        out_height = int(np.floor((height - pool_size) / stride)) + 1
        out_width = int(np.floor((width - pool_size) / stride)) + 1
        result = np.zeros((batch_size, out_height, out_width, in_channels))

        for batch in range(batch_size):
            for y in range(out_height):
                for x in range(out_width):
                    for channel in range(in_channels):
                        y_source = y * stride
                        x_source = x * stride
                        pool = X[batch, y_source:y_source+pool_size, x_source:x_source+pool_size, channel]
                        maximum = np.max(pool)
                        result[batch, y, x, channel] = maximum

        return result

    def backward(self, d_out):
        # TODO: Implement maxpool backward pass
        pool_size = self.pool_size
        stride = self.stride
        X = self.X
        batch_size, height, width, in_channels = X.shape
        _, out_height, out_width, out_channels = d_out.shape

        d_X = np.zeros_like(X)

        for batch in range(batch_size):
            for y in range(out_height):
                for x in range(out_width):
                    for channel in range(in_channels):
                        mask = np.zeros((pool_size, pool_size))
                        y_source = y * stride
                        x_source = x * stride
                        pool = X[batch,
                                 y_source:np.minimum(y_source+pool_size, height),
                                 x_source:np.minimum(x_source+pool_size, width), channel]

                        maximum = np.max(pool)
                        max_count = np.count_nonzero(pool == maximum)
                        argmax = np.argwhere(pool==maximum)
                        mask[argmax[:,0], argmax[:,1]] = d_out[batch, y, x, channel] / max_count

                        d_X[batch, y_source:y_source+pool_size, x_source:x_source+pool_size, channel] += mask

        return d_X

    def params(self):
        return {}

class Flattener:
    def __init__(self):
        self.X_shape = None

    def forward(self, X):
        self.X = X
        batch_size, height, width, channels = X.shape

        # TODO: Implement forward pass
        # Layer should return array with dimensions
        # [batch_size, hight*width*channels]
        return X.reshape((batch_size, -1))

    def backward(self, d_out):
        # TODO: Implement backward pass
        batch_size, height, width, channels = self.X.shape

        return d_out.reshape((batch_size, height, width, channels))

    def params(self):
        # No params!
        return {}


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

def coupled_logarithm(value: [int, float, np.ndarray],
                      kappa: [int, float] = 0.0,
                      dim: int = 1
                      ) -> [float, np.ndarray]:
    """
    Generalization of the logarithm function, which defines smooth
    transition to power functions.

    Parameters
    ----------
    value : Input variable in which the coupled logarithm is applied to.
            Accepts int, float, and np.ndarray data types.
    kappa : Coupling parameter which modifies the coupled logarithm function.
            Accepts int and float data types.
    dim : The dimension (or rank) of value. If value is scalar, then dim = 1.
          Accepts only int data type.
    """
    # convert value into np.ndarray (if scalar) to keep consistency
    value = np.array(value) if isinstance(value, (int, float)) else value
    assert isinstance(value, np.ndarray), "value must be an int, float, or np.ndarray."
    assert 0. not in value, "value must not be or contain np.ndarray zero(s)."
    if kappa == 0.:
        coupled_log_value = np.log(value)  # divide by 0 if x == 0
    else:
        coupled_log_value = (1. / kappa) * (value**(kappa / (1. + dim*kappa)) - 1.)
    return coupled_log_value

def coupled_exponential(value: [int, float, np.ndarray],
                        kappa: float = 0.0,
                        dim: int = 1
                        ) -> [float, np.ndarray]:
    """
    Generalization of the exponential function.

    Parameters
    ----------
    value : [float, np.ndarray]
        Input values in which the coupled exponential is applied to.
    kappa : float,
        Coupling parameter which modifies the coupled exponential function.
        The default is 0.0.
    dim : int, optional
        The dimension of x, or rank if x is a tensor. The default is 1.

    Returns
    -------
    float
        The coupled exponential values.

    """
    # convert number into np.ndarray to keep consistency
    value = np.array(value) if isinstance(value, (int, float)) else value
    assert isinstance(value, np.ndarray), "value must be an int, float, or np.ndarray."
    # assert 0 not in value, "value must not be or contain np.ndarray zero(s)."
    assert isinstance(dim, int) and dim >= 0, "dim must be an integer greater than or equal to 0."
    # check that -1/d <= kappa
    assert -1/dim <= kappa, "kappa must be greater than or equal to -1/dim."

    if kappa == 0:
        coupled_exp_value = np.exp(value)
    elif kappa > 0: # KPN 4/13/21 adding logic for 1 + kappa*value <=0
        if (1 + kappa*value) > 0:
            return (1 + kappa*value)**((1 + dim*kappa)/kappa)
        else: # KPN 4/13/21 since kappa > 0 (1+dim*kappa)/kappa > 0
            return 0.

    # the following is given that kappa < 0
    else:
        def _compact_support(value, kappa, dim):
            if (1 + kappa*value) > 0:  # KPN 4/13/21 removed equal sign; if = 0, then result is either 0 or inf
                try:
                    return (1 + kappa*value)**((1 + dim*kappa)/kappa)
                except ZeroDivisionError: # KPN 4/13/21 ZeroDivisionError may no longer be necessary
                    print("Skipped ZeroDivisionError at the following: " + \
                          f"value = {value}, kappa = {kappa}. Therefore," + \
                          f"(1+kappa*value) = {(1+kappa*value)}"
                          )
            elif ((1 + dim*kappa)/kappa) > 0:
                return 0.
            else:
                return float('inf')
        compact_support = np.vectorize(_compact_support)
        coupled_exp_value = compact_support(value, kappa, dim)

    return coupled_exp_value


from numpy import abs as npabs, sqrt, exp, pi

def norm_pdf(x, mu, sigma):
    """
    Normal distribution Probability
    Density Function.

    PDF across `x` for a normal
    distribution with mean `mu` and
    standard deviation `sigma`.

    >>> norm_pdf(0, 0.0, 1.0)
    0.3989422804014327
    >>> norm_pdf(-0.1, 0.0, 1.0)
    0.39695254747701181
    >>> norm_pdf(0.1, 0.0, 1.0)
    0.39695254747701181
    >>> norm_pdf(7, 5, 5) # doctest: +ELLIPSIS
    0.073654028060664...
    """
    a = npabs(sigma)
    u = (x - mu) / a
    v = sqrt(2 * pi) * a
    y = (1 / v) * exp(-u * u / 2)
    return y

if __name__ == '__main__':
    import pytest
    pytest.main([__file__])


## Energy Balance Model with forward Euler, modified Euler

import numpy as np
import matplotlib.pyplot as plt

## constants

global h,rho,C,a,S,e,s

h = 8.3e3 #height of troposphere
rho = 1.2 #density
C = 1e3 #specific heat capacity
a = 0.3 #albedo
S = 1367. #solar constant
e = 1 #emissivity
s = 5.67e-8 #stefan-boltzmann constant

## solve EBM numerically

def rhs(T):
    return ((1-a)*S/4. - e*s*T**4)/h/rho/C

def ebm(t):
    dt = t[1] - t[0]
    # preallocate 1: forw Euler, 2: mod. Euler
    T1,T2 = np.zeros_like(t),np.zeros_like(t)
    T1[0],T2[0] = 288,288 #initial condition

    for i in range(len(t)-1):
        #forward euler
        T1[i+1] = T1[i] + dt*rhs(T1[i])

        #modified euler
        T2[i+1] = T2[i] + dt*rhs(T2[i])
        T2[i+1] = T2[i] + .5*dt*(rhs(T2[i]) + rhs(T2[i+1]))

    #convert to celsius
    return T1-273.15,T2-273.15

#time stepping
td = np.linspace(0,200,30) #in days
t = td*3600*24 #in seconds (for solving the ODE)

T1,T2 = ebm(t)

e = .6 #change emissivity
T1e,T2e = ebm(t)

a = 0.26 #change albedo
T1a,T2a = ebm(t)

## plotting

plt.plot(td,T1,'gs-',label=r'forw Euler, $\epsilon = 1$, $\alpha = .3$')
plt.plot(td,T2,'g^-',label=r'mod Euler, $\epsilon = 1$, $\alpha = .3$')
plt.plot(td,T1e,'bs-',label=r'forw Euler, $\epsilon = .6$, $\alpha = .3$')
plt.plot(td,T2e,'b^-',label=r'mod Euler, $\epsilon = .6$, $\alpha = .3$')
plt.plot(td,T1a,'ks-',label=r'forw Euler, $\epsilon = .6$, $\alpha = .26$')
plt.plot(td,T2a,'k^-',label=r'mod Euler, $\epsilon = .6$, $\alpha = .26$')
plt.xlabel('time [days]')
plt.ylabel(r'temperature [$\degree{}$C]')
plt.legend(loc='center right')

plt.tight_layout()
plt.show()


#### Logistic regression optimized by BFGS algorithm

### author: Dr. Marko Mitic
### year: 2015
### contact: miticm@gmail.com

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

class LinearREG:

    def __init__(self, data):
        self.x=data[:,0:-1]
        self.y=data[:,-1]
        self.m=len(data)

    def plotdata(self):
        plot1=self.x[np.where(self.y==1)]
        plot2=self.x[np.where(self.y==0)]
        ###
        plt.figure()
        plt.plot(plot1[:,0], plot1[:,-1],'bo', label='Admitted')
        plt.plot(plot2[:,0], plot2[:,-1],'ro', label='Not admitted')
        #plt.legend()
        plt.show()

    def addones(self):
        X=np.append(np.ones([self.m,1]),self.x,1)
        return X

    def sigmoid(self,z):

        return 1./(1+np.exp(-z))

    def costandgradient(self, theta, x, y):

        z=np.dot(x,theta)
        hypothesis=self.sigmoid(z)

        ##compute cost
        firstterm=np.dot(y,np.log(hypothesis))
        secondterm=np.dot((1-y), np.log(1-hypothesis))

        J=(-1./self.m)*(firstterm+secondterm)

        ##compute gradient
        grad0=(1./self.m)*np.dot((hypothesis-y),x[:,0])
        gradrest=(1./self.m)*np.dot((hypothesis-y),x[:,1:np.shape(x)[1]])

        grad=np.append(grad0, gradrest)

        return [J, grad]

    def predict(self,theta,x):

        z=np.dot(x,theta)
        hypothesis=self.sigmoid(z)

        p=np.zeros(len(z))

        for i in range(0,len(z)):

            if hypothesis[i]>0.5:
                p[i]=1
            else:
                p[i]=0

        return p

    def plotresult(self,theta,x):

        plot1=self.x[np.where(self.y==1)]
        plot2=self.x[np.where(self.y==0)]

        plotx=[min(x[:,1]), max(x[:,1])]
        ploty=[-1./theta[2]]*(np.dot(plotx,theta[1])+theta[0])
        ###
        plt.figure()
        plt.plot(plot1[:,0], plot1[:,-1],'bo', label='Admitted')
        plt.plot(plot2[:,0], plot2[:,-1],'ro', label='Not admitted')

        plt.plot(plotx,ploty)
        plt.title('Model found by Logistic Regression')
        plt.show()

################################################################################
def runLR():
    data = np.loadtxt("data_LogisticR.txt", comments="#", delimiter=",", unpack=False)

    lr=LinearREG(data)
    lr.plotdata()

    X=lr.x
    X=lr.addones()
    y=lr.y

    initial_theta=np.zeros(X.shape[1])
    [J, grad]=lr.costandgradient(initial_theta, X, y)

    opt_solution = optimize.minimize(lr.costandgradient, initial_theta, args = (X,y), method = 'L-BFGS-B', jac = True, options = {'maxiter': 500})

    theta=opt_solution.x

    p=lr.predict(theta,X)

    accuracy=(np.mean(p==y))*100

    lr.plotresult(theta,X)

    return theta, accuracy

[theta, accuracy]=runLR()

print 'Optimal parameters found by BFGS are', theta
print 'Learning accuracy is', accuracy


import numpy as np
from bayesnet.tensor.constant import Constant
from bayesnet.tensor.tensor import Tensor
from bayesnet.function import Function

class Log(Function):
    """
    element-wise natural logarithm of the input
    y = log(x)
    """

    def forward(self, x):
        x = self._convert2tensor(x)
        self.x = x
        output = np.log(self.x.value)
        if isinstance(self.x, Constant):
            return Constant(output)
        return Tensor(output, function=self)

    def backward(self, delta):
        dx = delta / self.x.value
        self.x.backward(dx)

def log(x):
    """
    element-wise natural logarithm of the input
    y = log(x)
    """
    return Log().forward(x)


#Implementation of Bayesian polynomial regression using pymc3
from pymc3 import *
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import PolynomialFeatures
import pandas as pd
import theano
from scipy.stats.kde import gaussian_kde

# set sample size
NUM_SAMPLES = 200
# set desired standard error
SDEV = 0.3
# set random seed
np.random.seed(42)

# set true function
def f(x):
    return 7 *(x**3 -1.3 *x**2+0.5*x - 0.056)

# evenly spaced grid of points in unit interval
gridx = np.linspace(0,1, 200)
# sample from unit interval
x = np.random.random(NUM_SAMPLES)
# perturb values
y = f(x) + SDEV*np.random.randn(NUM_SAMPLES)

# construct polynomial features on the samples and the grid
poly = PolynomialFeatures(degree = 3)
xpow = poly.fit_transform(x.reshape(NUM_SAMPLES,1))
linpow = poly.fit_transform(gridx.reshape(200,1))

# Create dictionary of theano variables
data = dict(x1=theano.shared(xpow[:,1]), x2 = theano.shared(xpow[:,2]), x3 = theano.shared(xpow[:,3]), y=theano.shared(y))

# plot our true curve
fig = plt.figure()
ax = fig.add_subplot(111, title = 'Bayesian approach to polynomial regression')
ax.scatter(x,y, label = 'Sampled data')
ax.plot(gridx, f(gridx), label = 'True curve', linewidth = 4 )

# this is needed to work in pymc3 context
with Model() as model:
    # Build the pymc3 model
    coeff = Normal('coeff', mu = 0, sd = 10, shape = 4)
    sigma = HalfNormal('sigma', sd = 1)
    mu = np.sum([coeff[i]*data['x'+str(i)] for i in range(1,4)])+coeff[0]
    y_obs = Normal('y_obs', mu = mu, sd = sigma, observed = data['y'])

    # Calculate the posterior probability via MCMC integration
    trace = sample(3500, njobs = 4)

    # print summary of training in html format
    print(stats.df_summary(trace).to_html())

    # Get the mean coefficients
    mcoeff = np.mean(trace['coeff'], axis = 0)
    # define the predicted function using the mean polynomial
    def g(x):
        return np.sum([mcoeff[i]*x**i for i in range(4)], axis =0)

    # plot the mean polynomial
    ax.plot(gridx, g(gridx), label = 'Bayesian mean polynomial fit', color = 'Black', alpha = 0.5, lw = 2.5)

    # take the last 50 samples of the parameters and graph their associated polynomials
    for i in range(50):
        def h(x):
            return np.sum([trace['coeff'][-i][j]*x**j for j in range(4)], axis =0)
        ax.plot(gridx, h(gridx), color = 'Black', alpha = 0.1)

    # Calculate posterior values
    data['x1'].set_value(linpow[:,1])
    data['x2'].set_value(linpow[:,2])
    data['x3'].set_value(linpow[:,3])
    data['y'].set_value(np.zeros_like(linpow[:1,1]))
    post_pred = sample_ppc(trace, samples = 200)

    # plot the mean prediction plus +- one standard deviation
    ax.plot(gridx, np.mean(post_pred['y_obs'], axis = 0), label = 'Bayesian mean posterior', alpha = 0.5, color = 'Red')
    ax.fill_between(gridx, np.mean(post_pred['y_obs'], axis = 0)-np.std(post_pred['y_obs'], axis = 0), np.mean(post_pred['y_obs'], axis = 0)+np.std(post_pred['y_obs'], axis = 0), label = 'Bayesian error band', alpha = 0.1, color = 'Red')
    plt.legend(loc = 2)
    plt.savefig("bayreg.png")
    plt.show()
    plt.clf()
    plt.close()

    # plot the pdfs of the coefficients
    plt.figure(figsize = (10, 5))
    fig, axs = plt.subplots(5)
    for i in range(4):
        tdata = trace['coeff'][:,i]
        kde = gaussian_kde(tdata)
        tgridx = np.linspace(min(tdata), max(tdata), 200)
        axs[i].plot(tgridx, kde(tgridx))
        axs[i].set_title('Coeff{}'.format(i))

    tdata = trace['sigma']
    kde = gaussian_kde(tdata)
    tgridx = np.linspace(min(tdata), max(tdata), 200)
    axs[4].plot(tgridx, kde(tgridx))
    axs[4].set_title('Sigma')
    plt.tight_layout()
    plt.savefig("trace.png")
    plt.show()

import numpy,from scipy,import theano,from pymc3


#!/usr/bin/env python3
"""
GRADIENT DESCENT ALGORITHM

Gradient Descent Algorithm is a method to find the minimum value of a function,
and it is widely adopted in machine learning, especially deep learning. To make
an algorithm actually "learn" after processing data, a concept of minimizing
cost, or loss, is introduced. After a training procedure, the algorithm outputs a value or an array of values. Then it compares the predicted values to the
actual values, and the difference between each predicted and correct value is
called "cost" (Some call it "loss", but we will use "cost" in the text below).

Since we are doing a lot of trainings, the cost becomes a function, and it
reaches its minimum if predicted values and correct values are the same. Some
believe that modifying the predicted values to the correct values can achieve
this goal, but this eventually leads to "memorizing" the answers. Instead we
modify the parameters of the algorithm (e.g. weights and biases in deep learningalgorithms) by using gradient descent. It is like let a ball roll in the curve
of a function.

In this program, we are going to use gradient descent to fit a linear function
(y=kx+b where k!=0).
"""
import numpy as np
from matplotlib import pyplot as plt
import os
import sys

# y=3x+2 is used to create correct y values with respect to x values
def f(x):
    return 3*x+2

k=np.random.random()*20.0 - 10.0    # Generate random numbers between [-10,10]
b=np.random.random()*20.0 - 10.0

def f_learn(x):
    return k*x+b

def calculate_cost(y,yp):
    return (yp-y)**2

def cost_prime(y,yp):
    return 2*(yp-y)

def gradient_descent(dc_dk,dc_db,step=0.0001):
    global k,b
    k-=dc_dk*step
    b-=dc_db*step

# The training set
x_train=np.linspace(0,100,101000)
y_train=f(x_train)+np.random.random()-0.5

# The testing set
x_test=np.linspace(-20,20,100)
y_test=f(x_test)

epochs=100  # Number of iterations
batch_size=1     # Batch size (self-explanatory)

if len(sys.argv)>=2:
    batch_size=int(sys.argv[1])

if batch_size==1:
    print("Using Stochastic GD")
elif batch_size==len(x_train):
    print("Using Batch GD")
else:
    print("Using Mini-batch GD, batch_size=%d" % batch)

if os.path.exists("./logs/")==False:
    os.mkdir("logs")

print("Before learning: k=%f, b=%f" % (k,b))

costs=[]

for epoch_no in range(epochs):
    n=0
    log_file=open("logs/epoch_"+str(epoch_no+1)+".log","w")
    total_cost=0
    gk=0.0
    gb=0.0
    try:
        for x,y in zip(x_train,y_train):
            yp=f_learn(x)
            n+=1
            total_cost+=calculate_cost(y,yp)
            cost=total_cost/n
            log_file.write("%d: k=%f, b=%f, y=%f, yp=%f, cost=%f\n"
                    % (n,k,b,y,yp,cost))
            # This part calculates gradients
            dc_dyp=cost_prime(y,yp)
            dyp_db=1
            dyp_dk=x
            dc_dk=dc_dyp * dyp_dk   # Chain Rule
            dc_db=dc_dyp * dyp_db
            gk+=dc_dk
            gb+=dc_db
            if (n % batch_size)==0:
                gradient_descent(gk/batch_size,gb/batch_size)
                gk=0.0
                gb=0.0
        log_file.close()
        avg_cost=total_cost/n
        costs.append(avg_cost)
        #print("Epoch #%d completes, k=%f, b=%f, cost=%f" %
        #        (epoch_no+1,k,b,avg_cost))
    except KeyboardInterrupt:
        print("Epoch #%d interrupted cost=%f, terminate training"
                % (epoch_no+1,total_cost/n))
        break

print("Learned k=%f, b=%f" % (k,b))

plt.subplot(121)
plt.plot(range(1,len(costs)+1),costs)
plt.xlabel("Epoch")
plt.ylabel("Cost")
plt.subplot(122)
plt.plot(x_test,f_learn(x_test),"g-", \
    label="Linear Regression: $y_{learn}=%fx+%f" % (k,b))
plt.plot(x_test,f(y_test),label="To be learnt: $y=3x+2$")
plt.legend()
plt.show()

# Start testing...
y_predict=f_learn(x_test)
total_cost=0.0
for y,yp in zip(y_test,y_predict):
    total_cost+=calculate_cost(y,yp)

cost=total_cost / len(x_test)

print("Test result: cost=%f" % cost)


import math
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt

x_operator = np.array([[1, 2, 1], [0, 0, 0], [-1, -2, -1]])
y_operator = np.array([[1, 0, -1], [2, 0, -2], [1, 0, -1]])

def rgb2gray(rgb):
	r, g, b = rgb[:,:,0], rgb[:,:,1], rgb[:,:,2]
	gray = 0.2989 * r + 0.5870 * g + 0.1140 * b

	return gray

img = Image.open("../img/skyline.jpg")
img = np.array(img)
img = img / 255 # normalise image
gray_img = rgb2gray(img)

G_x = []
G_y = []

for i in range(0, len(gray_img), len(x_operator)):
	for j in range(0, len(gray_img), len(x_operator)):
		receptive_field = gray_img[i:i+len(x_operator), j:j+len(x_operator)]
		template = np.zeros(x_operator.shape)
		template[:receptive_field.shape[0],:receptive_field.shape[1]] = receptive_field

		x_result = np.sum(np.dot(x_operator, template))
		y_result = np.sum(np.dot(y_operator, template))

		G_x.append(x_result)
		G_y.append(y_result)

G_x = np.array(G_x)
G_y = np.array(G_y)

G = np.sqrt(np.square(G_x) + np.square(G_y))
print (G.shape)
G = G.reshape([int(math.sqrt(len(G))), int(math.sqrt(len(G)))])

plt.figure(1)
plt.subplot(131)
plt.imshow(img, cmap="gray")
plt.axis("off")

plt.subplot(132)
plt.imshow(gray_img, cmap="gray")
plt.axis("off")

plt.subplot(133)
plt.imshow(G, cmap="gray")
plt.axis("off")
plt.show()


import numpy as np
import logging
logging.basicConfig(level=logging.INFO, format="%(funcName)s\t%(message)s")

def euclidean_distance(vec_a, vec_b):
    squares = np.power(vec_a - vec_b, 2)
    sum_of_squares = squares.sum(axis=-1)
    return np.sqrt(sum_of_squares)[0, 0]

def random_centroid(dataset, k):
    n = np.shape(dataset)[1]
    centroids = np.mat(np.zeros((k, n)))
    for j in range(n):
        min_j = min(dataset[:, j])
        range_j = float(max(dataset[:, j]) - min_j)
        centroids[:, j] = min_j + range_j * np.random.rand(k, 1)
    return centroids

def k_means(dataset,
            k,
            distance_measure=euclidean_distance,
            create_centroids=random_centroid):
    """
    Create k centroids, then assign each point to the closest
    centroid. Then re-calculate the centroids. Repeat until the
    points stop changing clusters.
    """
    m = np.shape(dataset)[0]
    cluster_assessment = np.mat(np.zeros((m, 2)))
    centroids = create_centroids(dataset, k)
    cluster_changed = True
    while cluster_changed:
        cluster_changed = False
        for i in range(m):
            min_distance = np.inf
            min_index = -1
            for j in range(k):
                dist_j_i = distance_measure(centroids[j, :], dataset[i, :])
                if dist_j_i < min_distance:
                    min_distance = dist_j_i
                    min_index = j
            if cluster_assessment[i, 0] != min_index:
                cluster_changed = True
            cluster_assessment[i, :] = min_index, min_distance ** 2
        logging.info("centroids: {}".format(centroids))
        for cent in range(k):
            points_in_cluster = dataset[np.nonzero(cluster_assessment[:, 0].
                                                   A == cent)[0]]
            centroids[cent, :] = np.mean(points_in_cluster, axis=0)
    return centroids, cluster_assessment

def bisect_k_means(dataset, k, distance_measure=euclidean_distance):
    """
    Choose the cluster with the largest SSE and split it.
    Then repeat until you get the k number of clusters.
    For every cluster, you measure the total error, perform
    k-means with k=2, measure the error after k-means has split
    the cluster in two, choose to keep the cluster split that gives
    the lowest error
    """
    m = np.shape(dataset)[0]
    cluster_assessment = np.mat(np.zeros((m, 2)))
    centroid_0 = np.mean(dataset, axis=0).tolist()[0]
    centroid_list = [centroid_0]

    # set the original error
    for j in range(m):
        cluster_assessment[j, 1] = distance_measure(np.mat(centroid_0),
                                                    dataset[j, :]) ** 2

    while (len(centroid_list) < k):
        lowest_sse = np.inf
        for i in range(len(centroid_list)):
            points_in_current_cluster =\
                dataset[np.nonzero(cluster_assessment[:, 0].A == i)[0], :]
            centroid_matrix, split_cluster_assessment =\
                k_means(points_in_current_cluster, 2, distance_measure)

            # compare the SSE to the current minimum
            sse_split = sum(split_cluster_assessment[:, 1])
            nosplit_index = np.nonzero(cluster_assessment[:, 0].A != i)
            sse_not_split =\
                sum(cluster_assessment[nosplit_index[0], 1])

            logging.info("sse split:\n{split}".format(split=sse_split))
            logging.info("sse NOT split:\n{not_split}".
                         format(not_split=sse_not_split))

            if (sse_split + sse_not_split) < lowest_sse:
                best_centroid_to_split = i
                best_new_centroids = centroid_matrix
                best_cluster_assessmnt = split_cluster_assessment.copy()
                lowest_sse = sse_split + sse_not_split

        best_cluster_index = np.nonzero(best_cluster_assessmnt[:, 0].A == 1)[0]
        best_cluster_assessmnt[best_cluster_index, 0] = len(centroid_list)

        best_cluster_index = np.nonzero(best_cluster_assessmnt[:, 0].A == 0)[0]
        best_cluster_assessmnt[best_cluster_index, 0] = best_centroid_to_split

        logging.info("the best centroid on which to split = {best}".
                     format(best=best_centroid_to_split))
        logging.info("the length of best_cluster_assessmnt = {cluster_len}".
                     format(cluster_len=len(best_cluster_assessmnt)))

        centroid_list[best_centroid_to_split] =\
            best_new_centroids[0, :].tolist()[0]
        centroid_list.append(best_new_centroids[1, :])

        asssigning_cluster_index =\
            np.nonzero(cluster_assessment[:, 0].A == best_centroid_to_split)[0]
        cluster_assessment[asssigning_cluster_index, :] =\
            best_cluster_assessmnt

    return np.mat(centroid_list), cluster_assessment


from statistics import mean
import numpy as np
import matplotlib.pyplot as plt

xs = np.array([1,2,3,4,5,6])
ys = np.array([5,4,6,5,6,7])

def best_fit_slope_and_intercept (xs,ys):
	m = ( (mean(xs) * mean(ys)) - mean(xs*ys) )  / ( mean(xs)*mean(xs) - mean(xs*xs) )

	b = mean(ys) - m*mean(xs)

	return m, b

def squared_error(ys_original, ys_line):
	return sum ((ys_line-ys_original)**2)

def coef_determination(ys_original, ys_line):
	y_mean_line = [mean(ys_original) for y in ys_original]
	squared_error_regr = squared_error(ys_original, ys_line)
	squared_error_y_mean = squared_error(ys_original, y_mean_line)
	return 1 - (squared_error_regr/squared_error_y_mean)

m, b = best_fit_slope_and_intercept(xs,ys)

regression_line = [(m*x)+b for x in xs]

print (m,b)

predict_x = 8
predict_y = (m*predict_x)+b

rsquared = coef_determination(ys, regression_line)
print (rsquared)

plt.scatter(xs,ys)
plt.plot(xs,regression_line)
plt.show()


import numpy as np

def create_random_distance_matrix(N):
    nodes_list = []
    for i in range(N):
        nodes_list.append(np.random.rand(2) * 10)
    nodes_array = np.array(nodes_list)
    number_of_nodes = len(nodes_array)
    matrix = np.zeros((number_of_nodes, number_of_nodes))
    for i in range(number_of_nodes):
        for j in range(i, number_of_nodes):
            matrix[i][j] = distance_between_points(nodes_array[i], nodes_array[j])
            matrix[j][i] = matrix[i][j]
    return matrix

def distance_between_points(point_A, point_B):
    return np.sqrt((point_A[0] - point_B[0])**2 + (point_A[1] - point_B[1])**2)


# Copyright 2018 - Jonathan Alcantara e Osmar Fernandes

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import numpy as np

tolerance = 0.00000001
iterations_limit = 7

def broyden(x0_vector, initial_approx_Jacobian, f_vector):

    x_vector = x0_vector
    approx_Jacobian = initial_approx_Jacobian
    for iteration in range(iterations_limit):

        jacobian_current_values = approx_Jacobian
        function_current_values = f_vector(x_vector)

        delta_x = -1*(np.matmul(np.linalg.inv(jacobian_current_values),
                                function_current_values))

        x_vector = x_vector + delta_x
        delta_f = f_vector(x_vector) - function_current_values

        if(np.linalg.norm(delta_x)/np.linalg.norm(x_vector) \
            < tolerance):
            return x_vector
        else:
            jacob_correction = ((delta_f - approx_Jacobian
                                        @ delta_x) @ np.transpose(delta_x))\
                               /(np.transpose(delta_x) @ delta_x)
            approx_Jacobian = approx_Jacobian + jacob_correction

    return "Convergence not reached: \n" + str(x_vector)

def f_vector(x_vector):
    return np.array([[x_vector[0][0] + 2*x_vector[1][0] - 2.0],
            [pow(x_vector[0][0], 2) + 4*pow(x_vector[1][0], 2) - 4]])

print(broyden(np.array([[2], [3]]), np.array([[1, 2], [4, 24]]), f_vector))


import numpy as np
from numpy.linalg import svd, norm
from numpy.random import randn
from derivativetest import derivativetest

def fraction(x, HProp = None, arg = None, a=100, b=1):
    """
    Fraction problems:
        F(x, y): a*x^2/(b - y)
    INPUT:
        x: variable
        HProp:
            If arg == 'Hv': porposion of Hessian perturbation
            If arg == None: ||E|| = HProp*smallest_singular_value_of_H
        arg: output control
    OUTPUT:
        f, gradient, Hessian/perturbed Hessian
    """
    x1 = x[0]
    x2 = x[1]
    H1 = a/(x2 - b) # a/(x2-b)
    f = -H1*x1**2
    H2 = H1/(x2 - b) # a/(x2-b)^2
    H3 = H2/(x2 - b) # a/(x2-b)^3

    g1 = -2*x1*H1
    g2 = H2*x1**2
    g = np.append(g1,g2,axis=0).reshape(2,1)

    if arg == 'f':
        return f

    if arg == 'g':
        return g
    if arg == 'fg':
        return f, g

    if arg == 'Hv':
        Hv = lambda v: Hessvec(H1, H2, H3, x1, x2, v)
        if HProp != None:
            Hv2 = lambda v: Hessvec(H1, H2, H3, x1, x2, v) + HProp*v
            return f, g, Hv2, Hv
        else:
            return f, g, Hv

    if arg is None:
        H23 = 2*x1*H2
        H_top = np.append(-2*H1, H23)
        H_bot = np.append(H23, -2*x1**2*H3)
        H = np.c_[H_top, H_bot]
        if HProp == None:
            return f, g, H
        else:
            s = svd(H)[1]
#            print('H', H)
            # Stability Analysis of Newton-MR Under Hessian Perturbations
            # Condition 1, \epsilon < \gamma/4 (2\nu -1)
            eps = 1E-12 # ignore small epsilon
            sigma = s[s>eps]
            if len(sigma) == 0:
                raise ValueError('0 rank Hessian!')
            epsilon = min(sigma)
#            EE = np.eye(2)*epsilon*HProp # \vnorm{\EE} = \epsllon*HProp
#            print('EE', svd(EE)[1], EE)
            W = np.random.randn(2,2)
            W = W + W.T
            U, s2, V = svd(W)
            s3 = s2/max(s2)*epsilon*HProp # \vnorm{\EE} = \epsllon*HProp
            E = U.dot(np.diag(s3).dot(U.T))
            return f, g, H+E

def Hessvec(H1, H2, H3, x1, x2, v):
    v1 = v[0]
    v2 = v[1]
    H23 = 2*x1*H2
    Hv1 = -2*H1*v1 + H23*v2
    Hv2 = H23*v1 - 2*x1**2*H3*v2
    Hv = np.append(Hv1,Hv2,axis=0).reshape(2,1)
    return Hv

def main():
    obj = lambda w: fraction(w,a=2,b=1)
    x0 = randn(2,1)
    derivativetest(obj, x0)

if __name__ == '__main__':
    main()


# Minimize x1*x4( x1 + x2 + x3 ) + x3
# s.t.
# x1 * x2 * x3 * x4 >= 25
# x1**2 + x2**2 + x3**2 + x4**2 = 40
# 1 <= x1, x2, x3, x4 <= 5
# x0 = ( 1, 5, 5, 1 )

import numpy as np
from scipy.optimize import minimize

def objective( x ):
	x1 = x[ 0 ]
	x2 = x[ 1 ]
	x3 = x[ 2 ]
	x4 = x[ 3 ]

	return x1 * x4 *( x1 + x2 + x3 ) + x3

def constraint1( x ):
	return x[ 0 ] * x[ 1 ] * x[ 2 ] * x[ 3 ] - 25.0

def constraint2( x ):
	sum_sq = 40
	for i in range( 4 ):
		sum_sq = sum_sq - x[ i ] ** 2
	return sum_sq

x0 = [ 1, 5, 5, 1 ]
print( objective( x0 ) )

b = ( 1.0, 10.0 )

bnds = ( b, b, b, b )
con1 = { 'type' : 'ineq', 'fun': constraint1 }
con2 = { 'type' : 'eq', 'fun': constraint2 }

cons = [ con1, con2 ]

sol = minimize( objective, x0, method='SLSQP', \
	bounds=bnds, constraints=cons )

print( sol.fun )


import numpy as np

def set_sieve(n):
    """
    Sets are mutable, unordered collections which are useful
    for quick membership testing and math operations.
    """
    primes = set(range(2, n+1))
    for i in range(2, int(n**0.5)+1):
        if i in primes:
            primes -= set(range(i*i, n+1, i))
    return primes

def sieve(n):
    """Sieve away and only primes are left."""
    primes = 2 * [False] + (n - 1) * [True]
    for i in range(2, int(n**0.5+1)):
        for j in range(i*i, n+1, i):
            primes[j] = False
    return [prime for prime, checked in enumerate(primes) if checked]

def set_insertion_sieve(n):
    """Performing insertion over deletion"""
    factors = set()
    for i in range(2,int(n**0.5+1)):
        if i not in factors:
            factors |= set(range(i*i, n+1, i))
    return set(range(2,n+1)) - factors

def np_sieve(n):
    """
    Sieve with it's guts swapped with numpy
    ndarray
    """
    primes = np.ones(n+1, dtype=np.bool)
    for i in np.arange(2, n**0.5+1, dtype=np.uint32):
        if primes[i]:
            primes[i*i::i] = False
    return np.nonzero(primes)[0][2:]


import numpy as np

class Standardization:
    def fit_transform(self, X):
        """
        X.shape = (データ数, 次元数)
        """

        self.mean_ = X.mean(axis=0)
        self.std_ = X.std(axis=0)
        Xsd = (X - self.mean_) / self.std_
        return Xsd

    def transform(self, X):
        """
        X.shape = (データ数, 次元数)
        """

        Xsd = (X - self.mean_) / self.std_
        return Xsd

    def inverse_transform(self, Xsd):
        """
        Xsd.shape = (データ数, 次元数)
        """

        X = (Xsd * self.std_) + self.mean_
        return X

if __name__=="__main__":

    std = Standardization()

    X = np.array([[1,2,3],
                     [4,5,6]])
    print("X\n", X)

    Xsd = std.fit_transform(X)
    print("Xsd\n", Xsd)

    Xsd = std.transform(X)
    print("Xsd\n", Xsd)

    X_ = std.inverse_transform(Xsd)
    print("X_\n", X_)


"""Игра угадай число
Компьютер сам загадывает и сам угадывает число
"""

import numpy as np

def binsearch(number: int = 1) -> int:
    """Бинарный поиск

    Args:
        number (int, optional): Загаданное число. Defaults to 1.

    Returns:
        int: Число попыток
    """
    count = 0  # счетчик попыток
    prdict_number_min = 1
    prdict_number_max = 101

    while True:
        count += 1

        predict_number = (prdict_number_max + prdict_number_min) // 2
        if number > predict_number:
            prdict_number_min = predict_number
        elif number < predict_number:
            prdict_number_max = predict_number
        else:
            break  # выход из цикла если угадали
    return count

def random_predict(number: int = 1) -> int:
    """Рандомно угадываем число

    Args:
        number (int, optional): Загаданное число. Defaults to 1.

    Returns:
        int: Число попыток
    """
    count = 0

    while True:
        count += 1
        predict_number = np.random.randint(1, 101)  # предполагаемое число
        if number == predict_number:
            break  # выход из цикла если угадали
    return count

def score_game(predict) -> int:
    """За какое количство попыток в среднем за 1000
       подходов угадывает наш алгоритм

    Args:
        predict ([type]): функция угадывания

    Returns:
        int: среднее количество попыток
    """
    count_ls = []
    # np.random.seed(1)  # фиксируем сид для воспроизводимости
    random_array = np.random.randint(1, 101, size=(1000))

    for number in random_array:
        count_ls.append(predict(number))

    score = int(np.mean(count_ls))
    print(f"Ваш алгоритм угадывает число в среднем за:{score} попыток")
    return score

if __name__ == "__main__":
    # RUN
    score_game(binsearch)


#importing Numpy, Matplotlib and sklearn libraries
import matplotlib.pyplot as plt
import numpy as np
#importing datasets from scikit-learn
from sklearn import datasets, linear_model

#load the dataset
house_price = [245, 312, 279, 308, 199, 219, 405, 324, 319, 255]
size = [1400, 1600, 1700, 1875, 1100, 1550, 2350, 2450, 1425, 1700]
print(size)

#ReShape the input to your regression
size2 = np.array(size).reshape((-1, 1))
print(size2)

#By Using fit module in linear regression, user can fit the data frequently and quickly
regr = linear_model.LinearRegression()
regr.fit(size2, house_price)
print('Coefficients: \n', regr.coef_) #[251.92316258]
print('intercept: \n', regr.intercept_) #[251.92316258]

#Sample Output
size_new = 1400
#Example 1
price = (size_new * regr.coef_) + regr.intercept_
print(price)
#Example 2
print(regr.predict([[size_new]]))

#Formula obtained for the trained model
def graph(formula, x_range):
    x = np.array(x_range)
    y = eval(formula)
    plt.plot(x, y)

#Plotting the prediction line
graph('regr.coef_*x + regr.intercept_', range(1000, 2700))
plt.scatter(size, house_price, color = 'black')
plt.ylabel('House Price')
plt.xlabel('Size of lose in sq.ft.')
plt.show()

#My Notes:
"""
So, in SupervisedLearning, we have solution first, we trained it before we start putting it unknown data
"""


import numpy as np;

def is_magic_square(mat):
    col_sums = list(map(sum, mat.transpose()))
    max_col_sum = max(col_sums)
    min_col_sum = min(col_sums)

    print("       col_sums :", col_sums)
    print("    max_col_sum :", max_col_sum)
    print("    min_col_sum :", min_col_sum)
    print()

    row_sums = list(map(sum, mat))
    max_row_sum = max(row_sums)
    min_row_sum = min(row_sums)

    print("       row_sums :", row_sums)
    print("    max_row_sum :", max_row_sum)
    print("    min_row_sum :", min_row_sum)
    print()

    sum_diag1 = sum(np.diag(mat))
    sum_diag2 = sum(np.diag(np.fliplr(mat)))

    print("      sum_diag1 :", sum_diag1)
    print("      sum_diag2 :", sum_diag2)
    print()

    return max_col_sum == min_col_sum == \
           max_row_sum == min_row_sum == \
           sum_diag1 == sum_diag2

def main():
    A = np.array([[17, 24,  1,  8, 15],
                  [23,  5,  7, 14, 16],
                  [ 4,  6, 13, 20, 22],
                  [10, 12, 19, 21,  3],
                  [11, 18, 25,  2,  9]])

    print()

    if is_magic_square(A):
        print("A is a magic square")
    else:
        print("A is NOT a magic square")

    print()

if __name__ == '__main__':
    main()


import numpy

def setupSieve(max):
    if max%2 == 0:
        elements = max
    else:
        elements = max + 1

    primePotential = numpy.zeros((int(elements/2), 2), dtype=numpy.uint32)
    primePotential[0,0] = 2
    primePotential[0,1] = 1

    j = 1

    for i in range(3, elements, 2):
        primePotential[j,0] = i
        primePotential[j,1] = 1
        j+=1

    return primePotential

def runSieve(arrPrimePotentials):
    max = arrPrimePotentials[-1, 0]
    for i in range(1, int(numpy.sqrt(max))):
        j = 3
        if arrPrimePotentials[i, 1] == 1:
            mul = arrPrimePotentials[i,0]
            loopy = True
            while loopy:
                mul = arrPrimePotentials[i,0]*j
                j += 2
                if mul <= max:
                    arrPrimePotentials[int(mul/2),1] = 0
                else:
                    loopy = False

def printPrimes(sieve):
    out = ""
    prime_count = 0
    for i in range(0, sieve.shape[0]):
        if sieve[i,1] == 1:
            out += str(sieve[i,0]) + ", "
            prime_count += 1
    print(out)

def main():

    #test
    max = 101
    primes = setupSieve(max)
    runSieve(primes)
    printPrimes(primes)

if __name__ == "__main__":
    main()


import codecademylib3_seaborn
import pandas as pd
import numpy as np
from weather_data import london_data

#print(london_data.iloc[100:200])
#print (len(london_data))

temp = london_data["TemperatureC"]
average_temp = np.mean(temp)
#print('average temperature is ' + str (average_temp))

temperature_var= np.var(temp)
#print('variance of temperature '+str(temperature_var))

temperature_standard_deviation = np.std(temp)
#print ('temperature_standard_deviation is ' + str(temperature_standard_deviation))

#print(london_data.head())

june = london_data.loc[london_data['month'] == 6]['TemperatureC']

july = london_data.loc[london_data['month']==7]['TemperatureC']

print('mean value of june is '+str(np.mean(june)))
print('mean value of june is '+str(np.mean(july)))

Project Code/STATISTICS WITH PYTHON/Project 2 Variance in Weather/script.py


import math
import random
import numpy

##Simple Monte Carlo Pricing Class for Vanilla Call Option
class SimpleMCPricer():
    def __init__(self, expiry, strike, spot, vol, r, paths):
        #The sigma value on the left side of the exponent
        self.variance = vol**2 * expiry
        #The sigma value on the right side of the e exponent
        self.root_Variance = math.sqrt(self.variance)
        #Corresponds to the (-1/2 * sigma^2)
        self.itoCorr = -0.5*self.variance
        ##Corresponds to S0e^(rT - 1/2 sigma^2T)
        self.movedSpot = spot*math.exp(r*expiry + self.itoCorr)
        self.runningSum = 0
        ##Simulate for all paths
        for i in range(0,paths):
            thisGauss = numpy.random.normal()
            ##Our rootVariance already has been multiplied by the expiry
            thisSpot = self.movedSpot*math.exp(self.root_Variance*thisGauss)
            #Determine payoff of this specific path
            thisPayoff = thisSpot - strike
            #Value of option is zero is our price is less than the strike
            thisPayoff = thisPayoff if thisPayoff > 0 else 0
            self.runningSum+=thisPayoff

        self.mean = self.runningSum/paths
        self.mean*= math.exp(-r * expiry)

    def getMean(self):
        return round(self.mean,2)

if __name__ == '__main__':
    model = SimpleMCPricer(2,32,30,.1,0.03,1000000)
    print("Price",model.getMean())


import numpy as np
from collections import defaultdict

def simpson(func, lower, upper):
    mid = lower + (upper - lower) / 2
    return (func(lower) + func(mid) + func(upper))/6

def adaptive_quadrature(func, lower, upper, tolerance=1e-10, max_depth=20):
    record = defaultdict(float)
        mid = lower + (lower - upper) / 2
        simp = record[[func, lower, upper]] || simpson(func, lower, upper)
        sub_simp1 = record[[func, lower, mid]] || simpson(func, lower, mid)
        sub_simp2 = record[[func, mid, upper]] || simpson(func, lower, mid)
        sub_simp = sub_simp1 + sub_simp2
        if abs(simp - sub_simp) < 10 * tolerance:
            return sub_simp
        else:
            return adapt_quad_helper(func, lower, mid, tolerance/2, rec_level+1) + \
                            adapt_quad_helper(func, mid, upper, tolerance/2, rec_level+1)

    return adapt_quad_helper(func, lower, upper, tolerance, 0)


from __future__ import division
from scipy.stats import norm
from pandas import read_excel
import numpy as np

# Transform to normal distribution #
def allnorm(x, y):

    sample = len(x)

    # Estimate norm parameters #
    phat1 = norm.fit(x, loc=0, scale=1)
    meanx = phat1[0]
    sigmax = phat1[1]

    phat2 = norm.fit(y, loc=0, scale=1)
    meany = phat2[0]
    sigmay = phat2[1]

    # Save frequent  calculations #
    x_minus_mean_x = x - meanx
    y_minus_mean_y = y - meany
    sigmax_pow_3 = sigmax ** 3
    sigmax_pow_2 = sigmax ** 2
    sigmay_pow_3 = sigmay ** 3
    sigmay_pow_2 = sigmay ** 2
    minus_sample = -sample

    # Calculate hessian matrix of log-likelihood #
    hes_normx = np.array([[minus_sample / (sigmax_pow_2), -2*np.sum(x_minus_mean_x) / (sigmax_pow_3)],
                           [-2*np.sum(x_minus_mean_x) / (sigmax_pow_3), (sample / (sigmax_pow_2)) - (3*np.sum((x_minus_mean_x)**2) / (sigmax**4))]
                          ])

    hes_normy = np.array([[minus_sample / (sigmay_pow_2), -2*np.sum(y_minus_mean_y) / (sigmay_pow_3)],
                           [-2*np.sum(x - meany) / (sigmay_pow_3), (sample / (sigmay_pow_2)) - (3*np.sum((y_minus_mean_y)**2) / sigmay**4)]
                          ])

    # Calculate cumulative of x and y #
    u = norm.cdf(x_minus_mean_x / sigmax, loc=0, scale=1)
    v = norm.cdf(y_minus_mean_y / sigmay, loc=0, scale=1)

    # Fix output #
    zeros_tmp = np.zeros((2, 2))

    new_hes_normx = np.concatenate((hes_normx, zeros_tmp), axis=1)
    new_hes_normy = np.concatenate((zeros_tmp, hes_normy), axis=1)

    hes_norm = np.concatenate((new_hes_normx, new_hes_normy), axis=0)

    sigma = [sigmax, sigmay, meanx, meany]

    # Fix overflow #
    for i in range(len(u)):
        if u[i] == 1:
            u[i] = 0.99999999
        if v[i] == 1:
            v[i] = 0.99999999

    result = {"sigma": sigma,
              "hes_norm": hes_norm,
              "u": u, "v": v
              }

    return result

# Test #
if __name__ == "__main__":

    df = read_excel("/home/petropoulakis/Desktop/artificial_data.xlsx", sheet_name='Sheet1')
    x = []
    y = []

    for index, row in df.iterrows():
        x.append([float(row['x'])])
        y.append([float(row['y'])])

    result = allnorm(x, y)

    print(result['sigma'])
    print(result['hes_norm'])
    print(result['u'][:5])
    print(result['v'][:5])


'''
Eduard Larrañaga
Computational Astrophysics
2020

Linear Fit
'''
import numpy as np

def linear_fit(x_data, y_data, sigma_y, sigma_x = 0., dydx = 0.):
     '''
     ------------------------------------------------------------
     linear_fit(x_data, y_data, sigma_y, sigma_x = 0., dydx = 0.)
     Returns the linear fit coeffcients for a given set of data
     ------------------------------------------------------------
     Arguments:
     x_data: numpy array with x-data
     y_data: numpy array with y-data
     sigma_y: numpy array with error data in the y component
     sigma_x: numpy array with error data in the x component
              (optional)
     dydx: slope or derivative information. This is needed when
           sigma_x is present (optional)
     -----------------------------------------------------------
     '''
     # Total error
     sigma2 = sigma_y**2 + (dydx*sigma_x)**2
     Si = 1./sigma2
     S = Si.sum()
     xi = x_data * sigma2
     yi = y_data * sigma2
     xi2 = x_data *x_data * sigma2
     xiyi =x_data * y_data * sigma2
     Sx = xi.sum()
     Sy = yi.sum()
     Sx2 = xi2.sum()
     Sxy = xiyi.sum()

     # Parameters in the linear fit
     a_1 = (Sy*Sx2 - Sx*Sxy)/(S*Sx2 - Sx*Sx)
     a_2 = (S*Sxy - Sx*Sy)/(S*Sx2 - Sx*Sx)

     # Associated error to the parameters
     sigma_a1 = np.sqrt(Sx2/(S*Sx2 - Sx*Sx))
     sigma_a2 = np.sqrt(S/(S*Sx2 - Sx*Sx))

     # Chi_squared parameter
     deltai = sigma2 * (a_1 + a_2*x_data - y_data)**2
     chi2 = deltai.sum()

     # R^2 Score
     R2 = 1 - chi2/(y_data.mean())
     return a_1, a_2, sigma_a1, sigma_a2, chi2, R2


import numpy as np

from adventofcode.util.input_helpers import get_input_for_day_as_str

data = np.array([int(t) for t in get_input_for_day_as_str(2021, 7).split(",")])

def fuel(pos):
    """Linear fuel consumption for a target position"""
    return int(abs(data - pos).sum())

def fuel_cumulative(pos):
    """Cumulative fuel consumption for a target position"""
    return int(np.sum([k * (k + 1) / 2 for k in abs(data - pos)]))

def part1():
    # By definition of the median of a set of values
    return fuel(np.median(data))

def part2():
    # The mean of a set minimizes the cumulative fuel but is not an integer,
    # use the minimum fuel consumption between the two adjacent integers
    m = np.mean(data)
    return min((fuel_cumulative(np.floor(m)), fuel_cumulative(np.ceil(m))))

if __name__ == "__main__":
    print(f"Solution for part 1: {part1()}")
    print(f"Solution for part 2: {part2()}")


def hill_en(message, key, decrypt = False):
    from math import sqrt
    n = int(sqrt(len(key)))
    if n * n != len(key):
        raise Exception("Invalid key length, should be square-root-able like")

    alpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
    # print "[ALPHA LENGTH]: ", len(alpha)
    tonum = dict([(alpha[i], i * 1) for i in range(len(alpha))])

    # Construct our key matrix
    keylist = []
    for a in key:
        keylist.append(tonum[a])

    keymatrix = []
    for i in range(n):
        keymatrix.append(keylist[i * n : i * n + n])

    from numpy import matrix
    from numpy import linalg

    keymatrix = matrix(keymatrix).round().T

    if decrypt:
        determinant = linalg.det(keymatrix).round()
        print "[DETERMINANT]", determinant
        if determinant == 0:
            raise Exception("Determinant ZERO, CHANGE THE KEY!")
        elif determinant % len(alpha) == 0:
            raise Exception("Determinant divisible by ALPHA LENGTH, CHANGE THE KEY!")

        inverse = []
        keymatrix =  matrix(keymatrix.getI() * determinant).round()

        invdeterminant = 0
        for i in range(10000):
            if (determinant * i % len(alpha)) == 1:
                invdeterminant = i
                break

        print "[INVERTED DETERMINANT]", invdeterminant

        for row in keymatrix.getA() * invdeterminant:
            newrow = []
            for i in row:
                newrow.append( i.round() % len(alpha) )
            inverse.append(newrow)

        keymatrix = matrix(inverse)

        # print "DECIPHERING: ", message
    else:
    #   print "[ENCIPHERING]: ", message
        pass

    print "[MATRIX]\n", keymatrix

    out = ''
    for i in range(len(message) / n):
        lst = matrix( [[tonum[a]] for a in message[i * n:i * n + n]] )
        result = keymatrix * lst
        out += ''.join([alpha[int(result.A[j][0]) % len(alpha)] for j in range(len(result))])

    return out

if __name__ == "__main__":
    key = "BERLXPMCJ"
    msg = "thanksgiving"
    cipherText = hill(msg, key)
    print(cipherText)
    print "CIPHERED TEXT: |%s|\n" % cipherText
    decipherText = hill(cipherText, key, True)
    print "DECIPHERED TEXT: |%s|\n" % decipherText
    if( msg == decipherText ):
        print "CORRECT"
    else:
        print "INCORRECT"


from __future__ import print_function

import numpy as np
import numpy.testing as npt
import pyiacsun

def test_fsvd():
    A = np.array([[1,2,3,4],[3,5,6,7],[2,8,3,1]])

    U2, S2, V2 = np.linalg.svd(A)
    U, S, V = pyiacsun.linalg.fsvd(A, 9, 3, usePowerMethod=True)

    npt.assert_allclose(S, S2)

def test_cholinvert():
    A = np.array([[4,12,-16],[12,37,-43],[-16,-43,98]])

    AInv = np.linalg.inv(A)
    logDet = np.log(np.linalg.det(A))
    AInv2, logDet2 = pyiacsun.linalg.cholInvert(A)
    npt.assert_allclose(AInv, AInv2)
    npt.assert_allclose(logDet, logDet2)

def test_svht():
    rank = 3
    m = 80
    n = 80
    sigma = 0.02
    X1 = np.random.randn(m,rank)
    X2 = np.random.randn(rank,n)

    Y = np.dot(X1, X2) + sigma * np.random.randn(m,n)

    thrKnownNoise, thrUnknownNoise, noiseEstimation, wSVD = pyiacsun.linalg.optimalSVHT(Y)

    #print("Known sigma : {0} - rank={1}".format(thrKnownNoise * sigma, rankKnownNoise))
    #print("Unknown sigma : {0} - rank={1} - sigmaNoise={2}".format(thrUnknownNoise, rankUnknownNoise, noiseEstimation))


import numpy as np
import tqdm
#random_generate = np.random.uniform(low=0.0, high=2.0, size=(1, 1))

#求解 pi
sum = 0
for i in tqdm.tqdm(range(3000000)):
        #random_generate = np.random.rand(2
        random_generate = np.random.uniform(low=0.0, high=2.0, size=(2))
        if np.sum(np.square(random_generate-np.array([1.0, 1.0]))) <=1:
                sum += 1
print(sum)
pi = 4 * (sum / 3000000)
print('pi is:{}'.format(pi))


import cv2
import numpy as np

from math import log10, sqrt
from argparse import ArgumentParser

path_plt_pic = "resources/plot.png"
path_src_pic = "resources/src.bmp"
path_res_pic = "resources/res.bmp"

max_pixel = 255.0

def psnr(original, modified):
    pic_1 = cv2.imread(original)
    pic_2 = cv2.imread(modified, 1)

    mse = np.mean((pic_1 - pic_2) ** 2)
    if mse == 0:
        return 100

    psnr_value = 20 * log10(max_pixel / sqrt(mse))
    return float(f'{psnr_value:.2f}')

def cmd_parser():
    cmd = ArgumentParser(description="Embedding information in images (LSB Method)")

    # Extract data
    cmd.add_argument("-e", dest="embed", action="store_false",
                     help="extracting the secret message, embedding by default", default=True)

    # Secret message
    cmd.add_argument("-m", dest="message", required=False,
                     help="the secret message to embed")

    # Character storage
    cmd.add_argument("-b", dest="coding", required=False,
                     help="the number of bits for a symbol, 8 bits by default")

    # Source image file
    cmd.add_argument("-s", dest="source_file", required=True,
                     help="the name of the source file", metavar="FILE")

    # Result image file
    cmd.add_argument("-r", dest="result_file", required=False,
                     help="the name of the result file", metavar="FILE")

    # Secret message in the file
    cmd.add_argument("-f", dest="secret_file", required=False,
                     help="the text file containing the secret message", metavar="FILE")

    return cmd.parse_args()


import numpy as np # Since we will define the equation variables and coefficients in array form

from numdifftools.nd_algopy import Jacobian # For use of grad operator and finding jacobian of a matrix with ease

import math # for using mathematical funcs

from matplotlib.pyplot import * #for plotting the links for animation

ct = 0

# Given data [taken as per Student's wish as Instructed]

r1 = 60

o2 = math.radians(0) #varries

r2 = 40

r6 = 60

# Defining Func Eqns in Python

#r3,r4,r5,o3 = 87.17,130.75,51.96,math.radians(66.58) for theta = 30 degrees

eqn = []

eq1 = lambda x : 40*np.sin(o2)-x[0]*np.sin(x[3])+60

eqn.append(eq1)

eq2 = lambda x : 40*np.cos(o2)-x[0]*np.cos(x[3])

eqn.append(eq2)

eq3 = lambda x : 60-x[1]*np.sin(x[3])+60

eqn.append(eq3)

eq4 = lambda x : x[2]-x[1]*np.cos(x[3])

eqn.append(eq4)

#Jacobians Defined

jacob1 = Jacobian(eq1)

jacob2 = Jacobian(eq2)

jacob3 = Jacobian(eq3)

jacob4 = Jacobian(eq4)

#plot

def ploter(ct):

    #Naming file

    if ct<10 :

        filename = 'QuickReturn00'+str(ct)+'.jpg'

    elif ct<100 :

        filename = 'QuickReturn0'+str(ct)+'.jpg'

    else :

        filename = 'QuickReturn'+str(ct)+'.jpg'

    #Plotting

    figure()

    xlim(-200, 200)

    ylim(0, 125)

    plot((s0[0],s3[0]),(s0[1],s3[1]),linewidth='4')

    plot((s1[0],s2[0]),(s1[1],s2[1]),linewidth='4')

    plot((-200,200),(120,120),linestyle='dashed')

    plot((0,0),(0,120),linestyle='dashed')

    savefig(filename)

    ct=ct+1

    return ct

# Newton Raphson Method for Multivariable systems of Non-Linear equation to be implemented

def root_finder():

    i = 0

    er = 100

    tol = 0.000001

    maxiter = 100

    M = 4

    N = 4

    x0 = np.array([1,1,1,1],dtype=float).reshape(N,1)

    while np.any(abs(er)>tol) and i< maxiter:

        func_eval = np.array([eq1(x0),eq2(x0),eq3(x0),eq4(x0)]).reshape(M,1)

        flat_x0 = x0.flatten()

        jac = np.array([jacob1(flat_x0),jacob2(flat_x0),jacob3(flat_x0),jacob4(flat_x0)])

        jac = jac.reshape(N,M)

        x_new = x0 - np.linalg.inv(jac)@func_eval

        er = x_new - x0

        x0 = x_new

        i+=1

    return x_new

#Itering through theta to find all solutions

for i in range(360):

    o2 = np.radians(i)

    x_new = root_finder()

    #co-ordinates

    o3 = x_new[3][0]

    r4 = x_new[1][0]

    s0 = [0,0]

    s1 = [0,r1]

    s2 = [s1[0]+r2*math.cos(o2),s1[1]+r2*math.sin(o2)]

    s3 = [r4*math.cos(o3),r4*math.sin(o3)]

    if i ==30 :

        print(x_new)

    clf()

    ct = ploter(ct)


import matplotlib.pyplot as plt
import numpy as np

###Problem 1

N=10000
mathematics = np.random.normal(500,100,N)
reading = np.random.normal(500,100,N)
writing = np.random.normal(500,100,N)
SATscore = mathematics + reading + writing

plt.hist(SATscore)
plt.show()

np.std(SATscore)
np.sqrt(3*10000)
np.var(SATscore)
np.mean(SATscore)

#problem 2
sig = np.ones((3,3)) *5000
sig[0,0]=10000
sig[1,1]=10000
sig[2,2]=10000
sig[1,2]=7000
sig[2,1]=7000

mvnscores = np.random.multivariate_normal(mu,sig,10000)
SATscores = np.sum(mvnscores,axis=1)

plt.hist(SATscores,bins=100)
plt.show()

np.mean(SATscores)
np.var(SATscores)
np.std(SATscores)
np.sqrt(64000)

#Figures:
plt.subplot(311)
dat=np.random.exponential(1,[10000,10])
plt.hist(np.mean(dat,1),bins=100)
plt.xlim(0,2.5)
plt.ylim(0,400)
plt.title('n=10')

plt.subplot(312)
dat=np.random.exponential(1,[10000,20])
plt.hist(np.mean(dat,1),bins=100)
plt.xlim(0,2.5)
plt.ylim(0,400)
plt.title('n=20')

plt.subplot(313)
dat=np.random.exponential(1,[10000,30])
plt.hist(np.mean(dat,1),bins=100)
plt.xlim(0,2.5)
plt.ylim(0,400)
plt.title('n=30')

plt.show()

#poisson
xmax=6
ymax=800
plt.subplot(311)
dat=np.random.poisson(3,[10000,10])
plt.hist(np.mean(dat,1),bins=100)
plt.xlim(0,xmax)
plt.ylim(0,ymax)
plt.title('n=10')

plt.subplot(312)
dat=np.random.poisson(3,[10000,20])
plt.hist(np.mean(dat,1),bins=100)
plt.xlim(0,xmax)
plt.ylim(0,ymax)
plt.title('n=20')

plt.subplot(313)
dat=np.random.poisson(3,[10000,30])
plt.hist(np.mean(dat,1),bins=100)
plt.xlim(0,xmax)
plt.ylim(0,ymax)
plt.title('n=30')

plt.show()

#beta
xmax=1
ymax=400
plt.subplot(311)
dat=np.random.beta(.1,.1,[10000,10])
plt.hist(np.mean(dat,1),bins=100)
plt.xlim(0,xmax)
plt.ylim(0,ymax)
plt.title('n=10')
#
plt.subplot(312)
dat=np.random.beta(.1,.1,[10000,20])
plt.hist(np.mean(dat,1),bins=100)
plt.xlim(0,xmax)
plt.ylim(0,ymax)
plt.title('n=20')
#
plt.subplot(313)
dat=np.random.beta(.1,.1,[10000,30])
plt.hist(np.mean(dat,1),bins=100)
plt.xlim(0,xmax)
plt.ylim(0,ymax)
plt.title('n=30')
plt.show()

#beta
xmin=12
xmax=20
ymax=700
plt.subplot(311)
dat=np.random.binomial(20,.8,[10000,10])
plt.hist(np.mean(dat,1),bins=100)
plt.xlim(xmin,xmax)
plt.ylim(0,ymax)
plt.title('n=10')
#
plt.subplot(312)
dat=np.random.binomial(20,.8,[10000,20])
plt.hist(np.mean(dat,1),bins=100)
plt.xlim(xmin,xmax)
plt.ylim(0,ymax)
plt.title('n=20')
#
plt.subplot(313)
dat=np.random.binomial(20,.8,[10000,30])
plt.hist(np.mean(dat,1),bins=100)
plt.xlim(xmin,xmax)
plt.ylim(0,ymax)
plt.title('n=30')
plt.show()


### Задание 2. Approximation
## Рассмотрим сложную математическую функцию на отрезке [1, 15]:
# f(x) = sin(x / 5) * exp(x / 10) + 5 * exp(-x / 2)
## Как известно, многочлен степени n (то есть w_0 + w_1 x + w_2 x^2 + ... + w_n x^n)
# однозначно определяется любыми n + 1 различными точками, через которые он проходит.
# Это значит, что его коэффициенты w_0, ... w_n можно определить системой линейных уравнений,
# где через x_1, ..., x_n, x_{n+1} обозначены точки, через которые проходит многочлен,
# а через f(x_1), ..., f(x_n), f(x_{n+1}) — значения, которые он должен принимать в этих точках.

#1. Сформируйте систему линейных уравнений (то есть задайте матрицу коэффициентов A и свободный вектор b)
# для многочлена первой степени, который должен совпадать с функцией f в точках 1 и 15.
# Решите данную систему с помощью функции scipy.linalg.solve. Нарисуйте функцию f и полученный многочлен

import numpy as np
import scipy as sp
from scipy import linalg
import math

def f(x):
    return (math.sin(x/5.)*math.exp(x/10.)+5*math.exp(-x/2.))

x=np.arange(1,16,0.1)
y=list(map(f,x))

def get_matrix(x_points):
    n=len(x_points)
    matrix=[]
    for x in x_points:
        row=[]
        for i in range(n):
            row.append(x**i)
        matrix.append(row)
    return (np.array(matrix))

def get_approximate_values(w,x_points):
    y=[]
    for x in x_points:
        y_curr=0
        for i in range(len(w)):
            y_curr+=w[i]*(x**i)
        y.append(y_curr)
    return (y)

x_2=[1,15]
A_2=get_matrix(x_2)
# print ('A_2', A_2, '\n')
y_2=list(map(f,x_2))
# print ('y_2', y_2, '\n')
w_2=sp.linalg.solve(A_2,y_2)
print ('w_2', w_2, '\n')
y_approx_2=get_approximate_values(w_2,x)
# print ('y_approx_2', y_approx_2, '\n')

#2. Повторите те же шаги для многочлена второй степени, который совпадает с функцией f в точках 1, 8 и 15
x_3=[1,8,15]
A_3=get_matrix(x_3)
# print ('A_3', A_3, '\n')
y_3=list(map(f,x_3))
# print ('y_3', y_3, '\n')
w_3=sp.linalg.solve(A_3,y_3)
print ('w_3', w_3, '\n')
y_approx_3=get_approximate_values(w_3,x)
# print ('y_approx_3', y_approx_3, '\n')

#3. Повторите те же шаги для многочлена третьей степени, который совпадает с функцией f в точках 1, 4, 10 и 15.
# Хорошо ли он аппроксимирует функцию?
# Коэффициенты данного многочлена (четыре числа в следующем порядке: w_0, w_1, w_2, w_3) являются ответом на задачу
x_4=[1,4,10,15]
A_4=get_matrix(x_4)
# print ('A_4', A_4, '\n')
y_4=list(map(f,x_4))
# print ('y_4', y_4, '\n')
w_4=sp.linalg.solve(A_4,y_4)
print ('w_4', w_4, '\n')
y_approx_4=get_approximate_values(w_4,x)
# print ('y_approx_4', y_approx_4, '\n')

result=w_4
print ('result:',result)

#4. Построение графика

from matplotlib import pyplot as plt
plt.plot(x,y)
plt.plot(x,y_approx_2)
plt.plot(x,y_approx_3)
plt.plot(x,y_approx_4)
plot=[[plt.plot(x,y)],[plt.plot(x,y_approx_2)],[plt.plot(x,y_approx_3)],[plt.plot(x,y_approx_4)]]
print (plot)


import numpy as np
from math import sqrt

def get_primes_below(n):
    # http://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188
    """ Input n>=6, Returns a array of primes, 2 <= p < n """
    sieve = np.ones(n/3 + (n % 6 == 2), dtype=np.bool)
    sieve[0] = False
    for i in xrange(int(n**0.5)/3+1):
        if sieve[i]:
            k = 3*i+1 | 1
            sieve[((k*k)/3)::2*k] = False
            sieve[(k*k+4*k-2*k*(i & 1))/3::2*k] = False
    return np.r_[2, 3, ((3*np.nonzero(sieve)[0]+1) | 1)]

def is_prime(n):
    if n == 2:
        return True
    if n % 2 == 0 or n <= 1:
        return False
    for i in range(3, int(sqrt(n))+1, 2):
        if n % i == 0:
            return False
    return True


##-------------------------------------------
## 2 VARIABLE NORMAL DISTIBUTION
##-------------------------------------------

import matplotlib.pyplot as plt
import numpy as np

#USER INPUTS
FUNC=2
FS=18	#FONT SIZE
CMAP='hsv' #'RdYlBu'

#normal distribution param
ux=0.5; uy=0.0
sx=2.0; sy=1.0 								#STD-DEV
rho=0.5; 									#[0,1) RHO=PEARSON CORRELATION
u=np.array([[ux],[uy]]) 					#MEAN VECTOR u=[ux,uy]
s=np.array([[sx**2.0,rho*sy*sx],[rho*sy*sx,sy**2.0]])	#COVARIANCE METRIC

#GENERATE POINTS SAMPLED FROM DISTRIBUTION
xp, yp = np.random.multivariate_normal(u.reshape(2), s, 1000).T

# DEFINE FUNCTION
def N(x, y):
	out=1.0/(2*3.1415*sx*sy*(1-rho**2.0)**0.5)
	out=out*np.exp(-(((x-ux)/sx)**2.0-2*rho*((x-ux)/sx)*((y-uy)/sy)+((y-uy)/sy)**2.0)/(2*(1-rho**2)))
	return out

#MESH-1 (SMALLER)
L=3*max(sx,sy)
xmin=-L; xmax=L; ymin=-L; ymax=L
x,y = np.meshgrid(np.linspace(xmin,xmax,20),np.linspace(ymin,ymax,20))

#MESH-2 (DENSER)
X, Y = np.meshgrid(np.linspace(xmin, xmax, 40), np.linspace(ymin, ymax, 40))

#SURFACE PLOT
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.set_xlabel('x', fontsize=FS); ax.set_ylabel('y', fontsize=FS); ax.set_zlabel('p(x,y)', fontsize=FS)
surf=ax.plot_surface(X, Y, N(X, Y), cmap=CMAP)
ax.scatter(xp, yp, 1.1*np.max(N(X, Y)) , '.')
plt.show();

#SCATTER PLOT
plt.plot(xp, yp,'.')

#CONTOUR PLOT
# plt.axis('equal')
plt.contour(X, Y, N(X, Y), 20, cmap=CMAP);
plt.show();


"""
Minimal Polynomials of Linear Recurrence Sequences

AUTHORS:

- William Stein
"""

#*****************************************************************************
#       Copyright (C) 2005 William Stein <wstein@gmail.com>
#
#  Distributed under the terms of the GNU General Public License (GPL)
#
#    This code is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
#    General Public License for more details.
#
#  The full text of the GPL is available at:
#
#                  http://www.gnu.org/licenses/
#*****************************************************************************

import sage.rings.rational_field

def berlekamp_massey(a):
    r"""
    Use the Berlekamp-Massey algorithm to find the minimal polynomial
    of a linearly recurrence sequence a.

    The minimal polynomial of a linear recurrence `\{a_r\}` is
    by definition the unique monic polynomial `g`, such that if
    `\{a_r\}` satisfies a linear recurrence
    `a_{j+k} + b_{j-1} a_{j-1+k} + \cdots + b_0 a_k=0`
    (for all `k\geq 0`), then `g` divides the
    polynomial `x^j + \sum_{i=0}^{j-1} b_i x^i`.

    INPUT:

    -  ``a`` -- a list of even length of elements of a field
       (or domain)

    OUTPUT:

    -  ``Polynomial`` -- the minimal polynomial of the
       sequence (as a polynomial over the field in which the entries of a
       live)

    EXAMPLES::

        sage: from sage.matrix.berlekamp_massey import berlekamp_massey
        sage: berlekamp_massey([1,2,1,2,1,2])
        x^2 - 1
        sage: berlekamp_massey([GF(7)(1),19,1,19])
        x^2 + 6
        sage: berlekamp_massey([2,2,1,2,1,191,393,132])
        x^4 - 36727/11711*x^3 + 34213/5019*x^2 + 7024942/35133*x - 335813/1673
        sage: berlekamp_massey(prime_range(2,38))
        x^6 - 14/9*x^5 - 7/9*x^4 + 157/54*x^3 - 25/27*x^2 - 73/18*x + 37/9
    """

    if not isinstance(a, list):
        raise TypeError("Argument 1 must be a list.")
    if len(a)%2 != 0:
        raise ValueError("Argument 1 must have an even number of terms.")

    M = len(a)//2

    try:
        K = a[0].parent().fraction_field()
    except AttributeError:
        K = sage.rings.rational_field.RationalField()
    R = K['x']
    x = R.gen()

    f = {}
    q = {}
    s = {}
    t = {}
    f[-1] = R(a)
    f[0] = x**(2*M)
    s[-1] = 1
    t[0] = 1
    s[0] = 0
    t[-1] = 0
    j = 0
    while f[j].degree() >= M:
        j += 1
        q[j], f[j] = f[j-2].quo_rem(f[j-1])
        # assert q[j]*f[j-1] + f[j] == f[j-2], "poly divide failed."
        s[j] = s[j-2] - q[j]*s[j-1]
        t[j] = t[j-2] - q[j]*t[j-1]
    t = s[j].reverse()
    f = ~(t[t.degree()]) * t  # make monic  (~ is inverse in python)
    return f


import numpy as np
import time
import copy

def k_means(X, k, eps=1e-20, max_iter=5000, print_freq=100):
    """
    This function takes in the following arguments:
        1) X, the data matrix with dimension m x n
        2) k, the number of clusters
        3) eps, the threshold of the norm of the change in clusters
        4) max_iter, the maximum number of iterations
        5) print_freq, the frequency of printing the report

    This function returns the following:
        1) clusters, a list of clusters with dimension k x 1
        2) label, the label of cluster for each data with dimension m x 1
        3) cost_list, a list of costs at each iteration

    NOTE:
        1) We use l2-norm as the distance metric
    """
    m, n = X.shape
    cost_list = []
    t_start = time.time()
    # randomly generate k clusters
    clusters = np.random.multivariate_normal((np.random.rand(n))
        * X.mean(axis=0), 2*X.std(axis=0) * np.eye(n), size=k)
    label = np.zeros((m, 1)).astype(int)
    iter_num = 0
    while iter_num < max_iter:
        prev_clusters = copy.deepcopy(clusters)
        for i in range(m):
            data = X[i, :]
            diff = data - clusters
            curr_label = np.argsort(np.linalg.norm(diff, axis=1)).item(0)
            label[i] = curr_label

            # norm_list = [(np.linalg.norm(X[i, :] - centroid))**2 for
            #              centroid in clusters]
            # norm_array = np.array(norm_list)
            # sorted_norms = np.argsort(norm_arra)ym
            # label[i] = sorted_norms.item(0)

        for i in range(k):
            ind = np.where(label == i)[0]
            if len(ind) > 0:
                clusters[i, :] = X[ind].mean(axis=0)
            # new_centroid = np.zeros_like(clusters[0])
            # num_pts = 0
            # for j in range(len(label)):
            #     if label[j] == i:
            #         new_centroid += X[i, :]
            #         num_pts += 1
            # if num_pts > 0:
            #     clusters[i, :] = new_centroid / num_pts

        cost = k_means_cost(X, clusters, label)
        cost_list.append(cost)

        # if (iter_num + 1) % print_freq == 0:
            # print('-- Iteration {} - cost {:4.4E}'.format(iter_num+
            #                                               1, cost))
        if np.linalg.norm(prev_clusters - clusters) <= eps:
            # print('-- Algorithm converges at iteration {} with cost '
            #       '{:4.4E}'.format(iter_num + 1, cost))
            break
        iter_num += 1

    t_end = time.time()
    # print('-- Time elapsed: {t:2.2f} seconds'.format(t=t_end-t_start))
    return clusters, label, cost_list

def k_means_cost(X, clusters, label):
    """
    This function takes in the following arguments:
        1) X, the data matrix with dimension m x n
        2) clusters, the matrix with dimension k x 1
        3) label, the label of the cluster for each data point with
           dimension m x 1

        This function calculates and returns the cost for the given
        data and clusters.

    NOTE:
        1) The total cost is defined by the sum of the l2-norm
           difference between each data point and the cluster center
           assigned to this data point
    """
    m, n = X.shape
    k = clusters.shape[0]

    X_cluster = clusters[label.flatten()]
    cost = (np.linalg.norm(X - X_cluster, axis=1)**2).sum()

    # cost = 0.0
    # for i in range(m):
    #     cost += (np.linalg.norm(X[i] - clusters[label[i]]))**2

    return cost


# https://deeplearningcourses.com/c/artificial-intelligence-reinforcement-learning-in-python
# https://www.udemy.com/artificial-intelligence-reinforcement-learning-in-python
from __future__ import print_function, division
from builtins import range
# Note: you may need to update your version of future
# sudo pip install -U future

import numpy as np
from grid_world import windy_grid, ACTION_SPACE
from iterative_policy_evaluation import print_values, print_policy

SMALL_ENOUGH = 1e-3
GAMMA = 0.9

# copied from iterative_policy_evaluation
def get_transition_probs_and_rewards(grid):
  ### define transition probabilities and grid ###
  # the key is (s, a, s'), the value is the probability
  # that is, transition_probs[(s, a, s')] = p(s' | s, a)
  # any key NOT present will considered to be impossible (i.e. probability 0)
  transition_probs = {}

  # to reduce the dimensionality of the dictionary, we'll use deterministic
  # rewards, r(s, a, s')
  # note: you could make it simpler by using r(s') since the reward doesn't
  # actually depend on (s, a)
  rewards = {}

  for (s, a), v in grid.probs.items():
    for s2, p in v.items():
      transition_probs[(s, a, s2)] = p
      rewards[(s, a, s2)] = grid.rewards.get(s2, 0)

  return transition_probs, rewards

if __name__ == '__main__':
  grid = windy_grid()
  transition_probs, rewards = get_transition_probs_and_rewards(grid)

  # print rewards
  print("rewards:")
  print_values(grid.rewards, grid)

  # initialize V(s)
  V = {}
  states = grid.all_states()
  for s in states:
    V[s] = 0

  # repeat until convergence
  # V[s] = max[a]{ sum[s',r] { p(s',r|s,a)[r + gamma*V[s']] } }
  it = 0
  while True:
    biggest_change = 0
    for s in grid.all_states():
      if not grid.is_terminal(s):
        old_v = V[s]
        new_v = float('-inf')

        for a in ACTION_SPACE:
          v = 0
          for s2 in grid.all_states():
            # reward is a function of (s, a, s'), 0 if not specified
            r = rewards.get((s, a, s2), 0)
            v += transition_probs.get((s, a, s2), 0) * (r + GAMMA * V[s2])

          # keep v if it's better
          if v > new_v:
            new_v = v

        V[s] = new_v
        biggest_change = max(biggest_change, np.abs(old_v - V[s]))

    it += 1
    if biggest_change < SMALL_ENOUGH:
      break

  # find a policy that leads to optimal value function
  policy = {}
  for s in grid.actions.keys():
    best_a = None
    best_value = float('-inf')
    # loop through all possible actions to find the best current action
    for a in ACTION_SPACE:
      v = 0
      for s2 in grid.all_states():
        # reward is a function of (s, a, s'), 0 if not specified
        r = rewards.get((s, a, s2), 0)
        v += transition_probs.get((s, a, s2), 0) * (r + GAMMA * V[s2])

      # best_a is the action associated with best_value
      if v > best_value:
        best_value = v
        best_a = a
    policy[s] = best_a

  # our goal here is to verify that we get the same answer as with policy iteration
  print("values:")
  print_values(V, grid)
  print("policy:")
  print_policy(policy, grid)


import matplotlib.pyplot as pl
from matplotlib.ticker import MultipleLocator, FuncFormatter
import numpy as np
x = np.arange(0, 4*np.pi, 0.01)
y = np.sin(x)
pl.figure(figsize=(8,4))
pl.plot(x, y)
ax = pl.gca()

def pi_formatter(x, pos):
    """
    比较罗嗦地将数值转换为以pi/4为单位的刻度文本
    """
    m = np.round(x / (np.pi/4))
    n = 4
    if m%2==0: m, n = m/2, n/2
    if m%2==0: m, n = m/2, n/2
    if m == 0:
        return "0"
    if m == 1 and n == 1:
        return "$\pi$"
    if n == 1:
        return r"$%d \pi$" % m
    if m == 1:
        return r"$\frac{\pi}{%d}$" % n
    return r"$\frac{%d \pi}{%d}$" % (m,n)

# 设置两个坐标轴的范围
pl.ylim(-1.5,1.5)
pl.xlim(0, np.max(x))

# 设置图的底边距
pl.subplots_adjust(bottom = 0.15)

pl.grid() #开启网格

# 主刻度为pi/4
ax.xaxis.set_major_locator( MultipleLocator(np.pi/4) )

# 主刻度文本用pi_formatter函数计算
ax.xaxis.set_major_formatter( FuncFormatter( pi_formatter ) )

# 副刻度为pi/20
ax.xaxis.set_minor_locator( MultipleLocator(np.pi/20) )

# 设置刻度文本的大小
for tick in ax.xaxis.get_major_ticks():
    tick.label1.set_fontsize(16)
pl.show()


import sympy.physics.mechanics as _me
import sympy as _sm
import math as m
import numpy as _np

x, y = _me.dynamicsymbols('x y')
x_d, y_d = _me.dynamicsymbols('x_ y_', 1)
e = _sm.cos(x)+_sm.sin(x)+_sm.tan(x)+_sm.cosh(x)+_sm.sinh(x)+_sm.tanh(x)+_sm.acos(x)+_sm.asin(x)+_sm.atan(x)+_sm.log(x)+_sm.exp(x)+_sm.sqrt(x)+_sm.factorial(x)+_sm.ceiling(x)+_sm.floor(x)+_sm.sign(x)
e = (x)**2+_sm.log(x, 10)
a = _sm.Abs(-1*1)+int(1.5)+round(1.9)
e1 = 2*x+3*y
e2 = x+y
am = _sm.Matrix([e1.expand().coeff(x), e1.expand().coeff(y), e2.expand().coeff(x), e2.expand().coeff(y)]).reshape(2, 2)
b = (e1).expand().coeff(x)
c = (e2).expand().coeff(y)
d1 = (e1).collect(x).coeff(x,0)
d2 = (e1).collect(x).coeff(x,1)
fm = _sm.Matrix([i.collect(x)for i in _sm.Matrix([e1,e2]).reshape(1, 2)]).reshape((_sm.Matrix([e1,e2]).reshape(1, 2)).shape[0], (_sm.Matrix([e1,e2]).reshape(1, 2)).shape[1])
f = (e1).collect(y)
g = (e1).subs({x:2*x})
gm = _sm.Matrix([i.subs({x:3}) for i in _sm.Matrix([e1,e2]).reshape(2, 1)]).reshape((_sm.Matrix([e1,e2]).reshape(2, 1)).shape[0], (_sm.Matrix([e1,e2]).reshape(2, 1)).shape[1])
frame_a = _me.ReferenceFrame('a')
frame_b = _me.ReferenceFrame('b')
theta = _me.dynamicsymbols('theta')
frame_b.orient(frame_a, 'Axis', [theta, frame_a.z])
v1 = 2*frame_a.x-3*frame_a.y+frame_a.z
v2 = frame_b.x+frame_b.y+frame_b.z
a = _me.dot(v1, v2)
bm = _sm.Matrix([_me.dot(v1, v2),_me.dot(v1, 2*v2)]).reshape(2, 1)
c = _me.cross(v1, v2)
d = 2*v1.magnitude()+3*v1.magnitude()
dyadic = _me.outer(3*frame_a.x, frame_a.x)+_me.outer(frame_a.y, frame_a.y)+_me.outer(2*frame_a.z, frame_a.z)
am = (dyadic).to_matrix(frame_b)
m = _sm.Matrix([1,2,3]).reshape(3, 1)
v = m[0]*frame_a.x +m[1]*frame_a.y +m[2]*frame_a.z


"""
PCA Implementation via Covariance Matrix
By: Johnny Lu
"""
import numpy as np
from sklearn.decomposition import PCA
np.random.seed(42)

def pca(X, k):
    """
    Implement PCA from scratch using NumPy

    :param X: n-dimensional Original Array
    :param k: The target dimension
    :return:  n-dimensional array that after PCA with k dimension
    """
    n_samples, n_features = X.shape
    X_norm = X - np.mean(X, axis=0)
    # covariance formula yields scalar, Transpose: X_norm.T yield matrix
    cov_mat = np.cov(X_norm.T)
    eig_val, eig_vec = np.linalg.eig(cov_mat)
    eig_pairs = [(np.abs(eig_val[i]), eig_vec[:, i]) for i in range(n_features)]
    eig_pairs.sort(reverse=True)
    transfer_matrix = np.array([ele[1] for ele in eig_pairs[:k]])
    data = np.dot(X_norm, transfer_matrix.T)

    return -data

# for verification
if __name__ == '__main__':
    array = np.random.randn(10, 5)
    print(f"Origin Matrix: \n {array}\n")
    print(f"Own PCA approach: \n {pca(X=array, k=3)}\n")
    print(f"Scikit-learn Approach: \n {PCA(n_components=3).fit_transform(array)}")


import numpy as np
from scipy import stats

def welch_test_statistic(sample_1, sample_2):
    '''
    Computes the t-statistic for two sample arrays with different but normally distributed variances.
    Parameters:
    sample_1: numpy array
    sample_2: numpy array

    Returns:
    t-statistic
    '''
    numerator = np.mean(sample_1) - np.mean(sample_2)
    denominator_sq = (np.var(sample_1) / len(sample_1)) + (np.var(sample_2) / len(sample_2))
    return numerator / np.sqrt(denominator_sq)

def welch_satterhwaithe_df(sample_1, sample_2):
    '''Calculate the degrees of freedom for a two-sample t-test.
    Parameters:
    sample_1: numpy array
    sample_2: numpy array

    Returns:
    degrees of freedom
    '''
    ss1 = len(sample_1)
    ss2 = len(sample_2)
    df = (
        ((np.var(sample_1)/ss1 + np.var(sample_2)/ss2)**(2.0)) /
        ((np.var(sample_1)/ss1)**(2.0)/(ss1 - 1) + (np.var(sample_2)/ss2)**(2.0)/(ss2 - 1))
    )
    return df

def bootstrap_sample_means(data, n_bootstrap_samples=200):
    '''
    Generates an array of bootstrap sample means. Each bootstramp sample has
    the same length as the given dataset. The given dataset is resampled with
    replacement to generate the bootstraps.
    Parameters:
    ----------
    data: an array of samples
    n_bootstrap_samples: Number of bootstrap samples to generate

    Returns:
    -------
    An array of bootstrap sample means
    '''
    bootstrap_sample_means = []
    for i in range(n_bootstrap_samples):
        bootstrap_sample = np.random.choice(data, size=len(data), replace=True)
        bootstrap_sample_means.append(np.mean(bootstrap_sample))
    return bootstrap_sample_means

def compute_power(n, sigma, alpha, mu0, mua):
    '''
    Computes the power for an a/b test
    Parameters:
    ----------
    n: size of the sample
    sigma: population standard deviation
    mu0: population mean
    mua: effect
    '''

    standard_error = sigma / n**0.5
    h0 = stats.norm(mu0, standard_error)
    ha = stats.norm(mua, standard_error)
    critical_value = h0.ppf(1 - alpha)
    power = 1 - ha.cdf(critical_value)
    return power


from math import log
import numpy as np
import operator
# def createData():
#     return np.array([[1 , 1, 'yes'] , [1 , 1, 'yes'] , [1 , 0 , 'no'] , [0 , 1 , 'no'] , [0 , 1, 'no']]) , ['no surfacing' , 'flippers']

def shannonEntropy(Data):
    classOcurr = {}
    for X in Data:
        if X[-1] not in classOcurr.keys():
            classOcurr[X[-1]] = 0
            classOcurr[X[-1]]   += 1
        else:
            classOcurr[X[-1]] += 1
    shanEntropy = 0.0

    for X in classOcurr.keys():
        px = classOcurr[X]/len(Data)
        shanEntropy -= px * log(px , 2)
    return shanEntropy

def splitFeature(Data , axis , val):
    splitData = []
    for X in Data:
        if X[axis] == val:
            temp = list(X[ : axis])
            temp.extend(list(X[axis+1:]))
            splitData.append(temp)
    return splitData

def majorityList(classList):
    classes = {}
    for val in classList:
        if val not in classes.keys():
            classes[val] = 0
        classes[val] += 1
    return sorted(classes.items() , key=operator.itemgetter(1) , reverse=True)[0][0]

def bestFeatToSplit(Data):
    num = len(Data[0]) - 1
    bastEnt = shannonEntropy(Data)
    bastInfoGain = 0.0 ; BestFeat = -1
    for Xs in range(num):
        X = [Y[Xs] for Y in Data]
        uniX = set(np.array(X))
        newEnt = 0
        for val in uniX:
            ds = splitFeature(Data , Xs , val)
            px = len(ds)/len(Data)
            newEnt += px * shannonEntropy(ds)
            infoGain = bastEnt - newEnt
        if (infoGain > bastInfoGain):
            bastInfoGain = infoGain
            BestFeat = Xs
    return BestFeat

def createTree(Data , labels):
    classList = [labels[-1] for labels in Data]
    if classList.count(classList[0]) == len(classList):
        return classList[0]
    if len(Data[0]) == 1:
        return majorityList(classList)
    bestFeature = bestFeatToSplit(Data)
    myTree = {labels[bestFeature]: {} }
    featValues = [values[bestFeature] for values in Data]
    uniFeatValues = set(featValues)
    for val in uniFeatValues:
        sub = np.array(list(labels[:bestFeature]) + list(labels[bestFeature + 1:]))
        myTree[labels[bestFeature]][val] = createTree(splitFeature(Data , bestFeature , val) , sub)
    print(myTree.keys())
    return myTree

def classify(InTree , featLabels , testVec):
    firstFeat = list(InTree.keys())[0]
    secDict = InTree[firstFeat]
    firstIndex = list(featLabels).index(firstFeat)
    classlabel = 0
    for keys in list(secDict.keys()):
        if keys == testVec[firstIndex]:
            if type(secDict[keys]).__name__ == "dict":
                classlabel = classify(secDict[keys] , (featLabels[:firstIndex] + featLabels[firstIndex+1:]) , (testVec[:firstIndex] + testVec[firstIndex+1:]))
            else:
                classlabel = secDict[keys]

    return classlabel


# -*- coding: utf-8 -*-
"""
Created on Thu Oct 18 07:31:52 2018

@author: behzad
"""
import numpy as np

#' The main use of numpy is defining arrays ---These are vectors !!

A1 = np.array([1,4,5,11]) # An array of integers
A2 = np.array([1.2,5.0,9.3,5])
A1.dtype
A2.dtype
# All of the elements of an array should have the same type !
# If they don't numpy will conver them

A3 = np.array(["marco", "mirko", "sara"])
A4 = np.array([True,False, False, True])

A3.dtype
A5 = np.array([1, "manuel", 4.5])

# This is definitely a disadvantage because it will change it by itself and it
# it will create a mess !!!
L6 = [1.4,5.3,7.6]
L7 = [2.2,3.0, 9.5]
A6 = np.array(L6)
A7 = np.array(L7)

L8=L6+L7 # We don't want this !!!!
A8 = A6+ A7 # This does vectorized operation

A9 = A6 - A7

A10=A6*A7

L11 = 2*L6 #☻ We do not want this !!!
A11 = 2* A6

# LEt's use it to solve our probelms !! RLF method !

Opaque_item_list = ["wall", "ceiling","door"]
opaque_item_array = np.array(Opaque_item_list)

Opaque_U_list = [0.438,0.25,1.78]
opaque_U_array = np.array(Opaque_U_list)

opaque_area_array = np.array([105.8,200,2.2])

T_inside_heating= 20
T_outside_heating = -4.8
DeltaT_heating= T_inside_heating-T_outside_heating
opaque_HF_array = DeltaT_heating*opaque_U_array
opaque_Q_array = opaque_HF_array*opaque_area_array

# Element extraction
opaque_Q_array[0]
opaque_Q_array[0:2]
opaque_Q_array[-1]

opaque_Q_array[-1]=0 # You can assign values

#Logical arrays !!
TheOneMoreThan1000 = opaque_Q_array > 1000

A12 = np.array([3,5,7,11])
A13 = A12 > 5
A14 = A12<5

opaque_item_array == "wall"

A12[A14]

index_wall = opaque_item_array == "wall"
indeX_ceiling  = opaque_item_array == "ceiling"
index_wallOrCeiling = index_wall | indeX_ceiling

opaque_Q_array[opaque_item_array == "wall"]
Opaque_wallOrCeiling_value = opaque_Q_array[index_wallOrCeiling].sum()
SumOfAll_opaqueHearting =opaque_Q_array.sum()
AverageOfAll_opaqueHeating=opaque_Q_array.mean()

# Let's use this approach to solve the problem of resistances
Ri = ["R_internal","conv", 8.9, 15]
R1 = ["R_foam","cond", 0.06, 0.05, 15]
R2 = ["R_wood","cond", 0.1, 0.4, 15]
R3 = ["R_plaster","cond", 0.01, 1, 15]
Ro = ["R_external","conv", 20, 15]

resistance_names = np.array(["R_internal","R_foam","R_wood","R_plaster","R_external"])
resistance_types = np.array(["conv","cond","cond","cond","conv"])
resistance_k = np.array([ None,0.05,0.4,1,None])
resistance_L = np.array([ None,0.06,0.1,0.01,None])
resistance_A = np.array([ 15,15,15,15,15])
resistance_h = np.array([ 8.9,None,None,None,20])

resistance_RValues= np.array(np.zeros(5))

resistance_RValues[resistance_types=="cond"]=resistance_L[resistance_types=="cond"]/(resistance_k[resistance_types=="cond"]*resistance_A[resistance_types=="cond"])
resistance_RValues[resistance_types=="conv"]=1.0/(resistance_h[resistance_types=="conv"]*resistance_A[resistance_types=="conv"])
Rtot=resistance_RValues.sum()

# Let's define 2D arrays : Matrices
L1 = [1.2,3.3,4.5]
L2 = [3.9,4.3,2.2]
L3 = [2.2,3.2,3.9]

AA1 = np.array([L1,[3.9,4.3,2.2],L3]) # pay attention that we are defining lists inside other lists

AA1[:,1]

AA1[2,:]

AA1.sum()

AA1.sum(axis=0)
AA1.sum(axis=1)