import numpy as np
import time

x1 = [9, 2, 5, 0, 0, 7, 5, 0, 0, 0, 9, 2, 5, 0, 0]
x2 = [9, 2, 2, 9, 0, 9, 2, 5, 0, 0, 9, 2, 5, 0, 0]

### CLASSIC DOT PRODUCT OF VECTORS IMPLEMENTATION ###
tic = time.process_time()
dot = 0
for i in range(len(x1)):
    dot += x1[i] * x2[i]
toc = time.process_time()
print (1.1, "dot = " + str(dot) + "\n ----- Computation time = " + str(1000*(toc-tic)) + "ms")

### CLASSIC OUTER PRODUCT IMPLEMENTATION ###
tic = time.process_time()
outer = np.zeros((len(x1), len(x2))) # we create a len(x1)*len(x2) matrix with only zeros
for i in range(len(x1)):
    for j in range(len(x2)):
        outer[i, j] = x1[i] * x2[j]
toc = time.process_time()
print (1.2, "outer = " + str(outer) + "\n ----- Computation time = " + str(1000*(toc-tic)) + "ms")

### CLASSIC ELEMENTWISE IMPLEMENTATION ###
tic = time.process_time()
mul = np.zeros(len(x1))
for i in range(len(x1)):
    mul[i] = x1[i] * x2[i]
toc = time.process_time()
print (1.3, "elementwise multiplication = " + str(mul) + "\n ----- Computationtime=" + str(1000*(toc-tic)) + "ms")

### CLASSIC GENERAL DOT PRODUCT IMPLEMENTATION ###
W = np.random.rand(3,len(x1)) # Random 3*len(x1) numpy array tic = time.process_time()
gdot = np.zeros(W.shape[0])
for i in range(W.shape[0]):
    for j in range(len(x1)):
        gdot[i] += W[i, j]*x1[j]
toc = time.process_time()
print (1.4, "gdot = " + str(gdot) + "\n ----- Computation time = " + str(1000*(toc-tic)) + "ms")

### VECTORIZED DOT PRODUCT OF VECTORS ###
tic = time.process_time()
dot = np.dot(x1, x2)
toc = time.process_time()
print (2.1, "dot = " + str(dot) + "\n ----- Computation time = " + str(1000*(toc-tic)) + "ms")
### VECTORIZED OUTER PRODUCT ###
tic = time.process_time()
outer = np.outer(x1, x2)
toc = time.process_time()
print (2.2, "outer = " + str(outer) + "\n ----- Computation time = " + str(1000*(toc-tic)) + "ms")
### VECTORIZED ELEMENTWISE MULTIPLICATION ###
tic = time.process_time()
mul = np.multiply(x1, x2)
toc = time.process_time()
print (2.3, "elementwise multiplication = " + str(mul) + "\n -----Computationtime=" + str(1000*(toc-tic)) + "ms")
### VECTORIZED GENERAL DOT PRODUCT ###
tic = time.process_time()
dot = np.dot(W, x1)
toc = time.process_time()
print (2.4, "gdot = " + str(dot) + "\n ----- Computation time = " + str(1000*(toc-tic)) + "ms")

def L1(yhat, y):
    loss = sum(abs(y - yhat))
    return loss
yhat = np.array([.9, 0.2, 0.1, .4, .9])
y = np.array([1, 0, 0, 1, 1])
print(3, "L1 = " + str(L1(yhat,y)))

def L2(yhat, y):
    loss = np.dot(y-yhat, y-yhat)
    return loss
print(4, "L2 = " + str(L2(yhat, y)))


"""
Filename: particleDistribution.py
Comment: Setup the initial position of particles
"""

from numpy import *
import random

def latticeDistribution(leftLimit, rightLimit, topLimit, bottomLimit, spacing):
    '''
    Obtains the two dimensional computational domain limits:
        left, right, top, bottom
    and fill the computational domain with particles equispaced in
    the two dimensions.
    '''
    x , y = mgrid[leftLimit : rightLimit : spacing, topLimit : bottomLimit : spacing]
    x = x.flatten()
    y = y.flatten()

    z = []
    for i in range(len(x)):
        # Add the equispaced position to the particles' array
        z.extend([complex(x[i],y[i])])

    z = array(z)                # Convert the array to a numpy object
    return z

def triangleDistribution(leftLimit, rightLimit, topLimit, bottomLimit, spacing):
    '''
    Obtains the two dimensional computational domain limits:
        left, right, top, bottom
    and fill the computational domain with particles equispaced in
    the two dimensions and then shift the even .
    '''
    halfSpacing = (spacing / 2)
    x1, y1 = mgrid[leftLimit: (rightLimit - halfSpacing) : spacing, topLimit : (bottomLimit - spacing) : 2 * spacing]

    x = x1.flatten()
    y = y1.flatten()

    size = len(x)
    z = []
    for i in range(size):
        # Add the equispaced position to the particles' array
        z.extend([complex(x[i],y[i])])

    x2, y2 = mgrid[(leftLimit + halfSpacing): rightLimit : spacing, (topLimit - spacing) : bottomLimit : 2 * spacing]
    x = x2.flatten()
    y = y2.flatten()

    size = len(x)
    for i in range(size):
        # Add the equispaced position to the particles' array
        z.extend([complex(x[i],y[i])])

    z = array(z)                # Convert the array to a numpy object
    return z

def quasiRandomDistribution(leftLimit, rightLimit, topLimit, bottomLimit, spacing, noise):
    '''
    Obtains the two dimensional computational domain limits:
        left, right, top, bottom
    and fill the computational domain with particles quasi random equispaced in
    the two dimensions.
    '''
    x , y = mgrid[leftLimit : rightLimit : spacing, topLimit : bottomLimit : spacing]
    x = x.flatten()
    y = y.flatten()

    z = []
    halfSpacing = noise / 2

    for i in range(len(x)):
        # Generates uniform noise between '- half the spacing' to '+ half the spacing'
        #   in both dimensions
        xNoise = random.uniform(-halfSpacing, halfSpacing)
        yNoise = random.uniform(-halfSpacing, halfSpacing)
        # add the uniform noise to the particle position
        z.extend([complex(x[i] + xNoise, y[i] + yNoise)])

    z = array(z)                # Convert the array to a numpy object
    return z

# EOF


r"""
Miscellaneous Groups

This is a collection of groups that may not fit into some of the other infinite families described elsewhere.
"""

# Implementation note:
#     When adding a group here make an entry
#     in the  misc_groups_catalog.py module
#     or a more closely-related catalog module

def QuaternionMatrixGroupGF3():
    r"""
    The quaternion group as a set of `2\times 2` matrices over `GF(3)`.

    OUTPUT:

    A matrix group consisting of `2\times 2` matrices with
    elements from the finite field of order 3.  The group is
    the quaternion group, the nonabelian group of order 8 that
    is not isomorphic to the group of symmetries of a square
    (the dihedral group `D_4`).

    .. note::
        This group is most easily available via ``groups.matrix.QuaternionGF3()``.

    EXAMPLES:

    The generators are the matrix representations of the
    elements commonly called `I` and `J`, while `K`
    is the product of `I` and `J`. ::

        sage: from sage.groups.misc_gps.misc_groups import QuaternionMatrixGroupGF3
        sage: Q = QuaternionMatrixGroupGF3()
        sage: Q.order()
        8
        sage: aye = Q.gens()[0]; aye
        [1 1]
        [1 2]
        sage: jay = Q.gens()[1]; jay
        [2 1]
        [1 1]
        sage: kay = aye*jay; kay
        [0 2]
        [1 0]

    TESTS::

        sage: groups.matrix.QuaternionGF3()
        Matrix group over Finite Field of size 3 with 2 generators (
        [1 1]  [2 1]
        [1 2], [1 1]
        )

        sage: Q = QuaternionMatrixGroupGF3()
        sage: QP = Q.as_permutation_group()
        sage: QP.is_isomorphic(QuaternionGroup())
        True
        sage: H = DihedralGroup(4)
        sage: H.order()
        8
        sage: QP.is_abelian(), H.is_abelian()
        (False, False)
        sage: QP.is_isomorphic(H)
        False
    """
    from sage.rings.finite_rings.constructor import FiniteField
    from sage.matrix.matrix_space import MatrixSpace
    from sage.groups.matrix_gps.all import MatrixGroup
    MS = MatrixSpace(FiniteField(3), 2)
    aye = MS([1,1,1,2])
    jay = MS([2,1,1,1])
    return MatrixGroup([aye, jay])


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

#  # Correlation
#  Relate to the way people use the term **correlation**, often they mention events or things that are expected to happen together. We may use the term loosely
#  and may interprate that one is causing the other. But when we study correlation, we are always told **correlation is not causation** and so our initial inkling mustn't be that conclusion.
#  for e.g. one may say, "It rains whenever I wear white", we know that this cant be true but statements such as these sometimes may be interpreted as one causing the other.
#

#  The most comman form of correlation coefficient that most data scientists compute is called
#  **pearson correlation coefficient**. Normally, when we say correlation it is assumed that its pearson correlation that's been computed, but it doesn't take a lot to confirm.
#  We will discuss 3 types correlation coefficients but you may find a few more in the literature.
#  1. Pearson correlation coefficient
#  2. Spearman correlation coefficient
#  3. Point Biseral correlation coefficient
#  ## Pearson correlation coefficient
#  As mentioned this is the most common form of correlation coefficient, and its computed as follows.
#  $$
#  \rho_{X, Y} = \frac{\mathbb{E}[(X - \mu_{X})(Y - \mu_{Y})]}{\sigma_{X} \sigma_{Y}}
#  $$
#  The numerator represents covariance between X and Y and the denominator represents the standard deviation.
#  The use of standard deviation suggests that pearson coefficient assumes that the distribution is a form of normal/gaussian distribution.
#

#  Here are few important elements to remember about the coefficient.
#  * It measures a linear relationship/trend between two numerical variables and is effected by outliers.
#  * Correlation ranges from -1 to 1, wherein value of -1 represents perfect negative. While a value of 1 reflects perfect positive correlation.
#  * A positive correlation value suggests that both quantities increase together.
#  * A negative correlation value suggests that as one value increases the other decreases.
#  * A value of zero(0) correlation suggests that there is no linear relationship between the quantities.
#  * Correlation value is unit less as you would observe from the equation above (the units cancel out),
#  which means it isn't associate with any measurement and so can be used for comparisons.
#  for e.g correlation value of 0.9 is the same even if the value is measured in kilometers or miles.

#  Let's demonstrate this with some code. We will import some libraries.

# In[1]:

# importing some libraries
import matplotlib.pyplot as plt
import numpy as np
from scipy.stats.stats import pearsonr

# In[2]:

# Create different scenarios of correlation

perfect_pos_corr = [(x, x + 2) for x in range(1, 11)]
pos_corr_outlier = perfect_pos_corr.copy()
pos_corr_outlier.extend([(11, 6), (12, 2)])

perfect_neg_corr = [
    (x, y) for x, y in zip(range(1, 11), sorted(range(1, 11), reverse=True))
]
np.random.seed(0)
no_corr = [(np.random.randn(500), np.random.randn(500))]

x1, y1 = zip(*perfect_pos_corr)
x2, y2 = zip(*perfect_neg_corr)
x3, y3 = zip(*no_corr)
x4, y4 = zip(*pos_corr_outlier)

#  The first graph shows a **perfect positive** linear trend with a value of 1, while the second graph shows a **perfect negative** trend, with a value of -1.
#  We also have the third graph which almost certainly shows a random set of points with no linear trend and thus it has
#  a correlation value of nearly(-0.04) zero. The last plot is rather interesting because, it almost has a perfect positive linear trend
#  but has two points which are outlier points. Thus, by adding a few outliers we have affected the pearson correlation cofficient
#  by a large degree i.e. dropping the strength of relationship from a value of 1 to 0.36, which suggests weak linear relationship.

# In[3]:

fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2, figsize=(15, 8))
ax1.scatter(x1, y1, color="orange", edgecolor="k")
ax1.set_title(f"Perfect Positive Correlation -> {round(pearsonr(x1,y1)[0],2)}")
ax2.scatter(x2, y2, color="orange", edgecolor="k")
ax2.set_title(f"Perfect Negative Correlation -> {round(pearsonr(x2,y2)[0],2)}")
ax3.scatter(x3, y3, alpha=0.5, color="orange", edgecolor="k")
ax3.set_title(f"Nearly No Correlation -> {round(pearsonr(x3[0],y3[0])[0],2)}")
ax4.scatter(x4, y4, alpha=0.5, color="orange", edgecolor="k")
ax4.set_title(
    f"Positive Correlation with outliers -> {round(pearsonr(x4,y4)[0],2)}"
)
plt.show()

#  ## Spearman Correlation Coefficient
#  Spearman correlation coefficient has some advantages over pearson correlation coefficient.
#  It performs well in cases where pearson correlation coefficient doesnt pick the strength of relationship
#  between the features. It is defined as follows,
#  $$
#  r_{s} = \frac{cov((R(X),R(Y))}{\sigma_{R(X)} \sigma_{R(Y)}}
#  $$
#  The numerator represents covariance between the rank of the values in X and in Y and the denominator represents the standard deviation of the rank.
#  So if you had a table with examples such as below, ranks are calculated in the following manner.
#
#  | X  | Y  | R(X) | R(Y) |
#  |----|----|------|------|
#  | 20 | 5  | 20   | 3    |
#  | 10 | 2  | 1    | 1    |
#  | 50 | 80 | 3    | 2    |
#

#

#  Here are few important elements to remember about the coefficient.
#  * It measures linear or non-linear trend between two numerical variables and the are not as sensitive to outliers as pearson correlation coefficient is.
#  * It ranges from -1 to 1, wherein value of -1 represents perfect negative. While a value of 1 reflects perfect positive correlation.
#  * A positive correlation value suggests that both quantities increase together.
#  * A negative correlation value suggests that as one value increases the other decreases.
#  * A value of zero(0) correlation suggests that there is no linear relationship between the quantities.
#  * Same as pearson, the value is unit less and can be used for comparisons.

# In[4]:

from scipy.stats.stats import spearmanr

fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2, figsize=(15, 8))
ax1.scatter(x1, y1, color="orange", edgecolor="k")
ax1.set_title(
    f"Spearman Correlation -> {round(spearmanr(x1,y1)[0],2)}\
    , Pearson Correlation -> {round(pearsonr(x1,y1)[0],2)}"
)
ax2.scatter(x2, y2, color="orange", edgecolor="k")
ax2.set_title(
    f"Spearman Correlation -> {round(spearmanr(x2,y2)[0],2)}\
    , Pearson Correlation -> {round(pearsonr(x2,y2)[0],2)}"
)

ax3.scatter(x3, y3, alpha=0.5, color="orange", edgecolor="k")

ax3.set_title(
    f"Spearman Correlation -> {round(spearmanr(x3[0],y3[0])[0],2)}\
    , Pearson Correlation -> {round(pearsonr(x3[0],y3[0])[0],2)}"
)
ax4.scatter(x4, y4, alpha=0.5, color="orange", edgecolor="k")
ax4.set_title(
    f"Spearmen Correlation -> {round(spearmanr(x4,y4)[0],2)}\
    , Pearson Correlation -> {round(pearsonr(x4,y4)[0],2)}"
)
plt.show()

# In[5]:

from scipy.special import expit
np.random.seed(1)
scatter_dataX1 = np.random.randn(100)
scatter_dataY1 = scatter_dataX1 + np.random.randn(100) * 0.5
scatter_dataY1[-10:] = 3 + np.random.rand(1)

scatter_dataX2 = np.sort(np.random.randn(100))
scatter_dataY2 = scatter_dataX2 + np.random.randn(100) * 0.5
scatter_dataY2[-10:] = 3 + np.random.rand(1)

scatter_dataX3 = np.sort(np.random.randn(100))
scatter_dataY3 = scatter_dataX3 + np.random.randn(100) * 0.1
scatter_dataX3[-10:] = -1 + np.random.rand(1)

scatter_dataX4 = np.linspace(-10,10,100)
scatter_dataY4 = scatter_dataX4**3 #+ np.random.randn(100)*0.05
# scatter_dataX4[-10:] = -1 + np.random.rand(1)

# In[6]:

_, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2, figsize=(15, 8))
ax1.scatter(
    scatter_dataX1, scatter_dataY1, alpha=0.5, color="orange", edgecolor="k"
)
ax1.set_title(
    f"Spearmen Correlation -> {round(spearmanr(scatter_dataX1,scatter_dataY1)[0],2)}\
    , Pearson Correlation -> {round(pearsonr(scatter_dataX1,scatter_dataY1)[0],2)}"
)

ax2.scatter(
    scatter_dataX2, scatter_dataY2, alpha=0.5, color="orange", edgecolor="k"
)
ax2.set_title(
    f"Spearmen Correlation -> {round(spearmanr(scatter_dataX2,scatter_dataY2)[0],2)}\
    , Pearson Correlation -> {round(pearsonr(scatter_dataX2,scatter_dataY2)[0],2)}"
)

ax3.scatter(
    scatter_dataX3, scatter_dataY3, alpha=0.5, color="orange", edgecolor="k"
)
ax3.set_title(
    f"Spearmen Correlation -> {round(spearmanr(scatter_dataX3,scatter_dataY3)[0],2)}\
    , Pearson Correlation -> {round(pearsonr(scatter_dataX3,scatter_dataY3)[0],2)}"
)

ax4.scatter(
    scatter_dataX4, scatter_dataY4, alpha=0.5, color="orange", edgecolor="k"
)
ax4.set_title(
    f"Spearmen Correlation -> {round(spearmanr(scatter_dataX4,scatter_dataY4)[0],2)}\
    , Pearson Correlation -> {round(pearsonr(scatter_dataX4,scatter_dataY4)[0],2)}"
)
plt.show()

# In[7]:

import pandas as pd
from sklearn.datasets import load_boston

# load the boston dataset of houses,
# It contains the value of houses in the area of boston in thousands along with multiple features of the houses.
# load the dataset
boston = load_boston()
# required components of the sklearn bunch object
data = boston["data"]
target = boston["target"]
cols = boston["feature_names"]

# creating a pandas dataframe
# fmt:off
pd_df = (pd.DataFrame(data, columns=cols)
         .assign(target=target))
pd_df.columns = pd_df.columns.str.lower()

# In[8]:

# fmt: on
fig, ax = plt.subplots()
subset_df = pd_df.loc[:, ["rm", "target"]]
subset_df.plot(
    kind="scatter",
    x="rm",
    y="target",
    alpha=0.5,
    color="orange",
    edgecolor="k",
    ax=ax,
)
ax.set_title(
    f"Correlation between rm and the target is -> {round(subset_df.corr()['target'][0],2)}"
)
plt.show()

# In[9]:

# correlation ranges from -1 to 1
corr = pd_df.corr()
corr[["target"]].plot(kind="bar", color="k")


import numpy as np
import pandas as pd
from scipy import stats
import matplotlib.pyplot as plt
from sklearn.mixture import GaussianMixture

# Help taken from these websites below on how to apply the Skewness and kurtosis
# https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.kurtosis.html
# https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.skew.html
# including some parts of the algorithm from the matlab
# syntheticDataExample.m file provided in the course material

def statistics(IrisMatrix):
    # input of Numpy Matrix of a specific class
    # initializing my variables
    # all as 1x4 each position representing the features as follow
    # [sepal length, sepal width, petal length, petal width]
    minimum = [None]*4
    maximum = [None]*4
    avg = [None]*4
    stddev = [None]*4
    skewness = [None]*4
    kurtosis = [None]*4
    trimmedmean1 = [None]*4
    trimmedmean2 = [None]*4
    trimmedmean3 = [None]*4
    # computed the covariance of the class [50x4] before sorting each column of the classes for the trimmed mean
    # sorting the data will cause the covariance to be different as it will produce different pairs of data that were not originally there
    covar = np.cov(IrisMatrix.astype(float),rowvar=False)
    # Now sort the data by column to compute the trimmed mean
    IrisMatrix = np.sort(IrisMatrix, axis=0)

    i=0 # Initialize column counter
    while i < 4:
        minimum[i] = min(IrisMatrix[:,i]) # minimum of column
        maximum[i] = max(IrisMatrix[:,i]) # maximum of column
        avg[i] = np.mean((IrisMatrix[:,i])) # mean of column
        avg[i] = np.round(avg[i], 4) # round the mean to 4 decimals
        #compute the trimmed mean of p=1
        trimmedmean1[i] = np.mean((IrisMatrix[1:len(IrisMatrix)-1,i]))
        trimmedmean1[i] = np.round(trimmedmean1[i], 7) # 7 decimals
        trimmedmean2[i] = np.mean((IrisMatrix[2:len(IrisMatrix)-2,i])) # p=2
        trimmedmean2[i] = np.round(trimmedmean1[i], 7)
        trimmedmean3[i] = np.mean((IrisMatrix[3:len(IrisMatrix)-3,i])) # p=3
        trimmedmean3[i] = np.round(trimmedmean1[i], 7)
        # compute standard deviation over n-1 factor
        stddev[i] = np.std((IrisMatrix[:,i]), ddof=1)
        stddev[i] = np.round(stddev[i], 4)
        # compute skewness
        skewness[i] = stats.skew(IrisMatrix[:,i])
        skewness[i] = np.round(skewness[i], 4)
        # compute kurtosis using the pearson definition
        kurtosis[i] = stats.kurtosis(IrisMatrix[:,i], fisher=False)
        kurtosis[i] = np.round(kurtosis[i], 4)
        i += 1 # Increment column counter

    return ("Minimum: ",minimum, "Maximum: ",maximum, "Mean: ",avg, "Trimmed Mean(p=1): ",trimmedmean1, "Trimmed Mean(p=2): ",trimmedmean2,"Trimmed Mean(p=3): ",trimmedmean3,"StdDev: ",stddev,"Covariance: ",covar, "Skewness: ", skewness, "Kurtosis: ", kurtosis)

def syntheticData(n,minimun, maximum, avg, covar):
    # takes n = number of synthetic data points wanted, minimum, maximum, mean, and a numpy covariance matrix as input
    # make a nx4 uniform distributed random data matrix
    randData = np.random.rand(n,4)
    # matrix multiplication of the random data with covariance [4x4] matrix
    randData = np.matmul(randData,covar)
    # store the sythenthetic data in an nx4 matrix
    syntheticData = np.zeros((n,4))
   #store into synthetic data matrix
    mu = [None]*4

    i=0 # column counter
    while i<4:
        # Find min max of rand data column
        randMin = min(randData[:,i])
        randMax = max(randData[:,i])
        # Find min max of Iris data column
        a = minimun[i]
        b = maximum[i]
        # Compute min-max normalization
        X = (((randData[:,i] - randMin)/(randMax - randMin)) * (b-a)) + a
        #compute the difference between synthetic and original data mean
        mu[i] = np.mean(X) - avg[i]
        #store into synthetic data matrix after adjusting mean by the difference
        syntheticData[:,i] = X - mu[i]
        i+=1 #increment column counter

    return syntheticData

def plot(original, synthetic, i, j):
    #quick plot function
    index = ['sepal_length', 'sepal_width', 'petal_length', 'petal_width']
    plt.figure()
    plt.scatter(original[:,i], original[:,j], color='blue', label = 'Original')
    plt.scatter(synthetic[:,i], synthetic[:,j], color='red', label = 'Synthetic')
    plt.title('Synthetic vs. Iris Data')
    plt.ylabel(index[j])
    plt.xlabel(index[i])
    plt.legend()
    plt.show()
    return

def plotAllClasses(o1,s1,o2,s2,o3,s3, i, j):
    #quick plot function
    index = ['sepal_length', 'sepal_width', 'petal_length', 'petal_width']
    plt.figure()
    plt.scatter(o1[:,i], o1[:,j], color='blue', label = 'setosa_org')
    plt.scatter(s1[:,i], s1[:,j], color='red', label = 'setosa_synth')
    plt.scatter(o2[:,i], o2[:,j], color='green',label = 'versicolor_org')
    plt.scatter(s2[:,i], s2[:,j], color='purple',label = 'versicolor_synth')
    plt.scatter(o3[:,i], o3[:,j], color='orange',label = 'virginica_org')
    plt.scatter(s3[:,i], s3[:,j], color='brown',label = 'virginica_synth')
    plt.title('Synthetic vs. Iris Data')
    plt.ylabel(index[j])
    plt.xlabel(index[i])
    plt.legend()
    plt.show()
    return

if __name__ == '__main__':
    Iris = pd.read_csv("iris.csv",header=0)
    IrisMatrix = Iris.to_numpy()
    IrisMatrixCov = np.array(IrisMatrix[:,0:4])

    setosa = IrisMatrix[0:50,0:4]
    versicolor = IrisMatrix[50:100,0:4]
    virginica = IrisMatrix[100:150,0:4]

    sepal_l = IrisMatrix[:,0]
    sepel_w = IrisMatrix[:,1]
    petal_l = IrisMatrix[:,2]
    petal_w = IrisMatrix[:,3]

    # My Implentations

    setosa_stats = statistics(setosa)
    versicolor_stats = statistics(versicolor)
    virginica_stats = statistics(virginica)
    covar = np.cov(IrisMatrixCov.astype(float),rowvar=False)

    print()
    print(setosa_stats)
    print()
    print(versicolor_stats)
    print()
    print(virginica_stats)
    print()
    print(covar)
    print()

    # 0 = sepal length, 1 = sepal width, 2 = petal length, 3 = petal width
    setosa_synthetic= syntheticData(100,setosa_stats[1],setosa_stats[3],setosa_stats[5], setosa_stats[15])
    np.savetxt("setosa_synthetic.csv", setosa_synthetic, delimiter=",",fmt='%5.4f')
    plot(setosa, setosa_synthetic, 0, 3)

    versicolor_synthetic = syntheticData(100,versicolor_stats[1],versicolor_stats[3],versicolor_stats[5], versicolor_stats[15])
    np.savetxt("versicolor_synthetic.csv", versicolor_synthetic, delimiter=",",fmt='%5.4f')
    plot(versicolor, versicolor_synthetic, 0, 3)

    virginica_synthetic= syntheticData(100,virginica_stats[1],virginica_stats[3],virginica_stats[5], virginica_stats[15])
    np.savetxt("virginica_synthetic.csv", virginica_synthetic, delimiter=",",fmt='%5.4f')
    plot(virginica, virginica_synthetic, 0, 3)

    plotAllClasses(setosa, setosa_synthetic,versicolor, versicolor_synthetic,virginica, virginica_synthetic,0,3)

Algorithms for Data Science/Homework 2/Homework2_Q1_Q2.py


import numpy as np

print("--------------------------------------")
print("arange")
print("erzeugen von Arrays")
print("--------------------------------------")

a = np.arange(1, 7)
print(a)

# im Vergleich dazu nun range:
x = range(1, 7)
print(x) #x ist ein Iterator
print(list(x))

# weitere arange-Beispiele:
x = np.arange(7.3)
print(x)
x = np.arange(0.5, 6.1, 0.8)  # start-inklusiv, end-exklusiv, step, dtype
print(x)
x = np.arange(0.5, 6.1, 0.8, int)
print(x)

print("--------------------------------------")
print("linspace")
print("gleichmäßig verteilte Arrays erzeugen")
print("--------------------------------------")

# 50 Werte (Default) zwischen 1 und 10
print(np.linspace(1, 10))
# 7 Werte zwischen 1 und 10
print(np.linspace(1, 10, num=7))
# ohne Endpunkt
print(np.linspace(1, 10, num=7, endpoint=False))
# mit Wert der Abstandsweite -> liefert Tupel
samples, spacing = np.linspace(1, 10, num=5, endpoint=False, retstep=True)
print(samples, spacing)

print("--------------------------------------")
print("Nulldimensionale Arrays")
print("--------------------------------------")

x = np.array(42)
print("x : " , x)
print("Der Typ von x : ", x.dtype)
print("Die Dimension von x : ", np.ndim(x))

print("--------------------------------------")
print("Eindimensionale Arrays")
print("--------------------------------------")

F = np.array([1.2, 3.5, 6.4, 7.7, 8.5])
print("F : " , F)
print("Der Typ von F : ", F.dtype)
print("Die Dimension von F : ", np.ndim(F))

print("--------------------------------------")
print("Mehrdimensionale Arrays")
print("--------------------------------------")

A = np.array([[1.2, 3.5, 6.4],
              [1.5, -6.3, 6.6],
              [4.6, -5.7, -4.5]])
print("A : " , A)
print("Der Typ von A : ", A.dtype)
print("Die Dimension von A : ", np.ndim(A))


'''This module defines multiple notions of distance and norms to use in our
model construction and evaluation.

'''

import numpy as np

def euclidean_2(x):
    '''Compute the Euclidean l_2 norm.'''
    return np.linalg.norm(x)

def euclidean_infty(x):
    '''Compute the Euclidean l_infinity norm.'''
    return np.linalg.norm(x, ord=np.inf)

def euclidean_1(x):
    '''Compute the Euclidean l_1 norm (Manhattan distance).'''
    return np.linalg.norm(x, ord=1)


import pandas as pd
import numpy as np
import os
from .constants import random_index

from importlib import resources
import io

def total(matrix, num_of_params):
    '''total function sums the column of matrix and returns a 1d-array

    Args:
    matrix: It is the pairwise comparison matrix after taking user input
    num_of_params: Number of factors taken for comparison'''
    tot = np.full((num_of_params), 0, dtype=float)
    for i in range(num_of_params):
        for j in range(num_of_params):
            tot[i] = tot[i] + matrix[j, i]
    return(tot)

def normalization(sum_of_column, matrix, num_of_params):
    ''''normalization function computes the matrix with ouput from total function and returns matrix

    Args:
    sum_of_column: It is the sum of each column of pariwise comparison matrix and also a output from total function
    matrix: It is the pariwise comparison matrix after taking user input
    num_of_params: Number of factors taken for comparison'''
    norm = np.full((num_of_params, num_of_params), 1, dtype=float)
    for i in range(num_of_params):
        for j in range(num_of_params):
            norm[i, j] = matrix[j, i]/sum_of_column[i]
    norm_t = norm.transpose()
    return (norm_t)

def weight(normalized_matrix, num_of_params):
    '''weight function computes the weight of each factor

    Args:
    normalized_matrix: It is the matrix from normalization function which has normalized value computed from sum of column
    num_of_params: Number of factors taken for comparison'''
    li = []
    for i in range(num_of_params):
        wt = np.sum(normalized_matrix[[i]])/num_of_params
        li.append(round(wt, 3))
    return(li)

def consistency_check(total, weight, num_of_params):
    '''consistency_check function checks the set of judgements to determine their reliability

    total: It is the sum of each column of pariwise comparison matrix and also a output from total function
    weight: Weight of each factors derived from the weight function
    num_of_params: Number of factors taken for comparison '''
    dir_path = os.path.dirname(os.path.realpath(__file__))
    # Lambda value
    lmda = 0
    for i in range(num_of_params):
        lmda = lmda + total[i] * weight[i]

    # Consistency Index
    CI = (lmda-num_of_params)/(num_of_params-1)

    # Random Index
    #df = pd.read_csv(os.path.join(dir_path, 'random_index.csv'))
    # with resources.open_binary(os.path.join(dir_path, 'random_index.csv')) as fp:
    #     df = fp.read()
    # df = pd.read_csv(io.Bytes)
    for x in random_index:
        if (x==str(num_of_params)):
            RI = random_index[x]

    # Consistency Ratio
    CR = CI/RI
    to_return = {
        "Consistency Index: ": CI,
        "Random Index: ": RI,
        "Consistency Ratio: ": CR
    }
    if(CR < 0.1):
        to_return["Consistency: "] = True
    else:
        to_return["Consistency: "] = False

    return (to_return)

#     "The data is consistent"
# "The data is inconsistent. Iterate the process by changing comparison value"


#usr/bin/env/python
'''
Author  : Bhekimpilo Ndhlela
Author  : 18998712
module  : TW244 Applied Mathematics
task    : Assignment 03 problem1
since   : Wednesday-29-08-2018
'''
import numpy as np
import matplotlib.pyplot as plt
import scipy.integrate
def eulers_method(fx, fy, T, x0, y0, h):
    x, y = np.zeros(len(T), dtype=float), np.zeros(len(T), dtype=float)
    x[0], y[0] = x0, y0

    for i in range(1, len(T)):
       x[i] = x[i-1] + h*fx(T[i], x[i-1], y[i-1])
       y[i] = y[i-1] + h*fy(T[i], x[i-1], y[i-1])
    return x, y

def plot_graphs(x, y, t, odeint_sol=None):
    plt.xlabel('t = time')
    plt.ylabel('Prey vs. Predetor')
    plt.plot(t, x, '-k', linewidth=4, label='X = Predetor Euler')
    plt.plot(t, y, '-r', linewidth=4, label='Y = Prey Euler')
    if odeint_sol is not None:
        plt.title('Euler Method vs. ODE45 using Prey and Predetor model')
        plt.plot(t, odeint_sol[:,0], '-m', linewidth=4, label='X = Predetor ODE_INT')
        plt.plot(t, odeint_sol[:,1], '-b', linewidth=4, label='Y = Prey ODE_INT')
    else:
        plt.title('Euler Method: Prey and Predetor model')
    plt.legend(loc='best')
    plt.grid(True, linewidth=3)
    plt.show()

def plot_graph_Q1e(odeint_sol, t):
    plt.xlabel('t = time = linspace(0, 20000, 1000)')
    plt.ylabel('Prey vs. Predetor')
    plt.title('Prey vs. Predetor model (10000 as limiting Capacity for the Prey)')
    plt.plot(t, odeint_sol[:,0], '-r', linewidth=4, label='X = Predetor')
    plt.plot(t, odeint_sol[:,1], '-b', linewidth=4, label='Y = Prey')
    plt.legend(loc='best')
    plt.grid(True, linewidth=3)
    plt.show()

if __name__ == '__main__':
    # question 1a.)
    fx = lambda t, x, y: -3*x + 3*x*y
    fy = lambda t, x, y: y - 2*x*y
    T, h, x0, y0 = np.arange(0, 10, 1.0/100.0), 1.0/100.0, 0.3, 1.0
    X, Y = eulers_method(fx, fy, T, x0, y0, h)
    #plot_graphs(X, Y, T)

    # question 1b.)
    '''
    (b) Using the same function f as in part (a), solve the same system using
    ode45 . Plot the solution (using a continuous line) on the same Figure as
    above using hold on . Show the plot and the code you used to call ode45.
    Compare with the plot from (a). Which do you think is more accurate?
    '''
    f = lambda x, t: (-3*x[0] + 3*x[0]*x[1], x[1] - 2*x[1]*x[0])
    x0 = [0.3, 1.0]
    odeint_sol = scipy.integrate.odeint(f, x0, T)
    #plot_graphs(X, Y, T, odeint_sol=odeint_sol)

    # question 1c.)
    '''
    (c) Find approximations for the minimum and maxi-mum number of predators
    that will be present.
    '''
    # according to euler
    max_x_euler, min_x_euler= int(round(max(X) * 1000)), int(round(min(X) * 1000))
    print('MAX Predetor = ', max_x_euler, ' @ approx ', 9, ' days')
    print('MIN Predetor = ', min_x_euler ,' @ approx ', 7, ' days')

    # question 1e.)
    '''
    (e) Suppose now that in the absense of predators, the limiting capacity of
    the environment for the prey is 10 (thousand). Add a suitable logistic term
    to the model above, solve the model using ode45 for a long enough time to
    estimate the behaviour of the two populations as t -> inf. Plot the result on a
    new figure.
    '''
    """
    NOTE: the folowing code does not converge accordingly, still needs some
          debuging
    """
    t = np.arange(0, 1000, 5/10.0)
    f = lambda x, t: (-3*x[0] + 3*x[0]*x[1], x[1]-2*x[1]*x[0]-(1./10.)*x[1])
    x0 = [0.3, 1.0]
    odeint_sol = scipy.integrate.odeint(f, x0, t)

    plot_graph_Q1e(odeint_sol, t)

else:
    exit('USAGE: python problem1.py')


import numpy as np
from src.unconstrained_min import line_search

def f_1(x, hessian = False):
    Q = np.array([[1, 0], [0, 1]])
    f_x = np.matmul(x, np.matmul(Q, x))
    df_x = np.array(2*x)
    if hessian:
        H = Q * 2
        return f_x, df_x, H
    return f_x, df_x

def f_2(x, hessian = False):
    Q = np.array([[5, 0], [0, 1]])
    f_x = np.matmul(x, np.matmul(Q, x))
    df_x = np.matmul(Q, x)*2
    if hessian:
        H = Q*2
        return f_x, df_x, H
    return f_x, df_x

def f_3(x, hessian = False):
    sqr_3 = np.sqrt(3)
    b_matrix = np.array([[5, 0], [0, 1]])
    a_matrix = np.array([[sqr_3/2, -0.5], [0.5, sqr_3/2]])
    Q = np.matmul(np.matmul(a_matrix.transpose(), b_matrix), a_matrix)
    f_x = np.matmul(x, np.matmul(Q, x))
    df_x = np.matmul(Q+np.transpose(Q), x)
    if hessian:
        H = Q + np.transpose(Q)
        return f_x, df_x, H
    return f_x, df_x

def Rosenbrock(x, hessian = False):
    f_x = 100*((x[1] - x[0]**2)**2) + (1 - x[0])**2
    pd_f_x1 = -400*(x[1] -x[0]**2)*x[0] - 2*(1 - x[0])
    pd_f_x2 = 200*(x[1] -x[0]**2)
    df_x = np.array([pd_f_x1, pd_f_x2])
    if hessian:
        H = np.array([[1200*x[0]**2-400*x[1] + 2, -400*x[0]],
                      [-400*x[0], 200]])
        return f_x, df_x, H
    return f_x, df_x

def f_linear(x, hessian = False):
    a = [2, 3]
    f_x = np.dot(a, x)
    df_x = np.array(a)
    if hessian:
        pass
    return f_x, df_x

def min_obj_lp(x):
    f_x = x[0] + x[1]
    df_x = np.array([1, 1])
    hessian_x = np.zeros((2, 2))
    return f_x, df_x, hessian_x

def obj_lp(x):
    f_x = -x[0] -x[1]
    df_x = np.array([-1, -1])
    hessian_x = np.zeros((2, 2))
    return f_x, df_x, hessian_x

def lp_ineq_1(x):
    f_x = -x[0]-x[1] + 1
    df_x = np.array([-1, -1])
    hessian_x = np.zeros((2, 2))
    return f_x,  df_x, hessian_x

def lp_ineq_2(x):
    f_x = x[1] - 1
    df_x = np.array([0, 1])
    hessian_x = np.zeros((2, 2))
    return f_x,  df_x, hessian_x

def lp_ineq_3(x):
    f_x = x[0] - 2
    df_x = np.array([1, 0])
    hessian_x = np.zeros((2, 2))
    return f_x,  df_x, hessian_x

def lp_ineq_4(x):
    f_x = -x[1]
    df_x = np.array([0, -1])
    hessian_x = np.zeros((2, 2))
    return f_x,  df_x, hessian_x

def obj_qp(x):
    fx = x[0]**2 + x[1]**2 + (x[2]+1)**2
    dfx = np.array([2*x[0], 2*x[1], 2*(x[2]+1)])
    hessian = np.array([[2,0,0],[0,2,0],[0,0,2]])
    return fx, dfx, hessian

def qp_ineq_1(x):
    fx = -x[0]
    dfx = np.array([-1,0,0])
    hessian = np.zeros((3,3))
    return fx, dfx, hessian

def qp_ineq_2(x):
    fx = -x[1]
    dfx = np.array([0, -1, 0])
    hessian = np.zeros((3, 3))
    return fx, dfx, hessian

def qp_ineq_3(x):
    fx = -x[2]
    dfx = np.array([0, 0, -1])
    hessian = np.zeros((3, 3))
    return fx, dfx, hessian


import numpy as np
import matplotlib.pyplot as plt

def ode_FE(f, U_0, dt, T):
    N_t = int(round(T/dt))
    u = np.zeros(N_t+1)
    t = np.linspace(0, N_t*dt, len(u))
    u[0] = U_0
    for n in range(N_t):
        u[n+1] = u[n] + dt*f(u[n], t[n])
    return u, t

def demo_population_growth():
    """Test case: u'=r*u, u(0)=100."""
    def f(u, t):
        return 0.1*u

    u, t = ode_FE(f=f, U_0=100, dt=0.5, T=20)
    plt.plot(t, u, t, 100*np.exp(0.1*t))
    plt.show()

if __name__ == '__main__':
    demo_population_growth()


'''
    Problem 72 - Counting fractions

    Consider the fraction, n/d, where n and d are positive integers.
    If n<d and HCF(n,d)=1, it is called a reduced proper fraction.

    If we list the set of reduced proper fractions for d ≤ 8 in ascending order of size, we get:

        1/8, 1/7, 1/6, 1/5, 1/4, 2/7, 1/3, 3/8, 2/5, 3/7, 1/2, 4/7, 3/5, 5/8, 2/3, 5/7, 3/4, 4/5, 5/6, 6/7, 7/8

        It can be seen that there are 21 elements in this set.

    How many elements would be contained in the set of reduced proper fractions for d ≤ 1,000,000 ?

'''
'''
    Solution : It can be seen that the solution is:
        sum(phi(i)) for i in range(2, 1000001)

    We can use Euler's formula and a seive to compute it easily

'''
N = 10**6
# import numpy as np
# arr = np.arange(N+1)
# print(arr.shape)

arr = [i for i in range(N + 1)]
result = 0
for i in range(2, N + 1):
    if arr[i] == i:
        for j in range(i, N + 1, i):
            arr[j] = (arr[j] // i) * (i - 1)
    result += arr[i]

print(result)


"""
TODO finish the documentation once you are completely sure how it all works

REMEMBER TO MENTION COLUMN MAJOR!

@author G. Eli Jergensen <gelijergensen@ou.edu> - constructed following the
    paper by Stephen Liwicki et. al
"""

from abc import ABC, abstractmethod
import numpy as np

class Difference(ABC):

    @abstractmethod
    def getMatrix(self, n):
        """Returns the difference matrix of a particular size

        :param n: the dimension of the square matrix to return
        :returns: an (n by n) matrix
        """
        pass

class BackwardDifference(Difference):

    def getMatrix(self, n):
        """Backward difference subtracts the previous data point from the
        current

        :param n: the size of the square matrix to return
        :returns: an (n by n) real matrix
        """
        D = np.identity(n) - np.eye(n, k=1)
        D[0, 0] = 0
        return D

class ForwardDifference(Difference):

    def getMatrix(self, n):
        """Forward difference subtracts the current data point from the next

        :param n: the size of the square matrix to return
        :returns: an (n by n) real matrix
        """
        D = np.eye(n, k=-1) - np.identity(n)
        D[-1, -1] = 0
        return D

class CentralDifference(Difference):

    def getMatrix(self, n):
        """Forward difference subtracts half the previous data point from half
        of the next

        :param n: the size of the square matrix to return
        :returns: an (n by n) real matrix
        """
        D = np.eye(n, k=-1) - np.eye(n, k=1)
        D *= 0.5
        return D


# Print Z
# Description
# Given a single positive integer 'n' greater than 2, create a NumPy array of size (n x n) will all zeros and ones such that the ones make a shape like 'Z'.
# Examples:
# Input 1:
# 3
# Output 1:
# [[1 1 1]
#  [0 1 0]
#  [1 1 1]]
# Input 2:
# 5
# Output 1:
# [[1 1 1 1 1]
#  [0 0 0 1 0]
#  [0 0 1 0 0]
#  [0 1 0 0 0]
#  [1 1 1 1 1]]
# Explanation: Notice that the 1s in the array make a shape like 'Z'.

# Read the input
n = int(input())

# Import the NumPy package
import numpy as np

arr =np.zeros((n,n), dtype = int)

arr[0] = np.ones(1, dtype  = int)
arr[-1] = np.ones(1, dtype  = int)
for i in range(1, n):
    arr[i][n-i-1] = 1
print(arr)


"""

"""

import numpy as np

def generate_primes(n=1000):
	primes = []
	prime_flags = [0]*(n+1)
	for prime in xrange(2, n):
		if prime_flags[prime] == 0:
			primes.append(prime)
		else:
			continue
		mult = 2
		while mult*prime < n:
			prime_flags[mult*prime] = 1
			mult += 1
	return primes

def gen_rotations(val):
	txtval = str(val)
	out = [val]
	for i in xrange(len(txtval)-1):
		txtval += txtval[0]
		txtval = txtval[1:]
		out.append(int(txtval))
	return tuple(set(out))

primes = generate_primes(1000000)
found_circs = []

def is_circular_prime(num):
	global primes
	rots = gen_rotations(num)
	for va in rots:
		if va not in primes:
			return False, None
	return True, rots

for num in primes:
	if num in found_circs:
		continue
	test, rots = is_circular_prime(num)
	if test:
		found_circs += rots

print("Total of %d circular primes" % len(found_circs))
print("Found:")
print(found_circs) # 55


import numpy as np
from tdma import *

def calc_temps_vector(a, b, c, d, tau, temps, la, n_coeffs):
    """
    Calculate the coefficient array for the TDMA solver and calculate temperature

    :param a: a vector of length n_coeffs (empty)
    :param b: b vector of length n_coeffs
    :param c: c vector of length n_coeffs
    :param d: d vector of length n_coeffs
    :param tau: time array
    :param temps: temperature array of dimensions (num_depths x num_times)
    :param la: lambda from paper
    :param n_coeffs: number of coefficients (depths - 2)
    :return: temps
    """
    ## 2. Finding the coefficents for a, b, c, d for each timestep
    for i, t in enumerate(tau[1:-1]):
        Temp_idx = i + 1

        # Loop through coefficients
        for depth in np.arange(n_coeffs):
            a[depth] = -la
            b[depth] = 1 + 2 * la
            c[depth] = -la
            d[depth] = temps[depth+1, Temp_idx-1]

        d[0] += la * temps[0, Temp_idx]
        d[-1] += la * temps[-1, Temp_idx]

        # Solve for temperature
        temps[1:-1, Temp_idx] = TDMAsolver(a[1:], b, c[:-1], d)

    return temps

def temp_surface(tau, T_bar, A):
    """
    Calculate temperature at soil surface (z=0)

    :param tau: Times in seconds
    :param T_bar: Scalar value of mean temperature
    :param A: Amplitude of sine array
    :return: 1D array of temperatures
    """

    omega = (2 * np.pi) / (86400)
    T = T_bar + A * np.sin(omega * tau)  # + np.pi/2 for time offset

    return T

def temp_analytical(tau_x, depth_y, T_bar, A, kap):
    """
    Calculate analytical solution for certain times and depth in a 2D array

    :param tau: 2D array of times (time on axis=1)
    :param depths: 2D array of depths (depth on axis=0)
    :param T_bar: Scalar value of the mean temperature
    :param A: Amplitude of temperature sine wave
    :param kap: Soil
    :return: 2D array of temperatures
    """
    p = 24
    w = (2 * np.pi) / (p * 3600)
    D = np.sqrt((2 * kap) / w)

    # correct ts and z_prof to make proper 2d graph
    temps = np.zeros(tau_x.shape)

    # calculate profile
    temps = T_bar + A * np.exp(depth_y / D) * np.sin(w * tau_x + depth_y / D)

    return temps


"""
tanh
~~~~

Plots a graph of the tanh function."""

import numpy as np
import matplotlib.pyplot as plt

z = np.arange(-5, 5, .1)
t = np.tanh(z)

fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(z, t)
ax.set_ylim([-1.0, 1.0])
ax.set_xlim([-5,5])
ax.grid(True)
ax.set_xlabel('z')
ax.set_title('tanh function')

plt.show()


from sympy.vector import CoordSys3D
from symplyphysics import (
    symbols, Function, Eq, pretty, cos, pi
)
from symplyphysics.laws.nuclear.buckling import geometric_buckling_from_neutron_flux
from symplyphysics.laws.nuclear.buckling import neutron_flux_for_uniform_slab

# Description
## Neutron flux formula for the uniform rectangular parallelepiped reactor of physical dimensions a * b * c.
## The parallelepiped reactor is situated in cartesian geometry at the origin of coordinates.

## Law: Ф(x, y, z) = C1 * cos(Pi * x / a) * cos(Pi * y / b) * cos(Pi * z / c)
## Where:
## C1 - neutron flux power constant.
## Pi - Pi constant.
## x, y, z - distances (width, length, height) from the center of parallelepiped.
## a - width of the parallelepiped.
## b - length of the parallelepiped.
## c - height of the parallelepiped.
## Ф(x, y, z) - neutron flux density.

neutron_flux_power_constant = symbols('C1', constant=True)
x_distance_from_center = symbols('x_distance_from_center')
y_distance_from_center = symbols('y_distance_from_center')
z_distance_from_center = symbols('z_distance_from_center')
parallelepiped_width = symbols('parallelepiped_width')
parallelepiped_length = symbols('parallelepiped_length')
parallelepiped_height = symbols('parallelepiped_height')
neutron_flux_function = symbols('neutron_flux_function', cls = Function)

# These constants are being used for geometric buckling calculation
# See: [geometric buckling for uniform parallelepiped](geometric_buckling_for_uniform_parallelepiped.py)
width_constant = pi / parallelepiped_width
length_constant = pi / parallelepiped_length
height_constant = pi / parallelepiped_height

# derived the same way as uniform slab axial_constant
assert width_constant == neutron_flux_for_uniform_slab.axial_constant.subs(
    neutron_flux_for_uniform_slab.slab_width, parallelepiped_width)
assert length_constant == neutron_flux_for_uniform_slab.axial_constant.subs(
    neutron_flux_for_uniform_slab.slab_width, parallelepiped_length)
assert height_constant == neutron_flux_for_uniform_slab.axial_constant.subs(
    neutron_flux_for_uniform_slab.slab_width, parallelepiped_height)

law = Eq(neutron_flux_function(x_distance_from_center, y_distance_from_center, z_distance_from_center),
    neutron_flux_power_constant *
    cos(width_constant * x_distance_from_center) *
    cos(length_constant * y_distance_from_center) *
    cos(height_constant * z_distance_from_center))

# Check the solution by passing the known neutron flux to the geometric_buckling_from_neutron_flux.
# Neutron flux is a function of x, y, z in the cartesian coordinates.

# Boundary conditions:
# - vacuum boundary condition: Ф(a + d) = Ф(ae) = Ф(b + d) = Ф(be) = Ф(c + d) = Ф(ce) = 0
# - finite flux condition: 0 <= Ф(x, y, z) < ∞
# - interface condition: the neutron flux and the normal component of the neutron current must be continuous
# - source condition: all neutrons flowing through the bounding area of the source must come from the neutron source

# define flux function in cylindrical coordinates as a function of cylinder radius and height
cartesian_coordinates = CoordSys3D('cartesian_coordinates')
neutron_flux_function_cartesian = law.subs({
    x_distance_from_center: cartesian_coordinates.x,
    y_distance_from_center: cartesian_coordinates.y,
    z_distance_from_center: cartesian_coordinates.z})

solved = geometric_buckling_from_neutron_flux.apply_neutron_flux_function(neutron_flux_function_cartesian.rhs)

# check with the derived law: Bg^2 = width_constant**2 + length_constant**2 + height_constant**2
assert solved.rhs == (width_constant**2 + length_constant**2 + height_constant**2)

def print():
    return pretty(law, use_unicode=False)

# There is no calculate() method. Neutron flux is usually being used internally to pass to other laws.


import numpy as np
from numpy.linalg import inv

data = np.loadtxt("data/OneFeature.txt", delimiter=",", unpack=True)  # Output is 1D. Vectors are 2D m x 1 dimension so need to change to 2D using reshape

y = data[-1].reshape((data.shape[1], 1))  # Makes y a vector with each new line different training set

onesVector = np.ones((data.shape[1], 1))  # Creates an m dimensional vector of 1s
X = np.concatenate((onesVector, data[:-1].T), axis=1)  # Creates matrix X, where each new line is a different training example, where x0 on each line is 1

theta = inv((X.T.dot(X))).dot(X.T).dot(y) #Normal Equation

print("Theta = ", theta)

Linear Regression using Normal Equation.py


import numpy as np
import pandas as pd

def f(x):
    return np.sqrt(x) - 2 * np.cos(x)

def y(x:float, c:float):
    return c * np.exp(-x) + x**2 * np.sin(x)

def golden_selection_method(p:float = 3, q:float = 8, eps:float = .001):

    calculations = pd.DataFrame(data={'n': [], 'p': [], 'q': [], 'x1': [], 'x2': [], 'f(x1)': [],
                                            'f(x2)': [], 'p-q': []})
    K = [(3 - np.sqrt(5)) * 0.5, (np.sqrt(5) - 1) * 0.5]
    x = [p + K[0] * (q - p), p + K[1] * (q - p)]

    with open('points.txt', 'w') as file:
        pass
    iter = 0
    y = [f(_) for _ in x]
    while abs(q - p)/2 >= eps:
        if y[0] < y[1]:
            q = x[1]
            x[1] = x[0]
            x[0] =  p + K[0] * (q - p)
            y[1], y[0] = y[0], f(x[0])
        else:
            p = x[0]
            x[0] = x[1]
            x[1] = p + K[1] * (q - p)
            y[0], y[1] = y[1], f(x[1])
        iter += 1
        with open('points.txt', 'a') as file:
            file.write(str(q) + " " + str(p) + "\n")
        temp_calc = pd.DataFrame(data={'n': [iter], 'p': [p], 'q': [q], 'x1': [x[0]], 'x2': [x[1]], 'f(x1)': [f(x[0])],
                                            'f(x2)': [f(x[1])], 'p-q': [abs(p-q)]})
        calculations = pd.concat([calculations, temp_calc], ignore_index=True)

    calculations = np.round(calculations, 4)
    calculations.to_excel(f"golden_selection_method.xlsx")
    final_x = (p + q) / 2 #Абцисса точки минимума
    return final_x

def simpson_method(a:float, b:float, x_min:float, eps:float = .001):
    n = 2 #Количество разбиений отрезка интегрирования
    h = (b - a)/n
    s = (y(a, x_min) + 4 * y((a+b) / 2, x_min) + y(b, x_min)) * h/3    #Значение интеграла

    calc_simpson = pd.DataFrame({'n': [n], 'h': [h], 's': [s]})

    while True:
        n = 2 * n  #Увеличение разбиение отрезка интегрирования
        h = (b - a) / n #Шаг
        s1 = 0
        for i in range(1, n):
            s1 += (2 + i%2 * 2) * y(a + h * i, x_min) #Центральные точки
        s1 = s1 + y(a, x_min) + y(b, x_min) #Крайние точки
        s1 *= h/3

        calc_temp = pd.DataFrame({'n': [n], 'h': [h], 's': [s1]})
        calc_simpson = pd.concat([calc_simpson, calc_temp], ignore_index=True)

        if abs(s - s1) < eps:
            calc_simpson = np.round(calc_simpson, 4)
            calc_simpson.to_excel(f'simpson_method.xlsx')
            return s1
        s = s1

x_min = golden_selection_method()
print(f'С= {round(x_min, 4)}')
print('integral y(x)=', round(simpson_method(1, 3, x_min), 4))


import numpy
from algopy import CGraph, Function, UTPM, dot, qr, eigh, inv, solve

# first order derivatives, one directional derivative
# D - 1 is the degree of the Taylor polynomial
# P directional derivatives at once
# M number of rows of A
# N number of cols of A
D,P,M,N = 2,1,5,2

# generate badly conditioned matrix A
A = UTPM(numpy.zeros((D,P,M,N)))
x = UTPM(numpy.zeros((D,P,M,1)))
y = UTPM(numpy.zeros((D,P,M,1)))

x.data[0,0,:,0] = [1,1,1,1,1]
x.data[1,0,:,0] = [1,1,1,1,1]

y.data[0,0,:,0] = [1,2,1,2,1]
y.data[1,0,:,0] = [1,2,1,2,1]

alpha = 10**-5
A = dot(x,x.T) + alpha*dot(y,y.T)

A = A[:,:2]

# Method 1: Naive approach
Apinv = dot(inv(dot(A.T,A)),A.T)

print('naive approach: A Apinv A - A = 0 \n', dot(dot(A, Apinv),A) - A)
print('naive approach: Apinv A Apinv - Apinv = 0 \n', dot(dot(Apinv, A),Apinv) - Apinv)
print('naive approach: (Apinv A)^T - Apinv A = 0 \n', dot(Apinv, A).T  - dot(Apinv, A))
print('naive approach: (A Apinv)^T - A Apinv = 0 \n', dot(A, Apinv).T  - dot(A, Apinv))

# Method 2: Using the differentiated QR decomposition
Q,R = qr(A)
tmp1 = solve(R.T, A.T)
tmp2 = solve(R, tmp1)
Apinv = tmp2

print('QR approach: A Apinv A - A = 0 \n',  dot(dot(A, Apinv),A) - A)
print('QR approach: Apinv A Apinv - Apinv = 0 \n', dot(dot(Apinv, A),Apinv) - Apinv)
print('QR approach: (Apinv A)^T - Apinv A = 0 \n', dot(Apinv, A).T  - dot(Apinv, A))
print('QR approach: (A Apinv)^T - A Apinv = 0 \n', dot(A, Apinv).T  - dot(A, Apinv))

# Method 3: Stable evaluation of the analytical derivative formula

A0 = A.data[0,0]
A1 = A.data[1,0]

Q0, R0 = numpy.linalg.qr(A0)

# compute nominal solution
tmp1 = solve(R0.T, A0.T)
C0 = solve(R0, tmp1)

# compute first directional derivative
tmp2 = A1.T - dot( dot(A1.T, A0) + dot(A0.T, A1), C0)
tmp1 = solve(R0.T, tmp2)
C1 = solve(R0, tmp1)

Apinv.data[0,0] = C0
Apinv.data[1,0] = C1

print('analytical approach: A Apinv A - A = 0 \n',  dot(dot(A, Apinv),A) - A)
print('analytical approach: Apinv A Apinv - Apinv = 0 \n', dot(dot(Apinv, A),Apinv) - Apinv)
print('analytical approach: (Apinv A)^T - Apinv A = 0 \n', dot(Apinv, A).T  - dot(Apinv, A))
print('analytical approach: (A Apinv)^T - A Apinv = 0 \n', dot(A, Apinv).T  - dot(A, Apinv))


#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# Author: lionel

import numpy as np

class InformationGain(object):
    # 计算香农熵
    def calcShannonEnt(self, data):
        m, n = np.shape(data)
        labelCounts = {}
        for i in range(m):
            currentLabel = data[i][-1]
            if currentLabel not in labelCounts:
                labelCounts[currentLabel] = 0
            labelCounts[currentLabel] += 1
        shannonEnt = 0.0
        for key in labelCounts:
            prob = labelCounts[key] / m
            shannonEnt -= prob * np.log2(prob)
        return shannonEnt

    def splitData(self, data, axis, value):
        retData = []
        m, n = np.shape(data)
        for i in range(m):
            if data[i][axis] == value:
                reducedFeatVec = np.delete(data[i], axis, axis=0)
                retData.append(reducedFeatVec)
        return np.array(retData)

    def chooseBestFeatureToSplit(self, data):
        m, n = np.shape(data)
        # 特征个数
        numFeatures = n - 1
        baseEntropy = self.calcShannonEnt(data)
        bestInfoGain = 0.0
        bestFeature = -1
        for i in range(numFeatures):
            featureValues = [data[j][i] for j in range(m)]
            uniqueValues = set(featureValues)
            newEntropy = 0.0
            for value in uniqueValues:
                subData = self.splitData(data, i, value)
                prob = len(subData) / m
                newEntropy += prob * self.calcShannonEnt(subData)
            infoGain = baseEntropy - newEntropy
            if infoGain > bestInfoGain:
                bestInfoGain = infoGain
                bestFeature = i
        return bestFeature

if __name__ == '__main__':
    informationGain = InformationGain()
    arr = [[-1, -1, 0, 0],
           [-1, 1, 1, 1],
           [1, 0, 1, 1],
           [0, 0, 1, 1],
           [1, 0, 1, 1],
           [0, 1, 0, 1],
           [0, -1, 0, 0],
           [1, 0, 0, 1],
           [0, -1, 0, 1],
           [-1, -1, 1, 0]]
    features = ['no surfaceing', 'flippers']
    arr = [[1, 1, 1],
           [1, 1, 1],
           [1, 0, 0],
           [0, 1, 0],
           [0, 1, 0]]
    data = np.array(arr)
    print(informationGain.chooseBestFeatureToSplit(data))


import numpy as np
import matplotlib.pyplot as plt

mu = 0.5
sigma = 0.1

#Gerando distribuição normal com 1000 elementos
normal_dist = np.random.normal(mu, sigma, 1000)

#Graficando dados num histograma com n_bins
n_bins = 20
count, bins, ignored = plt.hist(normal_dist, n_bins, normed=True,color='red')

#Calculando gaussiana através dos dados
gaussiana = 1/(sigma*np.sqrt(2*np.pi))*np.exp(-(bins-mu)**2/(2*sigma**2))

plt.plot(bins,gaussiana,linewidth=3, color='blue')
plt.xlabel('Intervalo')
plt.ylabel('Contagem')
plt.title('Distribuição normal')

plt.show()


import numpy as np
import scipy.special as sp
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import axes3d
from matplotlib.widgets import TextBox,Button

class Bessel:
    def _numerator(self,p,v,x):
        return ((-1)**p)*((x/2)**(2*p+v))

    def _denominator(self,p,v):
        return sp.gamma(p+1)*sp.gamma(p+v+1)

    def bessel_of_first_kind(self,v,x):
        _sum = 0
        for p in range(0,110,1):
            _sum += self._numerator(p,v,x)/self._denominator(p,v)
        return _sum

bessel=Bessel()

def plot_2D(graph_axes,fig,v):
    x = np.linspace(0, 30, 1000)
    graph_axes.plot(x,bessel.bessel_of_first_kind(v,x))
    plt.draw()

def plot_3D():
    x = np.linspace(0, 20, 100)
    y = np.linspace(0, 20, 100)

    x, y = np.meshgrid(x, y)

    z=bessel.bessel_of_first_kind(y,x)

    fig = plt.figure(figsize=(15,10))
    ax = fig.add_subplot(111,projection='3d')

    h = ax.plot_surface(x, y, z, cmap='jet',edgecolor='k')
    plt.colorbar(h)

    ax.set_xlabel('X',fontweight='bold')
    ax.set_ylabel('Y',fontweight='bold')
    ax.set_zlabel('Z',fontweight='bold')

    plt.show()

def main():

    def onButtonClearClicked(event):
        graph_axes.clear()
        graph_axes.grid()
        graph_axes.set_xlabel('x')
        graph_axes.set_ylabel('${J}_n(x)$')
        graph_axes.set_xlim([0,30])
        graph_axes.set_ylim([-1.1,1.1])
        plt.draw()

    def onButton3DClicked(event):
        plot_3D()

    def submit(text):
        val=eval(text)
        plot_2D(graph_axes,fig,val)

    fig, graph_axes = plt.subplots()
    graph_axes.grid()
    graph_axes.set_xlabel('x')
    graph_axes.set_ylabel('${J}_n(x)$')
    graph_axes.set_xlim([0,30])
    graph_axes.set_ylim([-1.1,1.1])
    fig.subplots_adjust(left=0.13, right=0.95, top=0.95, bottom=0.4)

    axes_button_clear = plt.axes([0.05, 0.10, 0.4, 0.075])
    button_clear = Button(axes_button_clear, 'Очистить')
    button_clear.on_clicked(onButtonClearClicked)

    axes_button_3D = plt.axes([0.55, 0.10, 0.4, 0.075])
    button_3D = Button(axes_button_3D, '3D')
    button_3D.on_clicked(onButton3DClicked)

    axes_textbox = plt.axes([0.13, 0.20, 0.85, 0.08])
    text_box = TextBox(axes_textbox,'Порядок',initial=0)
    text_box.on_submit(submit)

    plt.show()

if __name__=='__main__':
    main()


import numpy as np
x = np.arange(6)
y = np.array([2,8,14,28,39,62], float)
m = len(x)
n = 1
A = np.zeros((n+1,n+1))
B = np.zeros(n+1)
a = np.zeros(n+1)
for  row in range(n+1):
    for col in range(n+1):
       if row == 0 and col == 0:
           A[row,col] = m
           continue
       A[row, col] = np.sum(x**(row+col))
    B[row] = np.sum(x**row * y)
a = np.linalg.solve(A, B)
print('The polynomial :')
print('f(x) = \t %.3f'%a[0])
for i in range(1, n+1):
    print('\t %+.3f x^%d' % (a[i],i))


from random import *
from math import *
from matplotlib.pyplot import *
from numpy import *

# Parameters
a = 1
b = 10
c = 7

def cdf(x):
    if x <= a:
        return 0
    elif x > a and x <= c:
        return (x-a)**2 / ((b-a)*(c-a))
    elif x > c and x < b:
        return 1 - ( (b-x)**2 / ((b-a)*(b-c)) )
    elif x >= b:
        return 1
    else:
        print("Error")

def pdf(x):
    if x < a:
        return 0
    elif x >= a and x < c:
        return (2 * (x-a)) / ((b-a)*(c-a))
    elif x == c:
        return 2 / (b-a)
    elif x > c and x <= b:
        return (2 * (b-x)) / ((b-a)*(b-c))
    elif x > b:
        return 0
    else:
        print("Error")

X = arange(0, b+1, 0.1)
Y = []

for x in X:
    Y.append(pdf(x))

matplotlib.rc('xtick', labelsize=18)
matplotlib.rc('ytick', labelsize=18)
plot(X, Y, Linewidth=2, color='black')
xlabel('$X$', size=22)
ylabel('$f_X(x)$', size=22)
#show()
savefig('triangular_pdf.pdf', format='pdf', bbox_inches='tight')

# Clear the current figure
clf()

X = arange(0, b, 0.1)
Y = []

for x in X:
    Y.append(cdf(x))

matplotlib.rc('xtick', labelsize=18)
matplotlib.rc('ytick', labelsize=18)
plot(X, Y, Linewidth=2, color='black')
xlabel('$X$', size=22)
ylabel('$F_X(x)$', size=22)
#show()
savefig('triangular_cdf.pdf', format='pdf', bbox_inches='tight')


# -*- coding: utf-8 -*-
"""
Copyright (c) 2020, University of Southampton
All rights reserved.
Licensed under the BSD 3-Clause License.
See LICENSE.md file in the project root for full license information.
"""

import random

import numpy as np

from oplab import Console

def augment(xyzs):
    axyz = np.ones((len(xyzs), 4))
    axyz[:, :3] = xyzs
    return axyz

def fit_plane(xyzs):
    axyz = augment(xyzs[:3])
    m = np.linalg.svd(axyz)[-1][-1, :]
    if m[0] < 0:
        m = m * (-1)
    return m

def is_inlier(coeffs, xyz, threshold):
    return np.abs(coeffs.dot(augment([xyz]).T)) < threshold

def run_ransac(
    data,
    estimate,
    is_inlier,
    sample_size,
    goal_inliers,
    max_iterations,
    stop_at_goal=True,
    random_seed=None,
):
    best_ic = 0
    best_model = None
    random.seed(random_seed)
    # random.sample cannot deal with "data" being a numpy array
    data = list(data)
    for i in range(max_iterations):
        inliers = []
        s = random.sample(data, int(sample_size))
        m = fit_plane(s)
        ic = 0
        for j in range(len(data)):
            if is_inlier(m, data[j]):
                ic += 1
                inliers.append(data[j])

        # print(s)
        # print('estimate:', m,)
        # print('# inliers:', ic)

        if ic > best_ic:
            best_ic = ic
            best_model = m
            if ic > goal_inliers and stop_at_goal:
                break
    # estimate final model using all inliers
    best_model = fit_plane(inliers)
    return best_model, inliers, i

def bounding_box(iterable):
    print(iterable.shape)
    min_x, min_y = np.min(iterable, axis=0)
    max_x, max_y = np.max(iterable, axis=0)
    return min_x, max_x, min_y, max_y

def plot_plane(a, b, c, d):
    yy, zz = np.mgrid[-6:7, 4:15]
    return (-d - c * zz - b * yy) / a, yy, zz

def plane_fitting_ransac(
    cloud_xyz,
    min_distance_threshold,
    sample_size,
    goal_inliers,
    max_iterations,
    plot=False,
):
    model, inliers, iterations = run_ransac(
        cloud_xyz,
        fit_plane,
        lambda x, y: is_inlier(x, y, min_distance_threshold),
        sample_size,
        goal_inliers,
        max_iterations,
    )
    a, b, c, d = model
    if plot:
        import matplotlib.pyplot as plt
        from mpl_toolkits.mplot3d import Axes3D

        fig = plt.figure()
        ax = Axes3D(fig)
        # min_x, max_x, min_y, max_y = bounding_box(cloud_xyz[:, 0:2])
        xx, yy, zz = plot_plane(a, b, c, d)  # , min_x, max_x, min_y, max_y)
        ax.plot_surface(xx, yy, zz, color=(0, 1, 0, 0.5))
        ax.scatter3D(cloud_xyz.T[0], cloud_xyz.T[1], cloud_xyz.T[2], s=1)
        ax.set_xlabel("$X$")
        ax.set_ylabel("$Y$")
        ax.set_zlabel("$Z$")
        plt.show()
    Console.info(
        "RANSAC took",
        iterations + 1,
        " iterations. Best model:",
        model,
        "explains:",
        len(inliers),
    )
    return (a, b, c, d), inliers

if __name__ == "__main__":
    N_POINTS = 100
    GOAL_INLIERS = N_POINTS * 0.8
    MAX_ITERATIONS = 100

    TARGET_A = 1.0
    TARGET_B = 0.000001
    TARGET_C = 0.000001
    TARGET_D = -1.5
    EXTENTS = 10.0
    NOISE = 0.1

    # create random data
    xyzs = np.zeros((N_POINTS, 3))
    xyzs[:, 0] = [
        np.random.uniform(2 * EXTENTS) - EXTENTS for i in range(N_POINTS)
    ]
    xyzs[:, 1] = [
        np.random.uniform(2 * EXTENTS) - EXTENTS for i in range(N_POINTS)
    ]
    for i in range(N_POINTS):
        xyzs[i, 2] = (
            -TARGET_D - xyzs[i, 0] * TARGET_A - xyzs[i, 1] * TARGET_B
        ) / TARGET_C + np.random.normal(scale=NOISE)

    # RANSAC
    m, inliers = plane_fitting_ransac(
        xyzs, 0.01, 3, GOAL_INLIERS, MAX_ITERATIONS, plot=True
    )
    scale = TARGET_D / m[3]
    print(np.array(m) * scale)
    print("Inliers: ", len(inliers))

    # [a, b, c, d, plane_angle, pitch_angle, yaw_angle] = fit_plane(xyzs)
    # print(a, b, c, d)
    # print(plane_angle, pitch_angle, yaw_angle)

    # mean_x = np.mean(xyzs[:, 0])
    # mean_y = np.mean(xyzs[:, 1])
    # mean_z = np.mean(xyzs[:, 2])
    # mean_xyz = np.array([mean_x, mean_y, mean_z])

    # plane, normal, offset = build_plane(pitch_angle, yaw_angle, mean_xyz)

    # print(plane)
    # print(normal)
    # print(offset)


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

# ## Exercises
#
# This will be a notebook for you to work through the exercises during the workshop. Feel free to work on these at whatever pace you feel works for you, but I encourage you to work together! Edit the title of this notebook with your name because I will ask you to upload your final notebook to our shared github repository at the end of this workshop.
#
# Feel free to google the documentation for numpy, matplotlib, etc.
#
# Don't forget to start by importing any libraries you need.

# In[2]:

# import your libraries here
import numpy as np #'import' loads up the package.
#you can use 'as' to define a shortcut so you don't need to type
#numpy before every use of the package. Most people use 'np'.

import astropy

import matplotlib.pyplot as plt

from scipy import integrate #'from' allows you to import a specific sub-package

# ### Day 1
#
# #### Exercise 1
#
#    A. Create an array with 10 evenly spaced values in logspace ranging from 0.1 to 10,000.
#
#    B. Print the following values: The first value in the array, the final value in the array, and the range of 5th-8th values.
#
#    C. Append the numbers 10,001 and 10,002 (as floats) to the array. Make sure you define this!
#
#    D. Divide your new array by 2.
#
#    E. Reshape your array to be 3 x 4.
#
#    F. Multiply your array by itself.
#
#    G.  Print out the number of dimensions and the maximum value.

# In[10]:

# your solution here
#A
long_logarray = np.logspace(np.log10(.1), np.log10(10000), 10)
print(long_logarray)
#B
first_val=long_logarray[0]
fin_val=long_logarray[-1]
bw_5_8=long_logarray[5:8]
print(first_val,fin_val,bw_5_8)
#C
appended_log=[long_logarray, [10001,10002]]
print(appended_log)
#D
print(long_logarray/2)
#E
reshaped_log=(long_logarray/2).reshape(2,5)#Can not reshape to (3,4) because this array is size 10
print(reshaped_log)
#F
print((reshaped_log)*(reshaped_log))
#G
numDim=reshaped_log.ndim
maxVal=np.max(reshaped_log)
print(numDim, maxVal)

# ### Day 2

# #### Exercise 1
#
#    A. Create an array containing the values 4, 0, 6, 5, 11, 14, 12, 14, 5, 16.
#    B. Create a 10x2 array of zeros.
#    C. Write a for loop that checks if each of the numbers in the first array squared is less than 100. If the statement is true, change that row of your zeros array to equal the number and its square. Hint: you can change the value of an array by stating "zerosarray[i] = [a number, a number squared]".
#    D. Print out the final version of your zeros array.
#
# Hint: should you loop over the elements of the array or the indices of the array?

# In[ ]:

# your solutions here

# #### Exercise 2
#
#    A. Write a function that takes an array of numbers and spits out the Gaussian distribution. Yes, there is a function for this in Python, but it's good to do this from scratch! This is the equation:
#
# $$ f(x) = \frac{1}{\sigma \sqrt{2\pi}} \exp{\frac{-(x - \mu)^2}{2\sigma^2}} $$
#
#     (Pi is built into numpy, so call it as np.pi.)
#
#    B. Call the function a few different times for different values of mu and sigma, between -10 < x < 10.
#
#    C. Plot each version, making sure they are differentiated with different colors and/or linestyles and include a legend. Btw, here's a list of the customizations available in matplotlib:
#
#     https://matplotlib.org/3.1.0/api/_as_gen/matplotlib.pyplot.plot.html
#
#     https://matplotlib.org/gallery/color/named_colors.html
#
#    D. Save your figure.
#
# If you have multiple lines with plt.plot(), Python will plot all of them together, unless you write plt.show() after each one. I want these all on one plot.

# In[ ]:

# your solutions here

# ### Day 3
#
# #### Exercise 1
#
# There is a file in this directory called "histogram_exercise.dat" which consists of of randomly generated samples from a Gaussian distribution with an unknown $\mu$ and $\sigma$. Using what you've learned about fitting data, load up this file using np.genfromtxt, fit a Gaussian curve to the data and plot both the curve and the histogram of the data. As always, label everything, play with the colors, and choose a judicious bin size.
#
# Hint: if you attempt to call a function from a library or package that hasn't been imported, you will get an error.

# In[ ]:

# your solution here

# #### Exercise 2
#
# Create a 1D interpolation along these arrays. Plot both the data (as points) and the interpolation (as a dotted line). Also plot the value of the interpolated function at x=325. What does the function look like to you?

# In[ ]:

x = np.array([0., 50., 100., 150., 200., 250., 300., 350., 400., 450., 500])
y = np.array([0., 7.071, 10., 12.247, 14.142, 15.811, 17.321, 18.708, 20., 21.213, 22.361])

# solution here

# ### Day 4
#
# #### Exercise 1
#
# Let's practice some more plotting skills, now incorporating units.
#
# A. Write a function that takes an array of frequencies and spits out the Planck distribution. That's this equation:
#
# $$ B(\nu, T) = \frac{2h\nu^3/c^2}{e^{\frac{h\nu}{k_B T}} - 1} $$
#
# This requires you to use the Planck constant, the Boltzmann constant, and the speed of light from astropy. Make sure they are all in cgs.
#
# B. Plot your function in log-log space for T = 25, 50, and 300 K. The most sensible frequency range is about 10^5 to 10^15 Hz. Hint: if your units are correct, your peak values of B(T) should be on the order of 10^-10. Make sure everything is labelled.

# In[ ]:

# solution here

# #### Exercise 2
#
# Let's put everything together now! Here's a link to the full documentation for FITSFigure, which will tell you all of the customizable options: http://aplpy.readthedocs.io/en/stable/api/aplpy.FITSFigure.html. Let's create a nice plot of M51 with a background optical image and X-ray contours overplotted.
#
# The data came from here if you're interested: http://chandra.harvard.edu/photo/openFITS/multiwavelength_data.html
#
# A. Using astropy, open the X-RAY data (m51_xray.fits). Flatten the data array and find its standard deviation, and call it sigma.
#
# B. Using aplpy, plot a colorscale image of the OPTICAL data. Choose a colormap that is visually appealing (list of them here: https://matplotlib.org/2.0.2/examples/color/colormaps_reference.html). Show the colorbar.
#
# C. Plot the X-ray data as contours above the optical image. Make the contours spring green with 80% opacity and dotted lines. Make the levels go from 2$\sigma$ to 10$\sigma$ in steps of 2$\sigma$. (It might be easier to define the levels array before show_contours, and set levels=levels.)

# In[ ]:

# solution here

import numpy,from scipy,import astropy,from astropy


# Our implemetation of SAX (Symbolic Aggregate approXimation)
## https://cs.gmu.edu/~jessica/SAX_DAMI_preprint.pdf

import string
from scipy.stats import norm
import numpy as np
import warnings

def pca_mean(ts, width):
    if len(ts) % width != 0:
        warnings.warn("Result truncated, width does not divide length")
    return [np.mean(ts[i*width:np.min([len(ts), (i+1)*width])]) for i in range(int(np.floor(len(ts)/width)))]

def reverse_pca(ts, width):
    return np.kron(ts, np.ones([1,width])[0])

def gaussian_breakpoints(ts, symbols):
    # Construct Breakpoints
    breakpoints = np.hstack((norm.ppf([float(a) / symbols for a in range(1, symbols)], scale=1), np.inf))
    ts_GB = ''
    for i in ts:
        for j in range(len(breakpoints)):
            if i < breakpoints[j]:
                ts_GB += chr(97 + j)
                break
    return ts_GB

def reverse_gaussian_breakpoints(ts_GB, number_of_symbols):
    breakpoint_values = norm.ppf([float(a) / (2 * number_of_symbols) for a in range(1, 2 * number_of_symbols, 2)], scale=1)
    ts = []
    for i in ts_GB:
        j = int(ord(i)-97)
        ts.append(breakpoint_values[j])
    return ts

def compress(ts, width = 2):
    reduced_ts = pca_mean(ts, width)
    return reduced_ts

def digitize(ts, number_of_symbols = 5):
    symbolic_ts = gaussian_breakpoints(ts, number_of_symbols)
    return symbolic_ts

def reverse_digitize(symbolic_ts, number_of_symbols = 5):
    reduced_ts = reverse_gaussian_breakpoints(symbolic_ts, number_of_symbols)
    return reduced_ts

def reconstruct(reduced_ts, width = 2):
    ts = reverse_pca(reduced_ts, width)
    return ts

if __name__ == "__main__":
    import matplotlib.pyplot as plt
    from tslearn.piecewise import SymbolicAggregateApproximation

    # Generate a random walk
    ts = np.random.normal(size = 700)
    ts = np.cumsum(ts)
    ts = ts - np.mean(ts)
    ts /= np.std(ts, ddof=1)

    n_sax_symbols = 8
    n_paa_segments = 10

    # tslearn SAX implementation
    sax = SymbolicAggregateApproximation(n_segments=n_paa_segments, alphabet_size_avg=n_sax_symbols)
    sax_dataset_inv = sax.inverse_transform(sax.fit_transform(ts))

    # Our SAX implementation
    width = len(ts) // n_paa_segments
    sax = compress(ts, width = width)
    sax = digitize(sax, number_of_symbols = n_sax_symbols)
    sax_ts = reverse_digitize(sax, number_of_symbols = n_sax_symbols)
    sax_ts = reconstruct(sax_ts, width = width)

    plt.figure()
    plt.plot(ts, "b-", alpha=0.4)
    plt.plot(sax_dataset_inv[0].ravel(), "b-")
    plt.plot(sax_ts, 'r--')
    plt.legend(['original', 'tslearn SAX implementation', 'our SAX implementation'])
    plt.title("SAX, %d symbols" % n_sax_symbols)
    plt.show()


#!/usr/bin/env python
"""
AER1415 Computer Optimization - Assignment 2

Author: Atilla Saadat
Submitted: Mar 31, 2021
Email: asaadat@utias-sfl.net

rosenbrock test function - supporting module

"""
from numpy import *

#rosenbrock function
def rosen(x,**kwargs):
	x = asarray_chkfinite(x)
	x0 = x[:-1]
	x1 = x[1:]
	return sum(100.0*(x1 - x0**2.0)**2.0 + (1 - x0)**2.0)

#rosenbrock gradient vector for n=2 and n=5
def rosen_gk(x):
	if len(x) == 2:
		#g = [400*x[0]**3 - 400*x[0]*x[1] + 2*x[0] - 2.,
		#	-200*x[0]**2 + 400*x[1]**3 + 202*x[1] - 2.]
		#g = [-400*(x[1]-x[0]**2)*x[0] - 2*(2.-x[0]),
		#	200*(x[1]-x[0]**2)]
		g = [2*x[0] - 400*x[0]*(-x[0]**2 + x[1]) - 2, 200*(x[1] -x[0]**2) ]
	elif len(x) == 5:
		'''
		g = [400*x[0]**3 - 400*x[0]*x[1] + 2*x[0] - 2.,
			-200*x[0]**2 + 400*x[1]**3 + x[1]*(202 - 400*x[2]) - 2.,
			-200*x[1]**2 + 400*x[2]**3 + x[2]*(202 - 400*x[3]) - 2.,
			-200*x[2]**2 + 400*x[3]**3 + x[3]*(202 - 400*x[4]) - 2.,
			-200*x[3]**2 + 400*x[4]**3 + 202*x[4] - 2.]
		'''
		g = [2*(x[0]-1) - 400*x[0]*(x[1] - x[0]**2),
			 2*(x[1]-1) - 400*x[1]*(x[2] - x[1]**2) + 200*(x[1] - x[0]**2),
			 2*(x[2]-1) - 400*x[2]*(x[3] - x[2]**2) + 200*(x[2] - x[1]**2),
			 2*(x[3]-1) - 400*x[3]*(x[4] - x[3]**2) + 200*(x[3] - x[2]**2),
			 200*(x[4] - x[3]**2),
		]
	return array(g)

#rosebrock hessiam matrix for n=2
def rosen_Hk_n2(x):
	#https://www.khanacademy.org/math/multivariable-calculus/applications-of-multivariable-derivatives/quadratic-approximations/a/the-hessian
	#https://www.wolframalpha.com/input/?i=d%2Fdx+2*%28200*x%5E3+-+200*x*y+%2B+x+-+1%29
	#https://www.wolframalpha.com/input/?i=d%2Fdy+2*%28200*x%5E3+-+200*x*y+%2B+x+-+1%29
	#https://www.wolframalpha.com/input/?i=d%2Fdx+200*%28y-x%5E2%29
	#https://www.wolframalpha.com/input/?i=d%2Fdy+200*%28y-x%5E2%29
	h_xx = 1200*x[0]**2 - 400*x[1] + 2.
	h_xy = -400*x[0]
	h_yx = -400*x[0]
	h_yy = 200.
	return array([[h_xx,h_yx],[h_xy,h_yy]])


# Laboratorul 7

import numpy as np

def metIacobi(B, eps, tol):
    """

    B: matricea simetrica
    eps: eroarea
    -----------------
    return: valori si vectori proprii

    """

    A=np.copy(B)
    n=np.shape(A)[0]
    modul_A = 0
    T = np.eye(n, n)

    for i in range(n):
        for j in range(n):
            if i != j:
                modul_A += A[i][j] ** 2

    modul_A = np.sqrt(modul_A)
    while modul_A >= eps:
        max = abs(A[1][0])
        p = 0
        q = 1
        for j in range(n):
            for i in range(j + 1, n):
                if abs(A[i][j]) > max:
                    max = abs(A[i, j])
                    p = j
                    q = i

        if abs(A[p, p] - A[q, q]) <= tol:
            teta = np.pi / 4
        else:
            teta = 1 / 2 * np.arctan(2 * A[p, q] / (A[q, q]-A[p, p]))

        c = np.cos(teta)
        s = np.sin(teta)

        R = np.eye(n, n)
        R[p, p] = c
        R[p, q] = s
        R[q, p] = -s
        R[q, q] = c
        A = np.transpose(R)@A@R

        T = T@R
        modul_A = 0
        for i in range(n):
            for j in range(n):
                if i != j:
                    modul_A += A[i][j] ** 2
        modul_A = np.sqrt(modul_A)

    return A, T

B = np.array([[17, -2, 3 * np.sqrt(3)],
              [-2, 8, 2 * np.sqrt(3)],
              [3 * np.sqrt(3), 2 * np.sqrt(3), 11]], float)
A, T = metIacobi(B, 10 ** (-3), 10 ** (-7))
print(A)
print(T)

B1 = np.array([[1, 1, 0],
               [1, 1, 0],
               [0, 0, 2]], float)

A1, T = metIacobi(B1, 10 ** (-3), 10 ** (-7))
print(A1)
print(T)

# Verificare
print(np.transpose(T)@B1@T)
v = T[:, 0]
print(B1@v - A1[0, 0] * v)

Calcul Numeric (CN)/Laborator/Laborator 7/lab7.py


import matplotlib.pyplot as plt
import numpy as np
from scipy.sparse import lil_matrix
from scipy.sparse.linalg import bicgstab
from scipy.linalg import solve
# is_inner_for = True
is_inner_for = False
is_sparse = True
# is_sparse = False

def get_analytical_solution(max_x, max_y, total_points_x, total_points_y):
    x = np.linspace(0, max_x, total_points_x)
    y = np.linspace(0, max_y, total_points_y)
    analytical_solution = np.zeros((total_points_x, total_points_y))
    for k in range(total_points_x):
        for i in range(total_points_y):
            analytical_solution[k, i] = \
                (
                        np.sin(x[k]) * np.sinh(y[i])
                 ) / (
                        np.sinh(max_y) * np.sin(max_x)
                )
    return analytical_solution

def get_linear_system_matrix_slow(mesh_points_x, mesh_points_y, mesh_step_ratio):
    matrix_size = mesh_points_x * mesh_points_y
    matrix = np.zeros((matrix_size, matrix_size))
    for k in range(matrix_size):
        for i in range(matrix_size):
            # origin for all finite differences
            if k == i:
                matrix[k, i] = -2 * (1 + mesh_step_ratio)
            # left and right finite differences
            if k == i + 1 and k % mesh_points_y != 0:
                matrix[k, i] = mesh_step_ratio
            if k == i - 1 and (k+1) % mesh_points_y != 0:
                matrix[k, i] = mesh_step_ratio
            # bottom and top finite differences
            if k == i + mesh_points_y or k == i - mesh_points_y:
                matrix[k, i] = 1

    return matrix

def get_linear_system_matrix(mesh_points_x, mesh_points_y, mesh_step_ratio):
    matrix_size = mesh_points_x * mesh_points_y
    matrix = lil_matrix((matrix_size, matrix_size)) if is_sparse else np.zeros((matrix_size, matrix_size))
    for k in range(matrix_size):
        # origin for all finite differences
        matrix[k, k] = -2 * (1 + mesh_step_ratio)

    for k in range(matrix_size-1):
        # left finite differences
        if (k+1) % mesh_points_y != 0:
            matrix[k+1, k] = mesh_step_ratio

    for k in range(1,matrix_size):
        # right finite differences
        if k % mesh_points_y != 0:
            matrix[k - 1, k] = mesh_step_ratio

    for k in range(matrix_size - mesh_points_y):
        # bottom finite differences
        matrix[k + mesh_points_y, k] = 1

    for k in range(mesh_points_y, matrix_size):
        # top finite differences
        matrix[k - mesh_points_y, k] = 1

    return matrix.tocsc() if is_sparse else matrix

def get_rhs_vector(boundary_x, boundary_y, step_ratio):
    mesh_points_x = len(boundary_x)
    mesh_points_y = len(boundary_y)
    all_mesh_points = mesh_points_x * mesh_points_y
    rhs_vector = np.zeros(all_mesh_points)
    for k in range(all_mesh_points):
        if (k + 1) % mesh_points_y == 0:
            rhs_vector[k] += -step_ratio * boundary_x[int(k / mesh_points_y)]
        if k > all_mesh_points - mesh_points_y - 1:
            rhs_vector[k] += -boundary_y[k % mesh_points_y]
    return rhs_vector

def initialize_with_boundary_conditions(top_boundary, right_boundary):
    numerical_solution = np.zeros((len(top_boundary), len(right_boundary)))
    numerical_solution[:, -1] = top_boundary
    numerical_solution[-1, :] = right_boundary

    # 5-point stencil doesn't use corner points of the analytical solution boundary
    return numerical_solution, top_boundary[1:-1], right_boundary[1:-1]

def get_step(max_x, max_y, total_points_x, total_points_y):
    step_x = max_x / (total_points_x - 1)
    step_y = max_y / (total_points_y - 1)
    step_ratio = (step_x / step_y) ** 2
    return step_ratio, step_y, step_y

def get_numerical_solution(top_boundary, right_boundary, step_ratio):
    numerical_solution, boundary_x, boundary_y = \
        initialize_with_boundary_conditions(top_boundary, right_boundary)

    if is_inner_for:
        linear_system_matrix = \
            get_linear_system_matrix_slow(len(boundary_x), len(boundary_y), step_ratio)
    else:
        linear_system_matrix = \
            get_linear_system_matrix(len(boundary_x), len(boundary_y), step_ratio)

    rhs_vector = get_rhs_vector(boundary_x, boundary_y, step_ratio)

    if is_sparse:
        linear_system_solution, exit_code = \
            bicgstab( linear_system_matrix, rhs_vector, tol=1e-14)
    else:
        linear_system_solution = solve( linear_system_matrix, rhs_vector)

    inner_shape = (len(boundary_x), len(boundary_y))
    numerical_solution[1:-1, 1:-1] = \
        np.reshape(linear_system_solution, inner_shape)
    return numerical_solution

def get_solution(max_x, max_y, total_points_x, total_points_y):
    analytical = get_analytical_solution(max_x, max_y,
                                         total_points_x, total_points_y)

    top_boundary = analytical[:, -1]
    right_boundary = analytical[-1, :]
    step_ratio, step_x, step_y = get_step(max_x, max_y,
                                          total_points_x, total_points_y)

    numerical = get_numerical_solution(top_boundary, right_boundary,
                                       step_ratio)
    solution_error = np.abs(numerical - analytical)
    error_rms = (
                    np.sum(
                        np.power(
                            # use only computed part for error estimate
                            solution_error[1:-1, 1:-1],
                            2
                        )
                    ) / (
                        (total_points_x-2) * (total_points_y-2)
                    )
                )**0.5
    return numerical, analytical, solution_error, error_rms, step_x, step_y

if __name__ == '__main__':
    max_x = 5
    max_y = 4
    total_points_x = 25
    total_points_y = 15

    numerical, analytical, solution_error, _, _, _ = \
        get_solution(max_x, max_y, total_points_x, total_points_y)

    data = [numerical, analytical, solution_error]
    titles = ['Numerical', 'Analytical', 'abs(error)']

    fig, axs = plt.subplots(figsize=(10, 5), ncols=len(data))
    for i in range(len(data)):
        numerical_plot = axs[i].imshow(data[i])
        fig.colorbar(numerical_plot, ax=axs[i])
        axs[i].set_title(titles[i])
    plt.show()


import numpy as np

def wallNormalGrid(num:int, eta=1., delta=1.):
    """The non-uniformly spaced grid for the wall-normal direction `[1]`_.

    Args:
        num (int): Number of grids to generate.
        eta (float, optional): The parameter to controls how strongly the points are clusterd near the wall. Defaults to 1..
        delta (float, optional): The channel half-width. Defaults to 1..

    Returns:
        np.array: Non-uniformly spaced grid.

    .. _[1] [Lee and Moser, "Direct numerical simulation of turbulent channel flow up to Ret=5200", 2015.](https://arxiv.org/abs/1410.7809)
    """
    zeta = np.linspace(start=-1., stop=1., num=num)
    return delta * np.sin(eta*zeta*np.pi*0.5) / np.sin(eta*np.pi*0.5)

# def wallNormalGrid2(num:int, alpha=None):
#     """The non-uniformly spaced grid for the wall-normal direction [#2]_.

#     Args:
#         num (int): Number of grids to generate.
#         alpha (float): Adjustable patameter. 0.967 for Ret=180, 0.98 for Ret=395, None for Ret=640

#     Returns:
#         _type_: _description_

#     ToDo:
#         Something wrong with this method.

#     .. [#2]  Hiroyuki Abe, Hiroshi Kawamura, Yuichi Matsuo, "Direct Numerical Simulation of a Fully Developed Turbulent Channel Flow With Respect to the Reynolds Number Dependence", 2001.
#     """
#     j = np.arange(num)
#     zeta = 2 * j / num - 1
#     if alpha==None:
#         alpha = 0.9885 - 0.5*zeta**2 + 0.405*zeta**3
#     return np.tanh(zeta / np.tanh(alpha)) / (2*alpha) + 0.5

if __name__=="__main__":
    Ret = 1000
    ny = 513
    eta = 0.99
    delta = 1.
    y = wallNormalGrid(ny, eta, delta)
    dy = np.diff(y)
    dyplus_wall = np.abs(dy).min() * Ret
    dyplus_center = np.abs(dy).max() * Ret
    print(dyplus_wall, dyplus_center)
    assert dyplus_wall < 0.45
    assert dyplus_center < 6.5
    # growthRate_wall = dy[1] / dy[0]
    # print(growthRate_wall)

    nx = 640
    Lx = 2*np.pi
    dx = Lx / nx
    dxplus = dx * Ret
    print(dxplus)
    assert dxplus < 10

    nz = 540
    Lz = np.pi
    dz = Lz / nz
    dzplus = dz * Ret
    print(dzplus)
    assert dzplus < 6


"""
Please see
https://computationalmindset.com/en/neural-networks/ordinary-differential-equation-solvers.html#sys1
for details
"""

import numpy as np
import matplotlib.pyplot as plt

import tensorflow as tf
import tensorflow_probability as tfp

def ode_sys(t, X):
	x=X[0]
	dx_dt=X[1]
	d2x_dt2=-dx_dt - 2*x
	return [dx_dt, d2x_dt2]

an_sol_x = lambda t : \
	np.exp(-t/2.) * (np.cos(np.sqrt(7) * t / 2.) + \
	np.sin(np.sqrt(7) * t / 2.)/np.sqrt(7.))

t_begin=0.
t_end=12.
t_nsamples=100
t_space = np.linspace(t_begin, t_end, t_nsamples)
t_init = tf.constant(t_begin)
x_init = tf.constant(1.)
dxdt_init = tf.constant(0.)

x_an_sol = an_sol_x(t_space)

num_sol = tfp.math.ode.BDF().solve(ode_sys, t_init, [x_init, dxdt_init],
	solution_times=tfp.math.ode.ChosenBySolver(tf.constant(t_end)) )

plt.figure()
plt.plot(t_space, x_an_sol, '--', linewidth=2, label='analytical')
plt.plot(num_sol.times, num_sol.states[0], linewidth=1, label='numerical')
plt.title('ODE 2nd order IVP solved by TFP with BDF')
plt.xlabel('t')
plt.ylabel('x')
plt.legend()
plt.show()


#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time     : 2018/12/04 15:05
# @Author   : Iydon
# @File     : course9.py

import numpy as np
import scipy as sp

def gersgorin_circle(A, numpy):
    r"""
    |z-a_{ii}|<=\sum_{j!=i}|a_{ij}|
    """
    shape = A.shape
    if shape[0] != shape[-1]:
        raise Exception("Dimensions do not match.")
    result = [[] for i in range(shape[0])]
    for i in range(shape[0]):
        summation = numpy.sum(numpy.abs(A[i,])) - numpy.abs(A[i,i])
        result[i] = [A[i,i], summation]
    return result

def power_method(A, numpy, x0=None, judge=None, eps=1e-6, max_loop=64, disply=False, p=0):
    r"""
    Numpy
    B = A - pI.
    """
    if x0==None:    x0 = np.ones((A.shape[0], 1))
    if judge==None: judge = lambda x,y: numpy.linalg.norm(x-y, float("inf"))
    A_    = A.copy() - p*numpy.eye(A.__len__())
    count = 0
    mu    = numpy.max(x0)
    x0    = x0 / mu
    last  = x0
    while count<max_loop:
        count += 1
        uv = numpy.matmul(A_, x0)
        mu = numpy.max(uv)
        x0 = uv / mu
        if disply:
            print("%%%dd: %%s"%(len(str(max_loop)))%(count, mu))
        if judge(last,x0)<eps:
            break
        last = x0
    return mu + p

def inverse_power_method(A, scipy, x0=None, judge=None, eps=1e-6, max_loop=64, disply=False, p=0):
    r"""
    Scipy
    pass
    """
    from scipy import linalg
    if x0==None:    x0 = np.ones((A.shape[0], 1))
    if judge==None:
        norm  = lambda x: scipy.linalg.norm(x, float("inf"))
        judge = lambda x,y: abs(norm(x-y))
    A_    = A.copy() - p*scipy.eye(len(A))
    LU    = linalg.lu_factor(A_)
    count = 0
    mu    = max(x0)
    x0    = x0 / mu
    last  = x0
    while count<max_loop:
        count += 1
        uv = linalg.lu_solve(LU, x0)
        mu = max(abs(x0))[0]
        x0 = uv / mu
        if disply:
            print("%%%dd: %%s"%(len(str(max_loop)))%(count, p+1/mu))
        if judge(last,x0)<eps:
            break
        last = x0
    return p + 1/mu

A = np.matrix([[0.25,1,0.5],[1,0.25,0.25],[0.5,0.25,1.25]])
print(A)
result = gersgorin_circle(A, np)
print(result)

result = power_method(A, np, disply=True, p=0)
print(result.T)
print(np.max(np.linalg.eigvals(A)))

A = sp.matrix([[1,2,4],[1,3,9],[1,5,1]])
result = inverse_power_method(A, sp, disply=True, eps=1e-8, max_loop=64, p=-7)
print(result.T)
print(np.min(np.linalg.eigvals(A)))


from __future__ import division, print_function

import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import spectrogram
from butter import butter_lowpass_filtfilt

time, pressure = np.loadtxt('pressure.dat', skiprows=2,
                            delimiter=',', unpack=True)

t0 = time.min()
t1 = time.max()

fs = 50000

nperseg = 80
noverlap = nperseg - 4

print("Spectrogram window length: %g ms (%d samples)" %
      (1000*nperseg/fs, nperseg))

f, t, spec = spectrogram(pressure, fs=fs, nperseg=nperseg, noverlap=noverlap,
                         window='hann')
t += t0/1000

cutoff = 1250
pressure_filtered = butter_lowpass_filtfilt(pressure, cutoff, fs, order=8)

f, t, filteredspec = spectrogram(pressure_filtered, fs=fs, nperseg=nperseg,
                                 noverlap=noverlap, window='hann')
t += t0/1000

tlo = t[0]*1000
thi = t[-1]*1000

spec_db = 10*np.log10(spec)
filteredspec_db = 10*np.log10(filteredspec)

vmax = max(spec_db.max(), filteredspec_db.max())
vmin = vmax - 80.0  # Clip display of values below 80 dB

linecolor = 'k'
cmap = plt.cm.coolwarm

plt.figure(figsize=(4.0, 4.5))
plt.subplot(211)
plt.plot(time, pressure, color=linecolor, alpha=0.8)
plt.xlim(tlo, thi)
plt.ylim(0, 10)
plt.ylabel("Pressure (MPa)")
plt.grid(alpha=0.25)

plt.subplot(212)
plt.pcolormesh(1000*t, f/1000, spec_db, vmin=vmin, vmax=vmax,
               cmap=cmap, shading='gouraud')
plt.xlim(tlo, thi)
plt.ylabel('Frequency (kHz)')
plt.xlabel('Time (ms)')
plt.tight_layout()
plt.savefig("pressure_example_input.pdf")

plt.figure(2, figsize=(4.0, 4.5))
plt.subplot(211)
plt.plot(time, pressure, color=linecolor, alpha=0.15)
plt.plot(time, pressure_filtered, color=linecolor, alpha=0.8)
plt.xlim(tlo, thi)
plt.ylim(0, 10)
plt.ylabel("Pressure (MPa)")
plt.grid(alpha=0.25)

plt.subplot(212)
plt.pcolormesh(1000*t, f/1000, filteredspec_db, vmin=vmin, vmax=vmax,
               cmap=cmap, shading='gouraud')
plt.axhline(cutoff/1000, color='k', linestyle='--', linewidth=1, alpha=0.5)
plt.xlim(tlo, thi)
plt.ylabel('Frequency (kHz)')
plt.xlabel('Time (ms)')
plt.tight_layout()
plt.savefig("pressure_example_filtered.pdf")


"""
Created on Friday 25 August 2017
Last update: Tuesday 26 December 2017

@author: Michiel Stock
michielfmstock@gmail.com

Some functions to illustrate the convergence of the optimization algorithms
for quadratic systems
"""

import sys
sys.path.append('helpers/')
from colors import colors_list
import matplotlib.pyplot as plt
import numpy as np
#import seaborn as sns
#sns.set_style('white')

def gd_error_decomposition(eigenvalues=[0.1, 1.5, 1.6, 1.8, 2],
                    x0=np.ones((5, 1)), n_steps=50, t='optimal', ax=None,
                    cumulative=True):
    """
    #FIX: docstring
    short description

    Inputs:
        -

    Output:
        -
    """
    if t=='optimal':
        t = 2 / (min(eigenvalues) + max(eigenvalues))
    n = len(eigenvalues)
    ev = np.reshape(eigenvalues, (-1, 1))  # vector format
    steps = np.arange(0, n_steps + 1)
    error_per_comp = (1 - t * ev) ** (2 * steps.reshape((1, -1)))
    error_per_comp *= ev * x0**2
    if ax is not None:
        colors = iter(colors_list)
        prev = np.zeros_like(steps) + 1e-10
        current = prev + 0
        for i, val in enumerate((eigenvalues)):
            label=r'$\lambda_{}=${}'.format(i+1, val)
            if cumulative:
                current += error_per_comp[i,:]
                ax.fill_between(steps+1, prev, current,
                        color=next(colors),
                        label=label)
                prev[:] = current
            else:
                ax.plot(steps+1, error_per_comp[i,:],color=next(colors),
                            label=label, lw=2)
        ax.legend(loc=0)
        if cumulative:
            ax.set_ylabel(r'$f(\mathbf{x}^{(k)})-f(\mathbf{x}^\star)$')
            #ax.set_ylim([1e-10, 5])
            ax.set_ylim([1e-10, error_per_comp[:,0].sum()])
        else:
            ax.set_ylabel(r'$(1-t\lambda_i)^{2k}\lambda_i[\mathbf{u}_i^\intercal(\mathbf{x}^{(k)} - \mathbf{x}^\star)]^2$')
        ax.set_xlabel(r'$k+1$')
        ax.set_ylim([1e-10, error_per_comp[:,0].sum()])
    return error_per_comp

def gd_convergence_and_bound(eigenvalues=[0.1, 1.5, 1.6, 1.8, 2], n_steps=50,
                        t='optimal', x0=np.ones((5, 1))):
    # condition number
    #FIX: docstring
    kappa = max(eigenvalues) / min(eigenvalues)
    c = 1 - 1/kappa
    error = gd_error_decomposition(eigenvalues=eigenvalues, n_steps=n_steps,
        t=t, x0=x0).sum(0)
    bound = np.sum([xi**2 * e for xi, e in zip(x0, eigenvalues)]) * c ** np.arange(0, n_steps+1)
    return error, bound

if __name__ == '__main__':
    # choose format of the plots
    format = 'png'

    # convergence plot

    n_steps = 1000 - 1

    fig, (ax0, ax1) = plt.subplots(ncols=2, figsize=(12, 6))
    E = gd_error_decomposition(ax=ax0, n_steps=n_steps, cumulative=True)
    ax0.semilogx()
    ax0.set_title('Error of gradient descent\n(cumulative eigencomponents)')

    gd_error_decomposition(ax=ax1, n_steps=n_steps, cumulative=False)
    ax1.set_title('Error of gradient descent\n(individual eigencomponents)')
    ax1.loglog()
    fig.tight_layout()
    fig.savefig('Chapters/01.Quadratic/Figures/convergence_decomposition.{}'.format(format))

    # error vs bound
    kappas = [1.1, 2.5, 5, 50, 100]

    n_steps = 10000
    colors = iter(colors_list)
    fig, ax = plt.subplots()
    steps = np.arange(0, n_steps+1)+1
    for kappa in kappas:
        color = next(colors)
        error, bound = gd_convergence_and_bound(eigenvalues=[1, kappa],
                    n_steps=n_steps, x0=np.ones((2, 1)))
        ax.plot(steps, error, color=color, ls='-', label=r'$\kappa$={}'.format(kappa), lw=2)
        ax.plot(steps, bound, color=color, ls='--', lw=2)

    ax.set_ylim([1e-6, 200])
    ax.loglog()
    ax.set_title('Convergence (-) and bound (--) of GD\nfor different condition numbers')
    ax.legend(loc=0)
    ax.set_ylabel(r'$f(\mathbf{x}^{(k)})-f(\mathbf{x}^\star)$')
    ax.set_xlabel(r'$k+1$')
    fig.tight_layout()
    fig.savefig('Chapters/01.Quadratic/Figures/convergence_bound.{}'.format(format))

    plt.close('all')


import numpy as np

#Task 1
#We define an array1
array1 = np.array ( [[1., 1., 1.],
                     [1., 1., 1.]], dtype=int)
#Use ones function to define array_ones so that it is equal to array1
array_ones = np.ones ( (2,3) )
#Make this true
print (np.array_equal(array_ones, array1) )

#Task 2
#We define an array2
array2 = np.array ( [0, 2, 4, 6, 8] )
#Use arange function to define array_arange so that it is equal to array2
array_arange = np.arange (0, 9, 2)
#Make this true
print (np.array_equal(array_arange, array2) )

#Task 3
#We define an array3
array3 = np.array ( [0, 0.25, 0.5, 0.75, 1] )
#Use linspace function to define array_linspace so that it is equal to array3
array_linspace = np.linspace (0, 1, 5)
#Make this true
print (np.array_equal(array_linspace, array3) )

#Task 4
#Before uncommenting and running these, think about what the results will be

print ("--------------simple operations----------------------")
print (array2 * 5)
print (array2 / 2)
print (array2 ** 2)
print (array2 <= 5)

print ("----------------upcasting----------------------------")
array4 = array2 + array3
print (array4)
print (array4.dtype)

#Task 5
#Which of the following demand will not generate errors?
#Uncomment that one
print ("------------------multiplication---------------------")
array1 = np.array ( [[1., 1., 1.],
                     [1., 1., 1.]], dtype=int)
array5 = np.array( [[1, 2],
                    [3, 4],
                    [5, 6]] )
#print (array1 * array5)
print (np.dot (array1, array5) )


import math
import random
from utils.num.ntheory import crt, egcd, modinv

#used for rsa problems where m^e < n meaning to decrypt c you can just do invpow(c,e)
#from https://stackoverflow.com/q/55436001/7941251
def invpow(x: int, n: int) -> int:
	"""Finds the integer component of the n'th root of x,
	an integer such that y ** n <= x < (y + 1) ** n.
	"""
	high = 1
	while high**n < x:
		high *= 2
	low = high // 2
	while low < high:
		mid = (low + high) // 2
		if low < mid and mid**n < x:
			low = mid
		elif high > mid and mid**n > x:
			high = mid
		else:
			return mid
	return mid + 1

# https://github.com/ashutosh1206/Crypton/tree/master/RSA-encryption/Factorisation-Fermat
def fermats_factorization(n):
	""" factor n by using difference of squares, only works if factors are close """
	a = math.isqrt(n) + 1
	b_2 = a**2 - n  # b squared
	while math.isqrt(b_2)**2 != b_2:
		a += 1
		b_2 = a**2 - n
	b = math.isqrt(b_2)
	return (a - b, a + b)

# see cryptopals 40
def hastad_broadcast_attack(cts, n_s, e):
	return invpow(crt(cts, n_s), e)

# see cryptopals 41
def decrypt_unpadded_oracle(c, e, n, oracle):
	s = random.randint(2, n - 1)
	c_prime = (pow(s, e, n) * c) % n
	p_prime = oracle(c_prime)
	return (p_prime * modinv(s, n)) % n

def common_mod_attack(c1, c2, e1, e2, n):
	""" pt is encrypted using 2 different e's but same n"""
	gcd, a, b = egcd(e1, e2)
	ct = (pow(c1, a, n) * pow(c2, b, n)) % n
	return invpow(ct, gcd)

def lsb_parity_oracle(c, e, n, oracle):
	# https://github.com/ashutosh1206/Crypton/tree/master/RSA-encryption/Attack-LSBit-Oracle
	upper = n
	lower = 0
	for _ in range(n.bit_length()):
		c = (c * pow(2, e, n)) % n
		if oracle(c):  #even
			upper = (upper + lower) // 2
		else:
			lower = (lower + upper) // 2
	return upper

def wieners_attack(e: int, n: int):
	""" returns d """
	#pylint: disable=import-outside-toplevel
	#lazy imports to avoid slowing down initial load
	from sympy.ntheory.continued_fraction import continued_fraction_convergents, continued_fraction_iterator
	from sympy.core.numbers import Rational
	c = 2
	convergents = continued_fraction_convergents(continued_fraction_iterator(Rational(e, n)))
	for convergent in convergents:
		d = convergent.denominator()
		p = pow(c, d, n)
		if pow(p, e, n) == c:
			return d
	raise ValueError(f"Couldn't find d for {e=} and {n=}")


import numpy as np

def bootstrap_test(tested_array, H0_mean, sampling = 10_000, seed=0, print_result=True):

  """This function outputs the probability of obtaining the observed difference between the mean of the tested_array and the H0_mean, given that the HO_mean is true (P-value).
  Type hints :
    tested_array : np.array()
    HO_mean : int or float
    sampling : int
    seed : int"""

  np.random.seed(seed)

  simulated_sample_means = [np.random.choice(tested_array,
                                  size=tested_array.shape[0],
                                  replace=True).mean()
                                  for _ in range(sampling)]

  array_mean = tested_array.mean()
  interval = [array_mean - abs(array_mean - H0_mean), array_mean + abs(array_mean - H0_mean)]

  number_extreme_values = 0
  for sample_mean in simulated_sample_means:
      if not interval[0] < sample_mean < interval[1]:
          number_extreme_values += 1

  p_value =  number_extreme_values / len(simulated_sample_means)

  if print_result == True :  print(f"P-value is approximately {p_value:.2f}")

  return p_value